mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-08 10:10:14 -10:00
Compare commits
558
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c6f99f583 | ||
|
|
caf0bb9d4d | ||
|
|
753f738368 | ||
|
|
5eb76327ff | ||
|
|
06a19ba790 | ||
|
|
795dd3b305 | ||
|
|
d63a846748 | ||
|
|
3b389b979a | ||
|
|
3f46f9fb68 | ||
|
|
ff92ae2db5 | ||
|
|
20cae21475 | ||
|
|
521dae4695 | ||
|
|
dfc63d3e46 | ||
|
|
af78a2e58b | ||
|
|
4b7a3046ce | ||
|
|
babbcab3da | ||
|
|
b0ac567e7a | ||
|
|
455fce9ff5 | ||
|
|
363851f9d2 | ||
|
|
905043012e | ||
|
|
e0ba315761 | ||
|
|
e41be11e9f | ||
|
|
9f0c33016f | ||
|
|
faa13945eb | ||
|
|
989952a873 | ||
|
|
bc9f8df2c2 | ||
|
|
ddface22a8 | ||
|
|
cf18090431 | ||
|
|
cd27cf03e1 | ||
|
|
c0f643dcbe | ||
|
|
84ffab7354 | ||
|
|
cbfd949756 | ||
|
|
55ce03844f | ||
|
|
1451fa8c65 | ||
|
|
d87f90dca3 | ||
|
|
6f8164da52 | ||
|
|
aace0531ab | ||
|
|
91609788d4 | ||
|
|
b5b7019b79 | ||
|
|
2bcafd6ef7 | ||
|
|
0f1092200c | ||
|
|
ccf612a711 | ||
|
|
d8ec77da69 | ||
|
|
aa3efd01cc | ||
|
|
58ca96e2a5 | ||
|
|
5bf7a15f8e | ||
|
|
7d863efcf8 | ||
|
|
6f43a14ddd | ||
|
|
369aa14bff | ||
|
|
4bd4f320bc | ||
|
|
e0340b2a74 | ||
|
|
508b2aa580 | ||
|
|
b8ec0f910c | ||
|
|
c716b3b481 | ||
|
|
ddecd61771 | ||
|
|
88c490b843 | ||
|
|
5998ae57ea | ||
|
|
94c99353fa | ||
|
|
b993866def | ||
|
|
b292efc741 | ||
|
|
bc78375816 | ||
|
|
82e4997624 | ||
|
|
51c64e7dce | ||
|
|
294adeae11 | ||
|
|
95c4c277a1 | ||
|
|
3d517c0bf5 | ||
|
|
2bd3a670e8 | ||
|
|
a621a2b61f | ||
|
|
bc810d16f1 | ||
|
|
fd3f8f5990 | ||
|
|
c713f64d7e | ||
|
|
ed2a8ff73d | ||
|
|
31524ed90b | ||
|
|
1c5aef19ae | ||
|
|
1932f8320a | ||
|
|
ae590d8378 | ||
|
|
124ca7fdc2 | ||
|
|
21128f51f5 | ||
|
|
1af9666622 | ||
|
|
abf66a9cd7 | ||
|
|
5ba8672ac8 | ||
|
|
4616ed9bc3 | ||
|
|
047b9f2eac | ||
|
|
14113faaba | ||
|
|
03b20c3f52 | ||
|
|
26a6eb1922 | ||
|
|
a2f00c5c91 | ||
|
|
dea480e10f | ||
|
|
b7fc2cd5ba | ||
|
|
2aad95726c | ||
|
|
105c56a817 | ||
|
|
3da1ed0a8e | ||
|
|
f46068314c | ||
|
|
914df83ba5 | ||
|
|
d7f5290f14 | ||
|
|
9d37471e4e | ||
|
|
57e75a2fa3 | ||
|
|
3fab879089 | ||
|
|
16cb3d36ba | ||
|
|
74ef17ee94 | ||
|
|
f1c540d877 | ||
|
|
6018e65ab9 | ||
|
|
43190d413c | ||
|
|
a156166a8e | ||
|
|
c8141c63ad | ||
|
|
8dd940804c | ||
|
|
d16f956068 | ||
|
|
082b25d81f | ||
|
|
a0e29198f6 | ||
|
|
b4c5a4c531 | ||
|
|
3a1e6ae5df | ||
|
|
3f7464bf6c | ||
|
|
6aef4501f8 | ||
|
|
3024f27b7a | ||
|
|
e8e1b52a9b | ||
|
|
1c8c76d389 | ||
|
|
a30eedf1e2 | ||
|
|
0b3314607f | ||
|
|
8e7c203772 | ||
|
|
399854342f | ||
|
|
bb692f26d0 | ||
|
|
da5a4c9fbe | ||
|
|
37fc3d0daf | ||
|
|
76a86e2e45 | ||
|
|
a25c32a60b | ||
|
|
4946642fc4 | ||
|
|
2ac59458f3 | ||
|
|
6d329e885f | ||
|
|
902da5c619 | ||
|
|
e9fcef3de5 | ||
|
|
b43ddd46ea | ||
|
|
9c3002928a | ||
|
|
17ec8d8a75 | ||
|
|
d241c818df | ||
|
|
6ff1375e44 | ||
|
|
bb3a13db3b | ||
|
|
ea439a7183 | ||
|
|
fa8355eccc | ||
|
|
62340ea5d8 | ||
|
|
e6deec89f8 | ||
|
|
65fae25715 | ||
|
|
f735f2cbdd | ||
|
|
f5658a6079 | ||
|
|
2b1580b73f | ||
|
|
3c519517c7 | ||
|
|
7389dc616b | ||
|
|
2ff0562a82 | ||
|
|
2ecdc3bb09 | ||
|
|
c1eb7cbfa8 | ||
|
|
45d2ac757e | ||
|
|
875f1d094d | ||
|
|
dc1c986c2c | ||
|
|
32db820b3d | ||
|
|
7bde8a55b4 | ||
|
|
dd083b1e66 | ||
|
|
6199c17441 | ||
|
|
064eb2112d | ||
|
|
10578fb7ee | ||
|
|
ea57c6a212 | ||
|
|
d38c59d3a0 | ||
|
|
36f82eb364 | ||
|
|
9d01904145 | ||
|
|
bb74a811e8 | ||
|
|
d70961afa3 | ||
|
|
3c8bd9c0fb | ||
|
|
e0f37bdde9 | ||
|
|
b638262e12 | ||
|
|
9cd4e70a42 | ||
|
|
c7a4d7dc6f | ||
|
|
582503697e | ||
|
|
308a546cc7 | ||
|
|
3a8ea7de1e | ||
|
|
e2690480d9 | ||
|
|
a48a0499b7 | ||
|
|
1bc817c48a | ||
|
|
317c2f0bf4 | ||
|
|
c4aacb4348 | ||
|
|
978ed8da50 | ||
|
|
13b7202dbb | ||
|
|
70280b7346 | ||
|
|
f00653f216 | ||
|
|
70982f4807 | ||
|
|
b629bd409b | ||
|
|
68c7902bf3 | ||
|
|
721b4bbaf8 | ||
|
|
67aa570b4d | ||
|
|
4be1b75a89 | ||
|
|
05d499d99b | ||
|
|
432e09c37b | ||
|
|
c33683c9df | ||
|
|
b0ea5de0ae | ||
|
|
3e3744cb94 | ||
|
|
9a7fe334b5 | ||
|
|
11c5982a26 | ||
|
|
d91fdc0dcd | ||
|
|
5f4f7bec6c | ||
|
|
4a2ff61fc8 | ||
|
|
3606ef8814 | ||
|
|
734aa87904 | ||
|
|
367235dbd3 | ||
|
|
8050fbd3ca | ||
|
|
b4c664b979 | ||
|
|
22b66a71f4 | ||
|
|
2ed43c3c16 | ||
|
|
2b3983b2e2 | ||
|
|
b85fd74144 | ||
|
|
58565cb40f | ||
|
|
2e9ce77612 | ||
|
|
6925b89c13 | ||
|
|
7c75cc3af8 | ||
|
|
56c540ae13 | ||
|
|
da19b4461f | ||
|
|
c1c3674519 | ||
|
|
e5297fa81a | ||
|
|
7fcbbbe5b6 | ||
|
|
ea49f740c0 | ||
|
|
d29fcfa667 | ||
|
|
b1c8e3dc93 | ||
|
|
3c8b70f224 | ||
|
|
0600886d22 | ||
|
|
6af8045c46 | ||
|
|
582977f20e | ||
|
|
4c72e3c910 | ||
|
|
a0aa2e2458 | ||
|
|
f6a92d6909 | ||
|
|
11c6afa687 | ||
|
|
062207c1fe | ||
|
|
f49b70750a | ||
|
|
15be8fb329 | ||
|
|
0c96d9ecde | ||
|
|
e01134a9c0 | ||
|
|
770f709a24 | ||
|
|
e2a37141da | ||
|
|
5accd2f847 | ||
|
|
46eaabf722 | ||
|
|
807da66d87 | ||
|
|
06861f8577 | ||
|
|
44ee38a868 | ||
|
|
89652e9ff2 | ||
|
|
6f1f35217f | ||
|
|
22c6e81e68 | ||
|
|
ab57dfc5c7 | ||
|
|
8d609ed881 | ||
|
|
0e9a422335 | ||
|
|
5cdd2d4947 | ||
|
|
f946cddd45 | ||
|
|
d45aa0dae9 | ||
|
|
464c7e6b47 | ||
|
|
9e4468acb6 | ||
|
|
dcb49fe731 | ||
|
|
03259e67d9 | ||
|
|
0ea662f57f | ||
|
|
4b629b9b28 | ||
|
|
a8b5ebba18 | ||
|
|
c904d9f66c | ||
|
|
f52c5bc6da | ||
|
|
a074ea8ba6 | ||
|
|
3a3f55f9a2 | ||
|
|
490cabcbe3 | ||
|
|
367c5bcfb1 | ||
|
|
d10de8d7df | ||
|
|
41749db028 | ||
|
|
e30f302de9 | ||
|
|
d119ed10b9 | ||
|
|
9281289a1b | ||
|
|
1683c0c679 | ||
|
|
88a8b9569d | ||
|
|
18aaa03381 | ||
|
|
aa3474d06e | ||
|
|
0accab638f | ||
|
|
29b52bc12e | ||
|
|
5840cd3402 | ||
|
|
926ff0f4f8 | ||
|
|
13689e7eac | ||
|
|
e4ed4ad3a8 | ||
|
|
25e4072fef | ||
|
|
1e6037019e | ||
|
|
da083aaab4 | ||
|
|
7a7853d434 | ||
|
|
eebe12ca27 | ||
|
|
7aaade8780 | ||
|
|
cb185d4d44 | ||
|
|
3f691dc4f0 | ||
|
|
d4c33f71eb | ||
|
|
ad106a07ea | ||
|
|
2ad3a0a7f5 | ||
|
|
dc461d4de6 | ||
|
|
d1a9b50dfe | ||
|
|
9a0da8d011 | ||
|
|
2d7e3877e7 | ||
|
|
0248ae0a96 | ||
|
|
9fd27f3b2c | ||
|
|
4152fcc934 | ||
|
|
53c887a06a | ||
|
|
316e10baa0 | ||
|
|
8a71c6bc4a | ||
|
|
9b806de7b0 | ||
|
|
a14dadc228 | ||
|
|
ca850b3d30 | ||
|
|
c01dbbea0e | ||
|
|
b883307881 | ||
|
|
ab9bcb1e0b | ||
|
|
3dc22ff0b8 | ||
|
|
5e382e12ad | ||
|
|
103e55ff97 | ||
|
|
6140b3eee8 | ||
|
|
09574a69e9 | ||
|
|
c53f961e12 | ||
|
|
a1d370fc04 | ||
|
|
471b679d3f | ||
|
|
e60caa8648 | ||
|
|
ccfc8a8d30 | ||
|
|
6a7b7bec6a | ||
|
|
0926c48aea | ||
|
|
d10a9e40ed | ||
|
|
4df12ee5ea | ||
|
|
433294fb40 | ||
|
|
298fe50dd1 | ||
|
|
1717fffe8f | ||
|
|
41521913d5 | ||
|
|
e75ca5d2ff | ||
|
|
0d2081ed30 | ||
|
|
d6abdc2a55 | ||
|
|
0a0cf77461 | ||
|
|
a5c438068c | ||
|
|
d2c8839a69 | ||
|
|
21b560a3b9 | ||
|
|
b1d8de62d4 | ||
|
|
1e41857d37 | ||
|
|
63920e95d3 | ||
|
|
7856b2b7ee | ||
|
|
5daf34ba29 | ||
|
|
e513cbeaaa | ||
|
|
c782ba2429 | ||
|
|
50dae3f5d8 | ||
|
|
d3e6551b40 | ||
|
|
0e1d1a788d | ||
|
|
dfafce7f05 | ||
|
|
eb7381457a | ||
|
|
2f8baf9559 | ||
|
|
34cb03c7df | ||
|
|
d76ecb8a38 | ||
|
|
943c2a0bd9 | ||
|
|
a7552c8bb8 | ||
|
|
8cd78041a2 | ||
|
|
3fe3499ec2 | ||
|
|
70c49f67c4 | ||
|
|
308c316dbf | ||
|
|
c660b3a9aa | ||
|
|
642bb357d3 | ||
|
|
4978177584 | ||
|
|
ae8a69a840 | ||
|
|
383c2be9fc | ||
|
|
1cc4653672 | ||
|
|
6b6daba17a | ||
|
|
d8eb090a7a | ||
|
|
eb2e96f13b | ||
|
|
41201cbb96 | ||
|
|
151115ed10 | ||
|
|
7d4154e0d4 | ||
|
|
7a470daa26 | ||
|
|
a4e40d06ac | ||
|
|
875efd2a42 | ||
|
|
9ee0ac92c3 | ||
|
|
c7f554bebb | ||
|
|
6fe8d71e61 | ||
|
|
f6f24bce25 | ||
|
|
8b81151ec1 | ||
|
|
55033ed25e | ||
|
|
a829a60341 | ||
|
|
0a25e78964 | ||
|
|
dec1acdfb1 | ||
|
|
4f0970138b | ||
|
|
4707997aec | ||
|
|
ae5a4b5f4f | ||
|
|
5187b55a2e | ||
|
|
60078852bd | ||
|
|
580bacaf93 | ||
|
|
eb1ab920cf | ||
|
|
6c0aabd36e | ||
|
|
a3d2443b70 | ||
|
|
313ca172a5 | ||
|
|
ceb4e53f15 | ||
|
|
4510b4997a | ||
|
|
12cc43bd7c | ||
|
|
21069c107a | ||
|
|
93032afe0f | ||
|
|
f422fe13f4 | ||
|
|
ed551d1eb3 | ||
|
|
58cd4119a6 | ||
|
|
c8147ce3d4 | ||
|
|
00df171604 | ||
|
|
50ca38d4d0 | ||
|
|
e31e5c1a5b | ||
|
|
c80356a90a | ||
|
|
4909b039c0 | ||
|
|
dc8ee2718b | ||
|
|
8118f4ad18 | ||
|
|
de422a0d93 | ||
|
|
cbffa01014 | ||
|
|
f8688c33a0 | ||
|
|
6e0e56b85e | ||
|
|
7e81522ed4 | ||
|
|
0c8a76fceb | ||
|
|
35273abff7 | ||
|
|
6c1f3ea4bf | ||
|
|
5e261e0d7f | ||
|
|
53553ece6f | ||
|
|
33d47ff1c8 | ||
|
|
16b8657a47 | ||
|
|
264c834c2c | ||
|
|
28b05465ea | ||
|
|
b903e57ef9 | ||
|
|
d5ffba47a2 | ||
|
|
34b99bfede | ||
|
|
4f5aac8f50 | ||
|
|
fe53eeb010 | ||
|
|
67b6f69926 | ||
|
|
6bf62a3d4e | ||
|
|
54b911550f | ||
|
|
31a988877a | ||
|
|
88642d81c0 | ||
|
|
135e8d98e9 | ||
|
|
bd5c8fd403 | ||
|
|
3b112793aa | ||
|
|
2fc8d9ae4f | ||
|
|
afe63f02fa | ||
|
|
6aa744dff9 | ||
|
|
095b04d31c | ||
|
|
6136fe0c8b | ||
|
|
e2f3752018 | ||
|
|
5d0fdf01f3 | ||
|
|
cb4b6bc76d | ||
|
|
bb0f57b5ab | ||
|
|
c23981b97f | ||
|
|
c005fc6754 | ||
|
|
8d24048c26 | ||
|
|
ac1ae9f9db | ||
|
|
53e8a40e1b | ||
|
|
a7d803bc82 | ||
|
|
944ae100fa | ||
|
|
b68fd36476 | ||
|
|
74d530d65e | ||
|
|
b5cf71c7af | ||
|
|
8d663f80bd | ||
|
|
77257e2532 | ||
|
|
44d6719107 | ||
|
|
05ddaa6356 | ||
|
|
d8a6b6528a | ||
|
|
478c781822 | ||
|
|
93039252f2 | ||
|
|
3efc3ebe25 | ||
|
|
1f5824a55b | ||
|
|
d364c2f53e | ||
|
|
7d0bc98e3e | ||
|
|
85e0b26a53 | ||
|
|
c3f21c8af2 | ||
|
|
8bd2148ae4 | ||
|
|
2c74cef483 | ||
|
|
3a1911f5cd | ||
|
|
d871886ec5 | ||
|
|
146a2e8aae | ||
|
|
727784d90a | ||
|
|
67647bc51e | ||
|
|
3ce9d84669 | ||
|
|
af6ed6c296 | ||
|
|
3f65c0593f | ||
|
|
98e7941371 | ||
|
|
3fb5eb3ec9 | ||
|
|
497c748955 | ||
|
|
230247af17 | ||
|
|
bbea40833b | ||
|
|
146ca6a9c9 | ||
|
|
fb7e8c730c | ||
|
|
e5135ae67b | ||
|
|
f1b524460e | ||
|
|
9c9c910fa8 | ||
|
|
63330cbb84 | ||
|
|
5c6816f8ab | ||
|
|
4c0366e340 | ||
|
|
38e2e4e16a | ||
|
|
430b24c0f3 | ||
|
|
b22b187ce0 | ||
|
|
cc32d6cb98 | ||
|
|
66332ae9e2 | ||
|
|
b6dd3acfea | ||
|
|
b655e89af0 | ||
|
|
2879cf51cd | ||
|
|
725dabea88 | ||
|
|
35f133cacd | ||
|
|
b0e4f2c696 | ||
|
|
65c423917e | ||
|
|
f128af26ec | ||
|
|
1bf955baa8 | ||
|
|
cee2ff2641 | ||
|
|
819cd6c3e2 | ||
|
|
67da32857a | ||
|
|
6796145fa9 | ||
|
|
fea1bcc123 | ||
|
|
b6125b8063 | ||
|
|
ad397bb1b6 | ||
|
|
dc333f052d | ||
|
|
a77e120fc2 | ||
|
|
07166e591e | ||
|
|
a1aac43a4e | ||
|
|
cc69471576 | ||
|
|
ed8e01ea0c | ||
|
|
4fb847196c | ||
|
|
40ee2cb868 | ||
|
|
8d0b2edba2 | ||
|
|
3b6e10a1f9 | ||
|
|
4d4a849c9b | ||
|
|
58f94fe9ec | ||
|
|
ebff6f995a | ||
|
|
5a8a4bb25b | ||
|
|
6d8e781c72 | ||
|
|
834374d0f2 | ||
|
|
f0d17b1f86 | ||
|
|
5478879a37 | ||
|
|
4e2f50eee7 | ||
|
|
c47e25bef3 | ||
|
|
b5203b97bb | ||
|
|
a7ac9a0aa8 | ||
|
|
0540efa171 | ||
|
|
b3b274acf7 | ||
|
|
944ffcb788 | ||
|
|
865baf0d5f | ||
|
|
8b555503c1 | ||
|
|
11bb6bb2aa | ||
|
|
63864adbda | ||
|
|
0d89989c20 | ||
|
|
59d4821bdc | ||
|
|
24ecba3e9e | ||
|
|
d9f9b86996 | ||
|
|
c27febf172 | ||
|
|
d18af9daf8 | ||
|
|
4813a35eec | ||
|
|
5bd33084dd | ||
|
|
939c54792f | ||
|
|
28f6f58dd7 | ||
|
|
27fd1d11b8 | ||
|
|
39355d3bd6 | ||
|
|
1582b486db | ||
|
|
e4d58dd9cb | ||
|
|
f417d640e0 | ||
|
|
f79e16f48d | ||
|
|
365daab33c | ||
|
|
62fceaaa3c | ||
|
|
5af78fb18a | ||
|
|
2dae632d24 | ||
|
|
680e460ecd | ||
|
|
07e715bb6d | ||
|
|
e255bc0874 | ||
|
|
0d0129e7c3 | ||
|
|
3ca24bd45c | ||
|
|
a627363afa | ||
|
|
bcf6ca9e52 | ||
|
|
561579a7d6 |
No files matched your search
@@ -0,0 +1,100 @@
|
||||
### Manual build Box86 with Github Action
|
||||
name: Custom build Box86
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
platform:
|
||||
description: 'Target platform name'
|
||||
required: true
|
||||
default: 'GENERIC_ARM'
|
||||
type: choice
|
||||
options:
|
||||
- I386
|
||||
- GENERIC_ARM
|
||||
- A64
|
||||
- GAMESHELL
|
||||
- ODROID
|
||||
- PANDORA
|
||||
- PHYTIUM
|
||||
- PYRA
|
||||
- RK3288
|
||||
- RK3399
|
||||
- RPI4
|
||||
- RPI4ARM64
|
||||
- SD845
|
||||
build_type:
|
||||
description: 'Build type'
|
||||
required: true
|
||||
default: 'RelWithDebInfo'
|
||||
type: choice
|
||||
options:
|
||||
- RelWithDebInfo
|
||||
- Release
|
||||
- Debug
|
||||
- MinSizeRel
|
||||
dynarec:
|
||||
description: 'Enable dynarec'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
trace:
|
||||
description: 'Enable trace'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box86 Repository"
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ github.event.inputs.platform }} != 'I386' && ${{ github.event.inputs.platform }} != 'GENERIC_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ github.event.inputs.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
else
|
||||
if [[ ${{ github.event.inputs.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
else
|
||||
echo "BOX86_PLATFORM_MARCRO=-DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ github.event.inputs.build_type }}"
|
||||
echo "Dynarec Enabled: ${{ github.event.inputs.dynarec }}"
|
||||
echo "Trace Enabled: ${{ github.event.inputs.trace }}"
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }}\
|
||||
-DARM_DYNAREC:BOOL=${{ github.event.inputs.dynarec }}\
|
||||
-DHAVE_TRACE:BOOL=${{ github.event.inputs.trace }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box86-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
### Auto build Box86 and release its binary with Github Action
|
||||
name: Build and Release Box86
|
||||
|
||||
on:
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
push:
|
||||
@@ -10,16 +10,16 @@ on:
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
pull_request:
|
||||
pull_request:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
|
||||
jobs:
|
||||
@@ -27,10 +27,25 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM]
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM, ANDROID]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-18.04
|
||||
- platform: TEGRAX1
|
||||
type: Trace
|
||||
os: ubuntu-18.04
|
||||
- platform: TEGRAX1ARM32
|
||||
type: Release
|
||||
os: ubuntu-18.04
|
||||
- platform: TEGRAX1ARM32
|
||||
type: Trace
|
||||
os: ubuntu-18.04
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box86 Repository"
|
||||
uses: actions/checkout@v2
|
||||
@@ -40,15 +55,22 @@ jobs:
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ matrix.platform }} != 'I386' && ${{ matrix.platform }} != 'OTHER_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
sudo apt-get -y install git cmake make python3
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
|
||||
unzip android-ndk-r23b-linux.zip
|
||||
echo "BOX86_COMPILER=$PWD/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-DANDROID=1 -DNOLOADADDR=1" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
ls /bin/*gcc*
|
||||
else
|
||||
echo BOX86_PLATFORM_MARCRO="-DARM_DYNAREC=ON -DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
@@ -63,26 +85,36 @@ jobs:
|
||||
echo BOX86_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
|
||||
echo BOX86_HAVE_TRACE=1 >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ env.BOX86_BUILD_TYPE }}"
|
||||
echo "Trace Enabled: ${{ env.BOX86_HAVE_TRACE }}"
|
||||
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }} -DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }} -DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }}\
|
||||
${{ env.BOX86_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
|
||||
- name: "Test Box86"
|
||||
if: ${{ matrix.platform == 'I386' }}
|
||||
run: |
|
||||
cd build
|
||||
ctest -j$(nproc)
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box86-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
|
||||
+95
-36
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
|
||||
option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
|
||||
@@ -9,19 +9,23 @@ option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch a
|
||||
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(ODROIDN2 "Set to ON if targeting an Odroid-N2 device" ${ODROIDN2})
|
||||
option(TEGRAX1 "Set to ON if targeting an Tegra X1 (ARM64) based device" ${TEGRAX1})
|
||||
option(TEGRAX1ARM32 "Set to ON if targeting an Tegra X1 (ARM32) based device" ${TEGRAX1ARM32})
|
||||
option(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(LX2160A "Set to ON if targeting an LX2160A based device" ${LX2160A})
|
||||
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)
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRAX1ARM32 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64 OR LX2160A)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
@@ -51,7 +55,13 @@ else()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
|
||||
if(RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
cmake_host_system_information(RESULT CMAKE_HOST_SYSTEM_PROCESSOR QUERY OS_PLATFORM)
|
||||
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(_aarch64 AND (RK3399 OR ODROIDN2 OR TEGRAX1 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64 OR LX2160A))
|
||||
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)
|
||||
@@ -123,10 +133,28 @@ 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(ODROIDN2)
|
||||
add_definitions(-DODROIDN2)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(TEGRAX1)
|
||||
add_definitions(-DTEGRAX1)
|
||||
add_definitions(-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(TEGRAX1ARM32)
|
||||
add_definitions(-DTEGRAX1ARM32)
|
||||
add_definitions(-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(LX2160A)
|
||||
add_definitions(-DLX2160A)
|
||||
add_definitions(-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
elseif(ARM_DYNAREC)
|
||||
#if DYNAREC is selected alone, without any arch
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
|
||||
@@ -157,6 +185,7 @@ endif()
|
||||
|
||||
if(NOALIGN)
|
||||
add_definitions(-DNOALIGN)
|
||||
add_definitions(-pipe -march=core2 -msse2)
|
||||
endif()
|
||||
|
||||
if(HAVE_TRACE)
|
||||
@@ -223,6 +252,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/box86context.c"
|
||||
"${BOX86_ROOT}/src/build_info.c"
|
||||
"${BOX86_ROOT}/src/custommem.c"
|
||||
"${BOX86_ROOT}/src/mallochook.c"
|
||||
"${BOX86_ROOT}/src/tools/bridge.c"
|
||||
"${BOX86_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX86_ROOT}/src/tools/fileutils.c"
|
||||
@@ -358,6 +388,8 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgmp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgcrypt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtk3.c"
|
||||
@@ -370,9 +402,16 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgconf2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstvideo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgsttag.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstbase.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstapp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
@@ -409,8 +448,20 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsoftokn3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfreebl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsecret1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedmimalloc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedselinux.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibcairogobject.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibvkd3d.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgomp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcap.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpcap.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
)
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
@@ -465,6 +516,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_printer.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_jmpnext.c"
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
@@ -495,6 +547,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_df.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f0.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_660f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_66f0.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f20f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f30f.c"
|
||||
)
|
||||
@@ -552,7 +605,7 @@ if(ARM_DYNAREC)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} dynarec m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread)
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread resolv)
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
@@ -572,9 +625,10 @@ add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} m dl)
|
||||
target_link_libraries(${BOX86} c m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
#target_link_libraries(${BOX86} c m dl rt pthread resolv)
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec)
|
||||
@@ -593,11 +647,6 @@ else()
|
||||
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)
|
||||
@@ -606,6 +655,7 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
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/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
@@ -649,105 +699,114 @@ set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVIS
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
if(NOT LD80BITS)
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
|
||||
add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME ucomiss COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile.txt
|
||||
add_test(NAME sse COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTNAN=0")
|
||||
|
||||
add_test(NAME longjumpInSignals COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile.txt
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME idiv COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
box86 (0.2.6) unstable; urgency=low
|
||||
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
* Many small fixes and improvement to get steam and SteamPlay working (along with box64)
|
||||
* Added some workaround for program calling uname to mimic x86 system
|
||||
* Added some more Vulkan extensions
|
||||
* Added some granularity to mmap64, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* - better handling of SSE/x87 registers
|
||||
* - optimisation to limit float/double conversion
|
||||
* - better handling of "internal" jump inside a dynablock
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
11
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
Source: box86
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Ryan Fortner <[email protected]>
|
||||
Build-Depends: cmake, debhelper (>=11~)
|
||||
Standards-Version: 4.1.4
|
||||
Homepage: https://github.com/ptitSeb/box86
|
||||
|
||||
Package: box86
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
Format-Specification: http://dep.debian.net/deps/dep5/
|
||||
|
||||
Files: *
|
||||
Copyright: © 2022 Sebastien Chevalier
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
|
||||
.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
box86: no-manual-page
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.5 --exclude=libstdc++.so.6
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
Bug-Database: https://github.com/ptitSeb/box86/issues
|
||||
Bug-Submit: https://github.com/ptitSeb/box86/issues/new
|
||||
Repository: https://github.com/ptitSeb/box86.git
|
||||
Repository-Browse: https://github.com/ptitSeb/box86
|
||||
Security-Contact: [email protected]
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
version=3
|
||||
@@ -1,3 +1,25 @@
|
||||
v0.2.6
|
||||
======
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
* Many small fixes and improvement to get steam and SteamPlay working (along with box64)
|
||||
* Added some workaround for program calling uname to mimic x86 system
|
||||
* Added some more Vulkan extensions
|
||||
* Added some granularity to mmap64, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* better handling of SSE/x87 registers
|
||||
* optimisation to limit float/double conversion
|
||||
* better handling of "internal" jump inside a dynablock
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
|
||||
v0.2.4
|
||||
======
|
||||
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
|
||||
|
||||
+73
-26
@@ -1,5 +1,17 @@
|
||||
Compiling
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
#### Debian-based Linux
|
||||
You can use [@Itai-Nelken](https://github.com/Itai-Nelken)'s apt repository to install precompiled box86 debs, updated weekly.
|
||||
|
||||
```
|
||||
sudo wget https://itai-nelken.github.io/weekly-box86-debs/debian/box86.list -O /etc/apt/sources.list.d/box86.list
|
||||
wget -qO- https://itai-nelken.github.io/weekly-box86-debs/debian/KEY.gpg | sudo apt-key add -
|
||||
sudo apt update && sudo apt install box86 -y
|
||||
```
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
#### for Pandora
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
@@ -14,26 +26,33 @@ Compiling
|
||||
|
||||
#### for Raspberry Pi
|
||||
|
||||
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
|
||||
_A build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
cd box86
|
||||
mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make
|
||||
mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo # -DRPI4=1 for Pi4 (use `-DRPI2=1` etc for other models)
|
||||
make # can use `make -j2`, `make -j3`, etc to speed up 1st build (but beware of running out of memory if going too high)
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
Note that you can use `make -j2` or more to speed up 1st build, but beware of the memory requirement if you go to high.
|
||||
|
||||
#### for Raspberry Pi on 64bits OS
|
||||
#### for Raspberry Pi on 64bit OS
|
||||
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models. Change `-DRPI4=1` to `-DRPI4ARM64=1` for compiling on arm64. (armhf multiarch or chroot required alongside armhf gcc. Install it with 'sudo apt install gcc-arm-linux-gnueabihf'.)_
|
||||
_armhf multiarch or chroot required for running box86 (armhf) on aarch64_
|
||||
|
||||
```
|
||||
# example of enabling multiarch & installing libc6:armhf (to run box86:armhf on aarch64)
|
||||
# (running i386-wine on aarch64 requires more armhf libraries)
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update
|
||||
sudo apt-get install libc6:armhf -y
|
||||
```
|
||||
_Build box86:armhf on RPiOS 64-bit ARM (aarch64)_
|
||||
```
|
||||
sudo apt install gcc-arm-linux-gnueabihf # building 32-bit ARM code on aarch64 requires this armhf gcc cross-compiler toolchain
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
cd box86
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo # -DRPI4ARM64=1 for Pi4 aarch64 (use `-DRPI2ARM64=1` etc for other models)
|
||||
make -j2
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
@@ -47,7 +66,9 @@ sudo systemctl restart systemd-binfmt
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most RK3399 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Tinker Board (1/1S) or RK3288
|
||||
|
||||
@@ -57,19 +78,23 @@ As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environme
|
||||
|
||||
`mkdir build; cd build; cmake .. -DA64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most Allwinner A64 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most Allwinner A64 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Snapdragon 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`.
|
||||
As most Snapdragon 845 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Phytium
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian/ubuntu, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most Phytium (D2000 or FT2000/4) devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Other ARM Linux platforms
|
||||
|
||||
@@ -79,42 +104,64 @@ As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf
|
||||
|
||||
`mkdir build; cd build; cmake .. -DCMAKE_C_FLAGS="-m32" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### use ccmake
|
||||
### use ccmake
|
||||
|
||||
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
|
||||
|
||||
#### Customize your build
|
||||
### Customize your build
|
||||
|
||||
*use ccache if you have it*
|
||||
#### use ccache if you have it
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
*have some debug info*
|
||||
#### To have some debug info
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
#### To have a Trace Enabled build
|
||||
|
||||
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
#### to have ARM Dynarec
|
||||
|
||||
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode). Note that compiling with `ARM_DYNAREC` but without hardware profile is not advise. If you get error building that "target CPU does not support ARM mode", then try to pick hardware profile (like ODROID for armv7 or PI4 for armv8). Also, if you are using a 64bits with armhf multiarch, it's much easier to pick one of the hardware profile like `RPI4ARM64`, `RK3399`, `PHYTIUM` or `SD845`.
|
||||
###### *Note: VFPv3 and NEON are required for Dynarec.*
|
||||
|
||||
*not building from a git clone*
|
||||
###### *Note: Compiling with `ARM_DYNAREC` without selecting a hardware profile is not advised.*
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
|
||||
Dynarec is only available on the ARM architecture (for the meantime anyways). Activate it by using `-DARM_DYNAREC=1`.
|
||||
|
||||
You will most likely need `-marm` in compilation flags (Many compilers default to the Thumb instruction set and Dynarec does not support this).
|
||||
|
||||
###### *Note: If you get error building that "target CPU does not support ARM mode", then try to pick a hardware profile (like ODROID for armv7 or PI4 for armv8).*
|
||||
|
||||
##### 64bit OS with Dynarec
|
||||
|
||||
If you are using a 64bit OS with armhf multiarch, it's much easier to pick one of the hardware profiles.
|
||||
|
||||
`RPI4ARM64`, `RK3399`, `PHYTIUM` or `SD845`.
|
||||
|
||||
#### Not building from a git clone
|
||||
If you are not building from a git clone (for example, downloading a release source code zip from github), you need to use `-DNOGIT=1` from cmake to be able to build (box86 uses git SHA1 to show last commit in version number).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
A few tests are included with box86.
|
||||
|
||||
They can be launched using the `ctest` command.
|
||||
|
||||
The tests are very basic and only tests some functionality for now.
|
||||
|
||||
----
|
||||
|
||||
Note about devices with Tegra X1 and newer.
|
||||
|
||||
Nvidia don't provide armhf libraries for their GPU drivers at this moment so there is no special variable to compile it for them as it would be missleading for many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. As instalation of Mesa can break Nvidia driver, safest option is usage of chroot.
|
||||
NVIDIA doesn't provide armhf libraries for their GPU drivers at this time. There is no special variable to compile box86 for them, as it would be misleading to many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. Installation of Mesa can break the NVIDIA driver, so the safest option is to use a chroot environment.
|
||||
|
||||
----
|
||||
|
||||
Debian Packaging
|
||||
----
|
||||
Box86 can also be packaged into a .deb file with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`.
|
||||
|
||||
+25
-20
@@ -1,22 +1,18 @@
|
||||
# box86
|
||||
|
||||

|
||||
|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[](https://app.travis-ci.com/ptitSeb/box86)
|
||||
[View changelog](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Report an error](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environment).
|
||||
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at those bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
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).)
|
||||
|
||||
@@ -29,13 +25,21 @@ To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
|
||||
|
||||
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
----
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
----
|
||||
|
||||
Here are 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
You can find many more Box86 video on Youtube in the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) Channels
|
||||
You can find many more Box86 videos on the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube channels.
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
Compatibility list is here: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
@@ -87,10 +91,11 @@ 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`.
|
||||
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm installed. To install it on Debian, run `sudo apt install libnm0`.
|
||||
- If you have trouble installing Steam, you can find `install_steam.sh` in the root folder of the box86 repo. This simple script will download and install steam in your home folder, and then create a shortcut to steam in `/usr/local/bin` (and for this it will ask for sudo permission). Simply use `steam` to launch once it's installed. Note that the installation, being in the Home folder, will only work for a single user. Don't use this script if you need a multi-user installation.
|
||||
- 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`.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables (it's automatically there if you used the `install_steam.sh` script)
|
||||
- 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 aforementioned feature, it is safer to add it to your system if you intend to play those games. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
|
||||
|
||||
Steam for Windows installs fine but doesn't work yet.
|
||||
|
||||
@@ -107,19 +112,19 @@ Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those mod
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box86 already wrap vulikan. If your system has a 32bits vulkan driver, box86 will use it when needed. Note that vulkan wrapping has not been tested much, due to the limited vulkan support on the hardware I currently own. Profile 1.0 and 1.1, whith some extension, should be OK. 1.2 is not really wrapped. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardxware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
Box86 already wrap Vulkan. If your system has a 32bits Vulkan driver, box86 will use it when needed. 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, with 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 (hardware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
|
||||
----
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box86 developpement.
|
||||
I want to thank everyone who has contributed to box86 development.
|
||||
There are many ways to contribute: code, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, icecream95, M-HT
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* For their continous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
* For their continuous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
And I also thank the many other people who participated even once in the project.
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||

|
||||
|
||||
Linux用户空间的x86应用模拟器
|
||||
|
||||
[更新历史](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [报告错误](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
使用Box86可以在ARM或其他非x86架构的Linux操作系统上运行x86 Linux程序(例如游戏),请注意,主机系统需要是**32位小端**的。
|
||||
|
||||
你需要一个**32位**的子系统来运行Box86,因为Box86在纯64位系统上无法使用,同时你也需要一个**32位**的Linux编译工具链来编译Box86,例如**arm-linux-gnueabihf-gcc**, 否则你将无法编译Box86 (一般的64位ARM编译工具链如 aarch64-linux-gnu-gcc 不支持"-marm"编译选项,会编译失败并报错)。
|
||||
|
||||
因为Box86使用了一些“系统”库的原生版本,例如libc、libm、SDL和OpenGL,所以在很多情况下性能很不错,也可以方便地与其他应用集成使用。点击[此处](https://box86.org/index.php/2021/06/game-performances/)查看Benchmark示例。
|
||||
|
||||
大多数x86游戏都用到了OpenGL,所以在ARM平台上类似于[gl4es](https://github.com/ptitSeb/gl4es)的解决方案通常是必要的。(许多ARM平台仅提供OpenGL ES支持,又或者他们的OpenGL实现很不可靠(例如Android上的OpenGL)。)
|
||||
|
||||
Box86为ARM平台集成了DynaRec(动态重编译器),比仅使用解释器提升5到10倍性能。关于Dynarec如何工作的更多信息,可以在[这里](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/)找到。
|
||||
|
||||
许多游戏已可在不做多少改动的情况下直接运行,例如:《粘粘世界》(WorldOfGoo)、《航空大亨豪华版》(Airline Tycoon Deluxe)、《超越光速》(FTL)等、基于GameMaker的游戏(《传说之下》(UNDERTALE)等)。
|
||||
|
||||
如果你想开发Box86,最好安装ccache,以缓存编译结果。
|
||||
如果你需要启用Trace跟踪(例如输出寄存器值与各条被执行的x86指令),你也需要安装[Zydis](https://github.com/zyantific/zydis)。
|
||||
|
||||
一些x86内部操作码使用“Realmode X86 Emulator Library”的部分内容,请参阅[x86primop.c](../src/emu/x86primop.c)了解版权详情
|
||||
|
||||
----
|
||||
|
||||
编译与安装
|
||||
----
|
||||
> [Box86编译指南](COMPILE.md)
|
||||
>
|
||||
> [Box86 Wine安装指南](X86WINE.md)
|
||||
|
||||
一些示例视频
|
||||
----
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
在这几个Youtube频道可以找到更多Box86的相关视频
|
||||
|
||||
[MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
|
||||
|
||||
[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
|
||||
|
||||
[The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
|
||||
程序兼容性列表: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
感谢制作Logo和图标的grayduck!
|
||||
|
||||
注意:
|
||||
不要把本项目和[86box](https://github.com/86Box/86Box)搞混了,后者是一个"**全量**"的x86 PC模拟器。
|
||||
|
||||
----
|
||||
|
||||
使用方法
|
||||
----
|
||||
|
||||
有若干环境变量可以设置Box86的行为。
|
||||
|
||||
点击[这里](USAGE.md)了解所有的环境变量和它们的作用。
|
||||
|
||||
请注意:Box86的Dynarec提供了一种包含"内存保护"和段错误信号处理程序的机制来处理JIT代码。简单来说,如果你想用GDB来调试一个使用JIT代码的运行程序(比如mono/Unity3D),就会触发很多“正常”的段错误。建议在GDB中使用类似于`handle SIGSEGV nostop`的命令,来防止在每个段错误时都停止程序运行,如果你想捕获段错误,可以在`signals.c`中的`my_memprotectionhandler`中放置一个断点。
|
||||
|
||||
----
|
||||
|
||||
关于64位平台的注意事项
|
||||
----
|
||||
|
||||
Box86的工作原理是直接将函数调用从x86_转换到主机系统,主机系统(Box86运行的系统)需要有32位的库。Box86并不包括任何64位<->32位的转换。所以如果你需要在64位平台上运行Box86,那么你需要建立一个32位的库环境,并以32位ARM为目标系统编译Box86(例如使用arm-linux-gnueabihf-gcc工具链交叉编译或直接在armhf chroot环境中编译运行)。
|
||||
|
||||
如果你需要运行64位应用,请考虑使用[Box64](https://github.com/ptitSeb/box64),它可以在64位平台上运行x86_64程序,但请再一次注意运行x86程序需要Box86与32位库环境(就像在x86_64的Linux上运行x86程序需要x86 multiarch库一样)。
|
||||
|
||||
----
|
||||
|
||||
关于Unity游戏的注意事项
|
||||
----
|
||||
|
||||
当前对于Unity游戏的模拟仍不完善。Unity使用Mono,但它所使用的信号机制还没有被完美模拟。理论上可以使用原生Mono库(在[这里](https://github.com/Unity-Technologies/mono)可以找到),但Mono的封装比较麻烦,现在还没完成,所以我们使用了模拟的Mono库,目前Mono的JIT动态编译代码已由"内存保护"(Protected memory)机制实现,应该能正常运行。
|
||||
|
||||
同时,一些Unity3D游戏需要OpenGL 3+,目前在大部分Arm开发板上提供OpenGL 3+是很困难的。
|
||||
|
||||
所以,并不是所有的Unity游戏都能运行,尤其是那些需要提供很高的OpenGL配置(3.2+)的游戏更有可能不行,但除此之外应该问题不大,而且能运行的游戏的性能应该不错。
|
||||
|
||||
提示:如果游戏开始后在显示任何东西之前退出,在Raspberry Pi4上使用`MESA_GL_VERSION_OVERRIDE=3.2`,在Panfrost上使用`PAN_MESA_DEBUG=gl3`来使用更高的配置文件。
|
||||
|
||||
----
|
||||
|
||||
关于Steam的注意事项
|
||||
----
|
||||
|
||||
Linux Steam 现在可以在Box86上运行,但还是有点不稳定,而且有些功能可能不正常:
|
||||
- 如果Steam在显示登录界面后崩溃,你可能需要安装libappindicator库,例如运行`sudo apt install libappindicator1`。
|
||||
- 如果你选择记住密码,而Steam在下次启动时崩溃,你可能需要安装libnm库,例如运行`sudo apt install libnm0`。
|
||||
- Steam不能在正常的大界面模式下工作,因为Steam在浏览器模式使用的一些组件只能在64位平台上运行。所以请在查看选项卡中选择"小模式",否则Steam将无法正常显示列表。或者在启动Steam添加`+open steam://open/minigameslist`参数,这样Steam将会直接在小模式下启动。
|
||||
- 为了避免"libc.so.6 is absent"的错误,请添加环境变量`STEAMOS=1` 与 `STEAM_RUNTIME=1`。
|
||||
- 一些游戏(例如基于起源引擎的游戏:《传送门》、《半衰期2》)使用了libtcmalloc库,Box86会尝试检测它们并通过LD_PRELOAD预加载它们来获得更好的兼容性,虽然应该可以在没有上述功能的情况下工作,但保险起见,我们还是建议你安装它,例如运行`sudo apt install libtcmalloc-minimal4`。
|
||||
|
||||
Windows Steam 可以安装但目前不能运行。
|
||||
|
||||
----
|
||||
|
||||
关于Wine的注意事项
|
||||
----
|
||||
|
||||
Box86现在已经支持Wine。Wine的内建程序全部能运行,许多Windows 程序和游戏也运行良好。但是不要忘记大多数 Windows 游戏都使用 Direct3D,这可能需要完整的 OpenGL 驱动程序和尽可能高的配置文件(基于 ES2 后端的 gl4es 现在不能运行 Wine 的Direct3D组件)。
|
||||
注意:如果你想在 Raspberry Pi 3 或更早版本上用 Box86 运行 Wine,由于这些设备的内核默认使用 2G/2G 虚拟内存分配(2G 空间用于用户态程序,2G 空间用于内核),与需要访问内存地址 > 2G 的 Wine 程序不兼容。 因此,你需要重新配置内核以使用 3G/1G 的内存分配方式。
|
||||
|
||||
----
|
||||
|
||||
关于Vulkan的注意事项
|
||||
----
|
||||
|
||||
Box86已经封装了Vulkan。如果设备的系统有32位的Vulkan驱动程序,Box86会在需要时使用它。但请注意,由于作者目前拥有的硬件上的Vulkan支持有限,因此Vulkan封装库尚未经过太多测试。 Vulkan 1.0、1.1与一些扩展应该能工作。 但Vulkan 1.2还没有被实现。已经有一些在树莓派4上的Vulkan演示 (Sascha Willems 的演示中,为x86构建的demo与与直接为armhf构建的demo工作均正常)。但请注意,Pi4的Vulkan驱动程序目前不支持 dxvk(wine DirectX->Vulkan 兼容层),这不是Box86的问题,而是由于缺少扩展(硬件支持)与一些其他驱动问题。而在Panfrost上,PanVK尚不成熟,暂时没有用它测试dxvk。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
----
|
||||
|
||||
我要感谢所有为 box86 开发做出贡献的人。
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, icecream95, M-HT
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* 为本项目持续的宣传:([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
(如果你的项目中使用了Box86,请不要忘记提及!)
|
||||
+67
-3
@@ -16,6 +16,11 @@ Controls the Dump of elf content
|
||||
* 0: No dump of elf information (Default)
|
||||
* 1: Dump elf sections and relocations and other information (also active if using `BOX86_LOG=3`)
|
||||
|
||||
#### BOX86_ROLLING_LOG
|
||||
Show last few wrapped function call when a Signal is caught
|
||||
* 0: No last function call printed (Default.)
|
||||
* 1: Last few wrapped function call printed when a signal is printed. Incompatible with BOX86_LOG>1 (may need BOX86_SHOWSEGV=1 also)
|
||||
|
||||
#### BOX86_NOBANNER
|
||||
Disables Box86 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
@@ -119,6 +124,7 @@ Forbid dynablock creation in the interval specified (helpfull for debugging beha
|
||||
Enables/Disables Box86's Dynarec building BigBlock.
|
||||
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 1 : Build Dynarec block as big as possible (Default.)
|
||||
* 2 : Build Dynarec block bigger (don't stop when block overlaps)
|
||||
|
||||
#### BOX86_DYNAREC_STRONGMEM
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
@@ -126,6 +132,22 @@ Enable/Disable simulation of Strong Memory model
|
||||
* 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_DYNAREC_X87DOUBLE
|
||||
Force the use of Double for x87 emulation
|
||||
* 0 : Try to use float when possible for x87 emulation (faster, Default)
|
||||
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis were it's enable automatically)
|
||||
|
||||
#### BOX86_DYNAREC_FASTNAN
|
||||
Enable/Disable generation of -NAN
|
||||
* 0 : Generate -NAN like on x86 (slower, more x86 accurate)
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (Default)
|
||||
|
||||
#### BOX86_DYNAREC_SAFEFLAGS
|
||||
Handling of flags on CALL/RET opcodes
|
||||
* 0 : Treat CALL/RET as if it never needs any flags (faster but may have side-effects)
|
||||
* 1 : most of RET will need flags, most of CALLS will not (Default)
|
||||
* 2 : All CALL/RET will need flags (slower, but might be needed. Automatically enabled for Vara.exe)
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
@@ -140,11 +162,26 @@ Enable/Disable simulation of Strong Memory model
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX86_ALLOWMISSINGLIBS
|
||||
Allow Box86 to continue even if a library is missing.
|
||||
#### BOX86_ALLOWMISSING_LIBS
|
||||
Allow Box86 to continue even if a library is missing (renamed from BOX86_ALLOWMISSINGLIBS).
|
||||
* 0 : Box86 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_ALLOWMISSING_SYMBOLS
|
||||
Allow dlopen with RTLD_NOW flag to not resolve all symbols.
|
||||
* 0 : Box86 will stop if a library have unresolved symbols. (Default.)
|
||||
* 1 : Continue even if a needed library have unresolved symbols (like symbols not yet wrapped).
|
||||
|
||||
#### BOX86_PREFER_WRAPPED
|
||||
Box86 will use wrapped libs even if the lib is specified with absolute path
|
||||
* 0 : Try to use emulated libs when they are defined with absolute path (Default.)
|
||||
* 1 : Use Wrapped native libs even if path is absolute
|
||||
|
||||
#### BOX86_PREFER_EMULATED
|
||||
Box86 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11
|
||||
* 0 : Native libs are prefered (Default.)
|
||||
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
|
||||
|
||||
#### BOX86_NOPULSE
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
@@ -153,18 +190,45 @@ Disables the load of pulseaudio libraries.
|
||||
#### BOX86_NOGTK
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
#### BOX86_NOVULKAN
|
||||
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_ENV
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var.
|
||||
|
||||
#### BOX86_ENV1
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
#### BOX86_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_SHOWSEGV
|
||||
Show Segfault signal even if a signal handler is present
|
||||
* 0 : Don't force segfault details when a signal handler is install (Default, to limit message spamming)
|
||||
* 1 : Show segfault details
|
||||
|
||||
#### BOX86_BACKTRACE
|
||||
Show a backtrace (native and emulated) on Signal
|
||||
* 0 : Don't show any backtrace (Default.)
|
||||
* 1 : Show native backtrace when a signal is dumped (not available on Andoid build)
|
||||
|
||||
#### BOX86_BASH
|
||||
Define x86 bash to launch script
|
||||
* yyyy
|
||||
Will use yyyy as x86 bash to launch script. yyyy needs to be a full path to a valid x86 version of bash. Note that is Box64 is available, an x86_64 version of bash can also be used. Also, BOX64_BASH env. var. will also be read if BOX86_BASH is not defined.
|
||||
|
||||
#### BOX86_BOX64
|
||||
Define where to find box64 binary
|
||||
* yyyy
|
||||
Will use yyyy as x86_64 interpretor, to launch x64_64 binaries
|
||||
#### BOX86_JITGDB
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
|
||||
+49
-12
@@ -3,10 +3,11 @@ _TwisterOS users: Wine, winetricks, and Box86 are already installed in TwisterOS
|
||||
|
||||
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 already has a 3G/1G split kernel and works with Wine, but **the Pi 3B+ and earlier models have a 2G/2G kernel and require a custom-compiled 3G/1G kernel to get Wine working.**_
|
||||
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM devices other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (for x64, use [box64](https://github.com/ptitSeb/box64) & wine-amd64 with an `aarch64` processor).
|
||||
|
||||
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM device's other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
|
||||
Installation files for Wine can be found in the [WineHQ repository](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/), the [TwisterOS FAQ](https://twisteros.com/faq.html) page, or the [PlayOnLinux website repository](https://www.playonlinux.com/wine/). Box86 requires the "i386" (x86) version of Wine even though we are installing it on an ARM processor.
|
||||
|
||||
@@ -15,6 +16,7 @@ The general procedure for installing Wine for Box86 is to...
|
||||
- Download all the install files (.deb, .zip, or even .pol files) for the version of Wine you wish to install
|
||||
- Unzip or dpkg the install files into one folder
|
||||
- Move that folder to the directory that you wish Wine to run from (in TwisterOS, this is `~/wine/` by default)
|
||||
- If you are running box86/i386-wine on a 64bit ARM OS (aarch64), you will also have to install some extra armhf libraries.
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries (`wine`, `winecfg`, and `wineserver`).
|
||||
- Boot wine to create a new wineprefix (`wine wineboot`).
|
||||
- Download winetricks (which is simply a very complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
@@ -50,11 +52,29 @@ sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg
|
||||
wine wineboot
|
||||
```
|
||||
|
||||
### Installing Wine for Box86 on Raspberry Pi OS Buster from WineHQ .deb files
|
||||
### Installing Wine for Box86 on Raspberry Pi OS from WineHQ .deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/)_
|
||||
|
||||
This install method allows you to install different versions of Wine. You may install any version and any branch of Wine that you wish (wine-devel, wine-stable, or wine-staging).
|
||||
This install method allows you to install different versions of Wine. You may install any version/branch of Wine that you wish.
|
||||
```
|
||||
### User-defined Wine version variables ################
|
||||
# - Replace the variables below with your system's info.
|
||||
# - Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.
|
||||
# - Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
|
||||
wbranch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386 - see below)
|
||||
wversion="7.1" #example: 7.1
|
||||
wid="debian" #example: debian, ubuntu
|
||||
wdist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, etc
|
||||
wtag="-1" #example: -1 (some wine .deb files have -1 tag on the end and some don't)
|
||||
|
||||
########################################################
|
||||
|
||||
# Clean up any old wine instances
|
||||
wineserver -k # stop any old wine installations from running
|
||||
rm -rf ~/.cache/wine # remove old wine-mono/wine-gecko install files
|
||||
rm -rf ~/.local/share/applications/wine # remove old program shortcuts
|
||||
|
||||
# Backup any old wine installations
|
||||
sudo mv ~/wine ~/wine-old
|
||||
sudo mv ~/.wine ~/.wine-old
|
||||
@@ -64,14 +84,12 @@ sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
|
||||
|
||||
# Download, extract wine, and install wine
|
||||
# (Replace the links/versions below with links/versions from the WineHQ site for the version of wine you wish to install. Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.)
|
||||
# (Pick an i386 version of wine-devel, wine-staging, or wine-stable)
|
||||
cd ~/Downloads
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel-i386_5.21~buster_i386.deb # NOTE: Replace this link with the version you want
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel_5.21~buster_i386.deb # NOTE: Also replace this link with the version you want
|
||||
dpkg-deb -xv wine-devel-i386_5.21~buster_i386.deb wine-installer # NOTE: Make sure these dpkg command matches the filename of the deb package you just downloaded
|
||||
dpkg-deb -xv wine-devel_5.21~buster_i386.deb wine-installer
|
||||
mv ~/Downloads/wine-installer/opt/wine* ~/wine
|
||||
wget https://dl.winehq.org/wine-builds/${wid}/dists/${wdist}/main/binary-i386/wine-${wbranch}-i386_${wversion}~${wdist}${wtag}_i386.deb # download
|
||||
wget https://dl.winehq.org/wine-builds/${wid}/dists/${wdist}/main/binary-i386/wine-${wbranch}_${wversion}~${wdist}${wtag}_i386.deb # (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
|
||||
dpkg-deb -x wine-${wbranch}-i386_${wversion}~${wdist}${wtag}_i386.deb wine-installer # extract
|
||||
dpkg-deb -x wine-${wbranch}_${wversion}~${wdist}${wtag}_i386.deb wine-installer
|
||||
mv wine-installer/opt/wine* ~/wine # install
|
||||
rm wine*.deb # clean up
|
||||
rm -rf wine-installer # clean up
|
||||
|
||||
@@ -83,7 +101,26 @@ sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
|
||||
# These packages are needed for running wine-staging on RPi 4 (Credits: chills340)
|
||||
# These packages are needed for running wine on a 64-bit RPiOS via multiarch
|
||||
karch=$(uname -m)
|
||||
if [ "$karch" = "aarch64" ] || [ "$karch" = "aarch64-linux-gnu" ] || [ "$karch" = "arm64" ] || [ "$karch" = "aarch64_be" ]; then
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update # enable multi-arch
|
||||
sudo apt-get install -y libasound2:armhf libc6:armhf libglib2.0-0:armhf libgphoto2-6:armhf libgphoto2-port12:armhf \
|
||||
libgstreamer-plugins-base1.0-0:armhf libgstreamer1.0-0:armhf libldap-2.4-2:armhf libopenal1:armhf libpcap0.8:armhf \
|
||||
libpulse0:armhf libsane1:armhf libudev1:armhf libusb-1.0-0:armhf libvkd3d1:armhf libx11-6:armhf libxext6:armhf \
|
||||
libasound2-plugins:armhf ocl-icd-libopencl1:armhf libncurses6:armhf libncurses5:armhf libcap2-bin:armhf libcups2:armhf \
|
||||
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
|
||||
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
|
||||
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
|
||||
libxrender1:armhf libxxf86vm1 libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel_7.1~bullseye-1_i386.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:armhf` to packages in dep list, then try installing them on Pi aarch64.
|
||||
fi
|
||||
|
||||
# These packages are needed for running wine-staging on RPiOS (Credits: chills340)
|
||||
sudo apt install libstb0 -y
|
||||
cd ~/Downloads
|
||||
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
|
||||
|
||||
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 58 KiB |
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 169 KiB |
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# create necessary directories
|
||||
mkdir -p ~/steam
|
||||
mkdir -p ~/steam/tmp
|
||||
cd ~/steam/tmp
|
||||
|
||||
# download latest deb and unpack
|
||||
wget https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb
|
||||
ar x steam.deb
|
||||
tar xf data.tar.xz
|
||||
|
||||
# remove deb archives, not needed anymore
|
||||
rm ./*.tar.xz ./steam.deb
|
||||
|
||||
# move deb contents to steam folder
|
||||
mv ./usr/* ../
|
||||
cd ../ && rm -rf ./tmp/
|
||||
|
||||
# create run script
|
||||
echo "#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
~/steam/bin/steam -noreactlogin steam://open/minigameslist $@" > steam
|
||||
|
||||
# make script executable and move
|
||||
chmod +x steam
|
||||
sudo mv steam /usr/local/bin/
|
||||
|
||||
# detect if we're running on 64 bit Debian
|
||||
MACHINE_TYPE=`uname -m`
|
||||
if [ ${MACHINE_TYPE} == 'aarch64' ] && [ -f '/etc/debian_version' ]; then
|
||||
echo "Detected 64 bit ARM Debian. Installing 32 bit libraries"
|
||||
sudo dpkg --add-architecture armhf # enable installation of armhf libraries
|
||||
sudo apt update # update package lists with the newly added arch
|
||||
sudo apt install libc6:armhf libncurses5:armhf libsdl2*:armhf libopenal*:armhf libpng*:armhf libfontconfig*:armhf libXcomposite*:armhf libbz2-dev:armhf libXtst*:armhf # install the libraries that Steam requires
|
||||
echo "Don't forget to compile/install Box64!"
|
||||
fi
|
||||
|
||||
echo "Script complete."
|
||||
+5
-20
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-arm-git}" -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-gameshell-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-gameshell-git}" -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroid-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-odroid-git}" -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pandora-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-pandora-git}" -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+5
-20
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pyra-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-pyra-git}" -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rpi-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -20,8 +20,7 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
build() {
|
||||
# Check for Pi version number
|
||||
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
|
||||
_piversion=4
|
||||
@@ -36,24 +35,11 @@ prepare() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-rpi-git}" -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-rk3399-git}" -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+5
-20
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-x86-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('i386')
|
||||
@@ -18,26 +18,11 @@ pkgver() {
|
||||
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)
|
||||
cmake -B build -S "${pkgname%-x86-git}" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
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
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ This will copy the PKGBUILD for your platform (where you type your platform name
|
||||
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
|
||||
|
||||
### 2. What platforms are currently supported.
|
||||
All specified in [COMPILE.md](../COMPILE.md).
|
||||
All specified in [COMPILE.md](../docs/COMPILE.md).
|
||||
|
||||
### 3. Any advantages with that sollution?
|
||||
This might give you some advantages like those:
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
#!/bin/sh
|
||||
systemctl restart systemd-binfmt
|
||||
if [ -d '/run/systemd/system' ]; then
|
||||
systemctl restart systemd-binfmt || :
|
||||
fi
|
||||
+277
-285
@@ -106,7 +106,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
alreadyChanged = 0
|
||||
csp = 0
|
||||
while csp < curSplt:
|
||||
if spltln[csp] == '\x00':
|
||||
if spltln[csp] == '\x01':
|
||||
alreadyChanged = 1
|
||||
curSplt = curSplt + 1
|
||||
else:
|
||||
@@ -119,7 +119,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
line = line + spltln[csp] + ">"
|
||||
alreadyChanged = 1
|
||||
csp = csp + 1
|
||||
if spltln[csp] == '\x00':
|
||||
if spltln[csp] == '\x01':
|
||||
alreadyChanged = 1
|
||||
curSplt = curSplt + 1
|
||||
csp = csp + 1
|
||||
@@ -134,7 +134,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
alreadyChanged = 1
|
||||
csp = csp + 1
|
||||
while csp < len(spltln):
|
||||
if spltln[csp] == '\x00':
|
||||
if spltln[csp] == '\x01':
|
||||
alreadyChanged = 1
|
||||
curSplt = curSplt + 1
|
||||
else:
|
||||
@@ -605,7 +605,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
printf_args = ""
|
||||
for idx, text in enumerate(instText):
|
||||
@@ -858,7 +858,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
printf_args = ""
|
||||
for idx, text in enumerate(instText):
|
||||
@@ -1156,7 +1156,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
printf_args = ""
|
||||
for idx, text in enumerate(instText):
|
||||
@@ -1456,7 +1456,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
# inside '{, '...'}'?
|
||||
hasOpened = False
|
||||
@@ -1675,308 +1675,300 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
# Now the files rebuilding part
|
||||
# File header and guard
|
||||
files_header = {
|
||||
"arm_printer.c": """
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
header = """
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "arm_printer.h"
|
||||
|
||||
// conditions
|
||||
#define cEQ (0b0000<<28)
|
||||
#define cNE (0b0001<<28)
|
||||
#define cCS (0b0010<<28)
|
||||
#define cCC (0b0011<<28)
|
||||
#define cMI (0b0100<<28)
|
||||
#define cPL (0b0101<<28)
|
||||
#define cVS (0b0110<<28)
|
||||
#define cVC (0b0111<<28)
|
||||
#define cHI (0b1000<<28)
|
||||
#define cLS (0b1001<<28)
|
||||
#define cGE (0b1010<<28)
|
||||
#define cLT (0b1011<<28)
|
||||
#define cGT (0b1100<<28)
|
||||
#define cLE (0b1101<<28)
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
static const char* conds[16] = {
|
||||
"EQ", "NE", "CS", "CC",
|
||||
"MI", "PL", "VS", "VC",
|
||||
"HI", "LS", "GE", "LT",
|
||||
"GT", "LE", "", "##"
|
||||
};
|
||||
|
||||
static const char* regname[16] = {
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9",
|
||||
"r10", "r11", "r12", "SP", "LR", "PC"
|
||||
};
|
||||
|
||||
// Single precision are V_:_
|
||||
// Double and quad precision are _:V_
|
||||
// So we always use _:V_ and invert the corresponding single-precision (cleaner? code)
|
||||
static const char* vecname[96] = {
|
||||
"S0", "S2", "S4", "S6", "S8", "S10", "S12", "S14",
|
||||
"S16", "S18", "S20", "S22", "S24", "S26", "S28", "S30",
|
||||
"S1", "S3", "S5", "S7", "S9", "S11", "S13", "S15",
|
||||
"S17", "S19", "S21", "S23", "S25", "S27", "S29", "S31",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
|
||||
"D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
|
||||
"D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
|
||||
"Q0", "!!!", "Q1", "!!!", "Q2", "!!!", "Q3", "!!!",
|
||||
"Q4", "!!!", "Q5", "!!!", "Q6", "!!!", "Q7", "!!!",
|
||||
"Q8", "!!!", "Q9", "!!!", "Q10", "!!!", "Q11", "!!!",
|
||||
"Q12", "!!!", "Q13", "!!!", "Q14", "!!!", "Q15", "!!!"
|
||||
};
|
||||
|
||||
static const char* dts[16] = {
|
||||
"S8", "S16", "S32", "S64",
|
||||
"U8", "U16", "U32", "U64",
|
||||
"I8", "I16", "I32", "I64",
|
||||
"F8", "F16", "F32", "F64"
|
||||
};
|
||||
|
||||
static const char* shift_type[4] = {
|
||||
"lsl ", "lsr ", "asr ", "ror "
|
||||
};
|
||||
|
||||
const char* print_shift(int shift, int comma) {
|
||||
static __thread char ret[20];
|
||||
ret[0] = '\\0';
|
||||
|
||||
#include "arm_printer.h"
|
||||
|
||||
// conditions
|
||||
#define cEQ (0b0000<<28)
|
||||
#define cNE (0b0001<<28)
|
||||
#define cCS (0b0010<<28)
|
||||
#define cCC (0b0011<<28)
|
||||
#define cMI (0b0100<<28)
|
||||
#define cPL (0b0101<<28)
|
||||
#define cVS (0b0110<<28)
|
||||
#define cVC (0b0111<<28)
|
||||
#define cHI (0b1000<<28)
|
||||
#define cLS (0b1001<<28)
|
||||
#define cGE (0b1010<<28)
|
||||
#define cLT (0b1011<<28)
|
||||
#define cGT (0b1100<<28)
|
||||
#define cLE (0b1101<<28)
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
static const char* conds[16] = {
|
||||
"EQ", "NE", "CS", "CC",
|
||||
"MI", "PL", "VS", "VC",
|
||||
"HI", "LS", "GE", "LT",
|
||||
"GT", "LE", "", "##"
|
||||
};
|
||||
|
||||
static const char* regname[16] = {
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9",
|
||||
"r10", "r11", "r12", "SP", "LR", "PC"
|
||||
};
|
||||
|
||||
// Single precision are V_:_
|
||||
// Double and quad precision are _:V_
|
||||
// So we always use _:V_ and invert the corresponding single-precision (cleaner? code)
|
||||
static const char* vecname[96] = {
|
||||
"S0", "S2", "S4", "S6", "S8", "S10", "S12", "S14",
|
||||
"S16", "S18", "S20", "S22", "S24", "S26", "S28", "S30",
|
||||
"S1", "S3", "S5", "S7", "S9", "S11", "S13", "S15",
|
||||
"S17", "S19", "S21", "S23", "S25", "S27", "S29", "S31",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
|
||||
"D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
|
||||
"D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
|
||||
"Q0", "!!!", "Q1", "!!!", "Q2", "!!!", "Q3", "!!!",
|
||||
"Q4", "!!!", "Q5", "!!!", "Q6", "!!!", "Q7", "!!!",
|
||||
"Q8", "!!!", "Q9", "!!!", "Q10", "!!!", "Q11", "!!!",
|
||||
"Q12", "!!!", "Q13", "!!!", "Q14", "!!!", "Q15", "!!!"
|
||||
};
|
||||
|
||||
static const char* dts[16] = {
|
||||
"S8", "S16", "S32", "S64",
|
||||
"U8", "U16", "U32", "U64",
|
||||
"I8", "I16", "I32", "I64",
|
||||
"F8", "F16", "F32", "F64"
|
||||
};
|
||||
|
||||
static const char* shift_type[4] = {
|
||||
"lsl ", "lsr ", "asr ", "ror "
|
||||
};
|
||||
|
||||
const char* print_shift(int shift, int comma) {
|
||||
static __thread char ret[20];
|
||||
ret[0] = '\\0';
|
||||
|
||||
int sh_op = (shift >> 1) & 3;
|
||||
if(shift & 1) {
|
||||
int rs = shift >> 4;
|
||||
sprintf(ret, "%s%s%s", (comma ? ", " : ""), shift_type[sh_op], regname[rs]);
|
||||
} else {
|
||||
uint8_t amount = shift >> 3;
|
||||
if (!amount) {
|
||||
switch (sh_op) {
|
||||
case 0b00:
|
||||
break;
|
||||
case 0b01:
|
||||
case 0b10:
|
||||
sprintf(ret, "%s%s#32", (comma ? ", " : ""), shift_type[sh_op]);
|
||||
break;
|
||||
case 0b11:
|
||||
sprintf(ret, "%srrx", (comma ? ", " : ""));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sprintf(ret, "%s%s#%u", (comma ? ", " : ""), shift_type[sh_op], amount);
|
||||
int sh_op = (shift >> 1) & 3;
|
||||
if(shift & 1) {
|
||||
int rs = shift >> 4;
|
||||
sprintf(ret, "%s%s%s", (comma ? ", " : ""), shift_type[sh_op], regname[rs]);
|
||||
} else {
|
||||
uint8_t amount = shift >> 3;
|
||||
if (!amount) {
|
||||
switch (sh_op) {
|
||||
case 0b00:
|
||||
break;
|
||||
case 0b01:
|
||||
case 0b10:
|
||||
sprintf(ret, "%s%s#32", (comma ? ", " : ""), shift_type[sh_op]);
|
||||
break;
|
||||
case 0b11:
|
||||
sprintf(ret, "%srrx", (comma ? ", " : ""));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sprintf(ret, "%s%s#%u", (comma ? ", " : ""), shift_type[sh_op], amount);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define print_modified_imm_ARM(imm12) (((imm12 & 0xFF) >> (2*(imm12 >> 8))) | ((imm12 & 0xFF) << (32 - 2*(imm12 >> 8))))
|
||||
|
||||
const char* print_register_list(int list, int size) {
|
||||
int last = -2;
|
||||
int cnt = 0;
|
||||
static __thread char ret[68];
|
||||
|
||||
#define print_modified_imm_ARM(imm12) (((imm12 & 0xFF) >> (2*(imm12 >> 8))) | ((imm12 & 0xFF) << (32 - 2*(imm12 >> 8))))
|
||||
ret[0] = '{';
|
||||
ret[1] = '\\0';
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (list & (1 << i)) {
|
||||
if (last >= 0) {
|
||||
++cnt;
|
||||
} else {
|
||||
if (last == -1)
|
||||
strcat(ret, ", ");
|
||||
strcat(ret, regname[i]);
|
||||
last = i;
|
||||
}
|
||||
} else {
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[i - 1]);
|
||||
}
|
||||
if (last != -2) last = -1;
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[size - 1]);
|
||||
}
|
||||
strcat(ret, "}");
|
||||
|
||||
const char* print_register_list(int list, int size) {
|
||||
int last = -2;
|
||||
int cnt = 0;
|
||||
static __thread char ret[68];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_prec) {
|
||||
static __thread char ret[68];
|
||||
|
||||
// Assume VFPSmallRegisterBank(), so no D16 and no S32 (and above)
|
||||
if (start + (double_prec + 1) * size > 32) {
|
||||
return "!!!";
|
||||
}
|
||||
if (size == 0) {
|
||||
return "!!!";
|
||||
}
|
||||
if (double_prec && (size % 2 == 1)) {
|
||||
strcpy(ret, "!! {");
|
||||
} else {
|
||||
ret[0] = '{';
|
||||
ret[1] = '\\0';
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (list & (1 << i)) {
|
||||
if (last >= 0) {
|
||||
++cnt;
|
||||
} else {
|
||||
if (last == -1)
|
||||
strcat(ret, ", ");
|
||||
strcat(ret, regname[i]);
|
||||
last = i;
|
||||
}
|
||||
} else {
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[i - 1]);
|
||||
}
|
||||
if (last != -2) last = -1;
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[size - 1]);
|
||||
}
|
||||
strcat(ret, "}");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_prec) {
|
||||
static __thread char ret[68];
|
||||
|
||||
// Assume VFPSmallRegisterBank(), so no D16 and no S32 (and above)
|
||||
if (start + (double_prec + 1) * size > 32) {
|
||||
return "!!!";
|
||||
}
|
||||
if (size == 0) {
|
||||
return "!!!";
|
||||
}
|
||||
if (double_prec && (size % 2 == 1)) {
|
||||
strcpy(ret, "!! {");
|
||||
} else {
|
||||
ret[0] = '{';
|
||||
ret[1] = '\\0';
|
||||
}
|
||||
|
||||
char regChr;
|
||||
if (double_prec) {
|
||||
regChr = 'D';
|
||||
size /= 2;
|
||||
} else {
|
||||
regChr = 'S';
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[6];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
}
|
||||
sprintf(tmp, "%c%d}", regChr, start + size - 1);
|
||||
char regChr;
|
||||
if (double_prec) {
|
||||
regChr = 'D';
|
||||
size /= 2;
|
||||
} else {
|
||||
regChr = 'S';
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[6];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
sprintf(tmp, "%c%d}", regChr, start + size - 1);
|
||||
strcat(ret, tmp);
|
||||
|
||||
static const char* _print_modified_imm_I64_bytes[2] = {"00", "FF"};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char* _print_modified_imm_I64_bytes[2] = {"00", "FF"};
|
||||
|
||||
const char* print_modified_imm_NEON(int op_cmode, int imm) {
|
||||
static __thread char ret[34] = "???\\0-"; // [dt: 4][imm: 30]
|
||||
|
||||
const char* print_modified_imm_NEON(int op_cmode, int imm) {
|
||||
static __thread char ret[34] = "???\\0-"; // [dt: 4][imm: 30]
|
||||
|
||||
strcpy(&ret[4], "UNPREDICTABLE");
|
||||
|
||||
switch (op_cmode) {
|
||||
case 0b00000: // VMOV.I32
|
||||
case 0b00001: // VORR.I32
|
||||
case 0b10000: // VMVN.I32
|
||||
case 0b10001: // VBIC.I32
|
||||
strcpy(&ret[4], "UNPREDICTABLE");
|
||||
|
||||
switch (op_cmode) {
|
||||
case 0b00000: // VMOV.I32
|
||||
case 0b00001: // VORR.I32
|
||||
case 0b10000: // VMVN.I32
|
||||
case 0b10001: // VBIC.I32
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b00010: // VMOV.I32
|
||||
case 0b00011: // VORR.I32
|
||||
case 0b10010: // VMVN.I32
|
||||
case 0b10011: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b00010: // VMOV.I32
|
||||
case 0b00011: // VORR.I32
|
||||
case 0b10010: // VMVN.I32
|
||||
case 0b10011: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
break;
|
||||
case 0b00100: // VMOV.I32
|
||||
case 0b00101: // VORR.I32
|
||||
case 0b10100: // VMVN.I32
|
||||
case 0b10101: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X0000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b00110: // VMOV.I32
|
||||
case 0b00111: // VORR.I32
|
||||
case 0b10110: // VMVN.I32
|
||||
case 0b10111: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X000000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01000: // VMOV.I16
|
||||
case 0b01001: // VORR.I16
|
||||
case 0b11000: // VMVN.I16
|
||||
case 0b11001: // VBIC.I16
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01010: // VMOV.I16
|
||||
case 0b01011: // VORR.I16
|
||||
case 0b11010: // VMVN.I16
|
||||
case 0b11011: // VBIC.I16
|
||||
if (imm) {
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01100: // VMOV.I32
|
||||
case 0b11100: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01101: // VMOV.I32
|
||||
case 0b11101: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFFFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01110: // VMOV.I8
|
||||
strcpy(ret, "I8");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01111: // VMOV.F32
|
||||
strcpy(ret, "F32");
|
||||
sprintf(&ret[4], "%e", (imm & 0x80 ? -1 : 1) * (1 << (((imm >> 4) & 0x7) ^ 0b100)) * (float) (16 + (imm & 0xF)) / 128.);
|
||||
break;
|
||||
case 0b11110: // VMOV.I64
|
||||
{
|
||||
strcpy(ret, "I64");
|
||||
sprintf(&ret[4], "#0x%s%s%s%s%s%s%s%s",
|
||||
_print_modified_imm_I64_bytes[(imm >> 7) & 1], _print_modified_imm_I64_bytes[(imm >> 6) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 5) & 1], _print_modified_imm_I64_bytes[(imm >> 4) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 3) & 1], _print_modified_imm_I64_bytes[(imm >> 2) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 1) & 1], _print_modified_imm_I64_bytes[(imm >> 0) & 1]);
|
||||
}
|
||||
break;
|
||||
case 0b11111: // V???.-
|
||||
default:
|
||||
strcpy(ret, "-");
|
||||
strcpy(&ret[4], "UNDEFINED");
|
||||
break;
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
|
||||
return ret;
|
||||
break;
|
||||
case 0b00100: // VMOV.I32
|
||||
case 0b00101: // VORR.I32
|
||||
case 0b10100: // VMVN.I32
|
||||
case 0b10101: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X0000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b00110: // VMOV.I32
|
||||
case 0b00111: // VORR.I32
|
||||
case 0b10110: // VMVN.I32
|
||||
case 0b10111: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X000000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01000: // VMOV.I16
|
||||
case 0b01001: // VORR.I16
|
||||
case 0b11000: // VMVN.I16
|
||||
case 0b11001: // VBIC.I16
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01010: // VMOV.I16
|
||||
case 0b01011: // VORR.I16
|
||||
case 0b11010: // VMVN.I16
|
||||
case 0b11011: // VBIC.I16
|
||||
if (imm) {
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01100: // VMOV.I32
|
||||
case 0b11100: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01101: // VMOV.I32
|
||||
case 0b11101: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFFFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01110: // VMOV.I8
|
||||
strcpy(ret, "I8");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01111: // VMOV.F32
|
||||
strcpy(ret, "F32");
|
||||
sprintf(&ret[4], "%e", (imm & 0x80 ? -1 : 1) * (1 << (((imm >> 4) & 0x7) ^ 0b100)) * (float) (16 + (imm & 0xF)) / 128.);
|
||||
break;
|
||||
case 0b11110: // VMOV.I64
|
||||
{
|
||||
strcpy(ret, "I64");
|
||||
sprintf(&ret[4], "#0x%s%s%s%s%s%s%s%s",
|
||||
_print_modified_imm_I64_bytes[(imm >> 7) & 1], _print_modified_imm_I64_bytes[(imm >> 6) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 5) & 1], _print_modified_imm_I64_bytes[(imm >> 4) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 3) & 1], _print_modified_imm_I64_bytes[(imm >> 2) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 1) & 1], _print_modified_imm_I64_bytes[(imm >> 0) & 1]);
|
||||
}
|
||||
break;
|
||||
case 0b11111: // V???.-
|
||||
default:
|
||||
strcpy(ret, "-");
|
||||
strcpy(&ret[4], "UNDEFINED");
|
||||
break;
|
||||
}
|
||||
|
||||
const char* arm_print(uint32_t opcode) {
|
||||
static __thread char ret[100];
|
||||
memset(ret, 0, sizeof(ret));
|
||||
|
||||
"""
|
||||
return ret;
|
||||
}
|
||||
files_guard = {
|
||||
"arm_printer.c": """
|
||||
{
|
||||
strcpy(ret, "???");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* arm_print(uint32_t opcode) {
|
||||
static __thread char ret[100];
|
||||
memset(ret, 0, sizeof(ret));
|
||||
|
||||
"""
|
||||
footer = """
|
||||
{
|
||||
strcpy(ret, "???");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
"""
|
||||
banner = "/*******************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
" * File automatically generated by rebuild_printer.py (v" + ver + ") *\n" \
|
||||
" *******************************************************" + ('*'*len(ver)) + "***/\n"
|
||||
trim = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
|
||||
# Yes, the for loops are inverted. This is because both dicts should have the same keys.
|
||||
for fhdr in files_guard:
|
||||
files_header[fhdr] = banner + trim(files_header[fhdr])
|
||||
for fhdr in files_header:
|
||||
files_guard[fhdr] = trim(files_guard[fhdr])
|
||||
trim = lambda string: '\n'.join(line[1:] for line in string.splitlines())[1:]
|
||||
header = banner + trim(header)
|
||||
footer = trim(footer)
|
||||
|
||||
for f in files_header:
|
||||
with open(os.path.join(root, "src", "dynarec", f), 'w') as file:
|
||||
file.write(files_header[f])
|
||||
file.write(output)
|
||||
file.write(files_guard[f])
|
||||
with open(os.path.join(root, "src", "dynarec", "arm_printer.c"), 'w') as file:
|
||||
file.write(header)
|
||||
file.write(output)
|
||||
file.write(footer)
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "dynarec", "last_run.txt"), 'w') as file:
|
||||
file.write('\n'.join(insts))
|
||||
@@ -1988,6 +1980,6 @@ if __name__ == '__main__':
|
||||
for i, v in enumerate(sys.argv):
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
if main(sys.argv[1], "1.2.0.05") != 0:
|
||||
if main(sys.argv[1], "1.2.0.06") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
+20
-15
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -166,8 +166,8 @@ U = TypeVar('U')
|
||||
Filename = str
|
||||
|
||||
class CustOrderedDict(Generic[T, U], Iterable[T]):
|
||||
__keys__: List[T]
|
||||
__actdict__: Dict[T, U]
|
||||
__keys__: List[T] = []
|
||||
__actdict__: Dict[T, U] = {}
|
||||
|
||||
def __init__(self, src: Optional[Dict[T, U]] = None) -> None:
|
||||
if src is None:
|
||||
@@ -195,7 +195,7 @@ class CustOrderedDictList(CustOrderedDict[T, List[U]]):
|
||||
return super().__getitem__(k)
|
||||
|
||||
class FirstArgumentSingletonMeta(Generic[T], type):
|
||||
_singletons: Dict[T, Type['FirstArgumentSingletonMeta']]
|
||||
_singletons: Dict[T, Type['FirstArgumentSingletonMeta']] = {}
|
||||
|
||||
@classmethod
|
||||
def __prepare__(metacls, __name: str, __bases: Tuple[type, ...], **kwds: Any) -> Dict[str, Any]:
|
||||
@@ -227,10 +227,9 @@ class FileSpec:
|
||||
values: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M', 's']
|
||||
rvalues: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M', 's']
|
||||
validrepl: Sequence[str] = ['c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M', 's']
|
||||
structs: CustOrderedDict[str, Struct]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.structs = CustOrderedDict()
|
||||
self.structs: CustOrderedDict[str, FileSpec.Struct] = CustOrderedDict()
|
||||
|
||||
self.typedefs: CustOrderedDictList[_BareFunctionType, Function] = CustOrderedDictList()
|
||||
self.structsuses: List[FunctionType] = []
|
||||
@@ -441,8 +440,8 @@ class Function:
|
||||
DefineType = NewType('DefineType', str)
|
||||
@final
|
||||
class Define:
|
||||
name: DefineType
|
||||
inverted_: bool
|
||||
name: DefineType = DefineType("")
|
||||
inverted_: bool = False
|
||||
|
||||
defines: List[DefineType] = []
|
||||
|
||||
@@ -480,7 +479,7 @@ class Define:
|
||||
return isinstance(o, Define) and (self.name == o.name) and (self.inverted_ == o.inverted_)
|
||||
@final
|
||||
class Clause:
|
||||
defines: List[Define]
|
||||
defines: List[Define] = []
|
||||
|
||||
def __init__(self, defines: Union[List[Define], str] = []) -> None:
|
||||
if isinstance(defines, str):
|
||||
@@ -528,7 +527,7 @@ class Clauses:
|
||||
Represent a list of clauses, aka a list of or-ed together and-ed "defined()"
|
||||
conditions
|
||||
"""
|
||||
clauses: List[Clause]
|
||||
clauses: List[Clause] = []
|
||||
|
||||
def __init__(self, clauses: Union[List[Clause], str] = []) -> None:
|
||||
if isinstance(clauses, str):
|
||||
@@ -748,9 +747,15 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("smpeg", "smpeg2") \
|
||||
or match("udev0", "udev1") \
|
||||
or match("gstinterfaces010","gstvideo")\
|
||||
or match("gstinterfaces010","gstaudio")\
|
||||
or match("gstreamer010","gstreamer") \
|
||||
or match("appindicator","appindicator3")\
|
||||
\
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "ldlinux") \
|
||||
or match("libc", "ldlinux") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("tcmallocminimal","tbbmallocproxy") \
|
||||
:
|
||||
# libc and ldlinux have some "__libc_" data symbols in common... TODO check if ok
|
||||
continue
|
||||
@@ -1053,8 +1058,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
memcpy(value+4, v->data, 2*sizeof(double));
|
||||
{rbr}
|
||||
|
||||
void* VulkanFromx86(void* src, void** save);
|
||||
void VulkanTox86(void* src, void* save);
|
||||
void* VulkanFromx86(void* src);
|
||||
void VulkanTox86(void* src);
|
||||
|
||||
#define ST0val ST0.d
|
||||
|
||||
@@ -1254,7 +1259,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
delta = 4
|
||||
for c in args:
|
||||
if c == 'P':
|
||||
f.write("void* save{d} = NULL; void *arg{d} = VulkanFromx86(*(void**)(R_ESP + {d}), &save{d}); ".format(d=delta))
|
||||
f.write("void *arg{d} = VulkanFromx86(*(void**)(R_ESP + {d})); ".format(d=delta))
|
||||
if c == 'G':
|
||||
f.write("my_GValue_t arg{d}; alignGValue(&arg{d}, *(void**)(R_ESP + {d})); ".format(d=delta))
|
||||
delta = delta + deltas[FileSpec.values.index(c)]
|
||||
@@ -1262,7 +1267,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
delta = 4
|
||||
for c in args:
|
||||
if c == 'P':
|
||||
f.write("VulkanTox86(arg{d}, save{d}); ".format(d=delta))
|
||||
f.write("VulkanTox86(arg{d}); ".format(d=delta))
|
||||
if c == 'G':
|
||||
f.write("unalignGValue(*(void**)(R_ESP + {d}), &arg{d}); ".format(d=delta))
|
||||
delta = delta + deltas[FileSpec.values.index(c)]
|
||||
|
||||
@@ -52,5 +52,10 @@ if( TEST_RESULT )
|
||||
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
|
||||
endif( TEST_RESULT )
|
||||
|
||||
# remove the temporary files if they exist
|
||||
if( EXISTS ${TEST_OUTPUT} )
|
||||
file(REMOVE "${TEST_OUTPUT}")
|
||||
endif()
|
||||
|
||||
# everything went fine...
|
||||
message( "Passed: The output of ${TEST_PROGRAM} matches ${TEST_REFERENCE}" )
|
||||
+37
-18
@@ -74,8 +74,8 @@ void free_tlsdatasize(void* p)
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
free(data->tlsdata);
|
||||
free(p);
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
}
|
||||
|
||||
int unlockMutex()
|
||||
@@ -161,8 +161,13 @@ box86context_t *NewBox86Context(int argc)
|
||||
}
|
||||
#endif
|
||||
// init and put default values
|
||||
box86context_t *context = my_context = (box86context_t*)calloc(1, sizeof(box86context_t));
|
||||
box86context_t *context = my_context = (box86context_t*)box_calloc(1, sizeof(box86context_t));
|
||||
|
||||
if(cycle_log)
|
||||
for(int i=0; i<CYCLE_LOG; ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
#ifdef BUILD_LIB
|
||||
context->deferedInit = 0;
|
||||
#else
|
||||
@@ -176,6 +181,8 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
context->globaldefver = NewDefaultVersion();
|
||||
context->weakdefver = NewDefaultVersion();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, iFEv, x86Syscall, 0, NULL);
|
||||
addAlternate((void*)0xffffe400, (void*)context->vsyscall);
|
||||
@@ -187,7 +194,7 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
context->argv = (char**)box_calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
@@ -229,7 +236,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
box_free(ctx->elfs);
|
||||
|
||||
FreeFTSMap(ctx);
|
||||
|
||||
@@ -243,16 +250,16 @@ void FreeBox86Context(box86context_t** context)
|
||||
DeleteX86Trace(ctx);
|
||||
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
box_free(ctx->deferedInitList);
|
||||
|
||||
free(ctx->argv);
|
||||
/*box_free(ctx->argv);*/
|
||||
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
/*for (int i=0; i<ctx->envc; ++i)
|
||||
box_free(ctx->envv[i]);
|
||||
box_free(ctx->envv);*/
|
||||
|
||||
if(ctx->atfork_sz) {
|
||||
free(ctx->atforks);
|
||||
box_free(ctx->atforks);
|
||||
ctx->atforks = NULL;
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
@@ -273,16 +280,20 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
// free(ctx->stack); // don't free the stack, it's owned by main emu!
|
||||
// box_free(ctx->stack); // don't free the stack, it's owned by main emu!
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box86path);
|
||||
box_free(ctx->fullpath);
|
||||
box_free(ctx->box86path);
|
||||
box_free(ctx->bashpath);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if(ctx->stack_clone)
|
||||
box_free(ctx->stack_clone);
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
@@ -291,7 +302,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
box_free(ctx->tlsdata);
|
||||
|
||||
for(int i=0; i<3; ++i) {
|
||||
if(ctx->segtls[i].present) {
|
||||
@@ -304,6 +315,8 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
FreeDefaultVersion(&ctx->globaldefver);
|
||||
FreeDefaultVersion(&ctx->weakdefver);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
@@ -319,7 +332,13 @@ void FreeBox86Context(box86context_t** context)
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
|
||||
free(ctx);
|
||||
if(cycle_log)
|
||||
for(int i=0; i<CYCLE_LOG; ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
|
||||
box_free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
@@ -327,7 +346,7 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
@@ -338,7 +357,7 @@ 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);
|
||||
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
|
||||
// clean GS segment for current emu
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 2
|
||||
#define BOX86_REVISION 4
|
||||
#define BOX86_REVISION 7
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
+489
-112
@@ -25,36 +25,54 @@
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
#include "dynarec/dynarec_next.h"
|
||||
#include "khash.h"
|
||||
|
||||
#define USE_MMAP
|
||||
//#define USE_MMAP_MORE
|
||||
|
||||
// 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];
|
||||
// lock addresses
|
||||
KHASH_SET_INIT_INT(lockaddress)
|
||||
static kh_lockaddress_t *lockaddress = NULL;
|
||||
#endif
|
||||
#define MEMPROT_SHIFT 12
|
||||
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
|
||||
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
typedef struct memprot_s
|
||||
{
|
||||
uint8_t prot;
|
||||
uint8_t hot;
|
||||
} memprot_t;
|
||||
static memprot_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
static int inited = 0;
|
||||
|
||||
typedef struct mapmem_s {
|
||||
uintptr_t begin, end;
|
||||
struct mapmem_s *next;
|
||||
} mapmem_t;
|
||||
|
||||
static mapmem_t *mapmem = NULL;
|
||||
|
||||
typedef struct blocklist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
size_t size;
|
||||
void* first;
|
||||
} 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
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static int c_blocks = 0; // capacity of blocks for custom malloc
|
||||
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
|
||||
|
||||
typedef union mark_s {
|
||||
struct {
|
||||
@@ -98,6 +116,23 @@ static void* getFirstBlock(void* block, size_t maxsize, size_t* size, void* star
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* getNextFreeBlock(void* block)
|
||||
{
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
while (m->next.fill) {
|
||||
m = NEXT_BLOCK(m);
|
||||
};
|
||||
return m;
|
||||
}
|
||||
static void* getPrevFreeBlock(void* block)
|
||||
{
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
do {
|
||||
m = PREV_BLOCK(m);
|
||||
} while (m->next.fill);
|
||||
return m;
|
||||
}
|
||||
|
||||
static size_t getMaxFreeBlock(void* block, size_t block_size, void* start)
|
||||
{
|
||||
// get start of block
|
||||
@@ -228,19 +263,37 @@ static size_t sizeBlock(void* sub)
|
||||
return s->next.size;
|
||||
}
|
||||
|
||||
#define THRESHOLD (128-2*sizeof(blockmark_t))
|
||||
|
||||
static size_t roundSize(size_t size)
|
||||
{
|
||||
if(!size)
|
||||
return size;
|
||||
size = (size+7)&~7LL; // 8 bytes align in size
|
||||
|
||||
if(size<THRESHOLD)
|
||||
size = THRESHOLD;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void* customMalloc(size_t size)
|
||||
{
|
||||
size = roundSize(size);
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
size_t fullsize = size+2*sizeof(blockmark_t);
|
||||
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);
|
||||
sub = getFirstBlock(p_blocks[i].block, size, &rsize, p_blocks[i].first);
|
||||
if(sub) {
|
||||
if(rsize-size<THRESHOLD)
|
||||
size = rsize;
|
||||
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);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
@@ -248,17 +301,20 @@ void* customMalloc(size_t size)
|
||||
}
|
||||
// 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
|
||||
if(n_blocks>c_blocks) {
|
||||
c_blocks += 4;
|
||||
p_blocks = (blocklist_t*)box_realloc(p_blocks, c_blocks*sizeof(blocklist_t));
|
||||
}
|
||||
size_t allocsize = (fullsize>MMAPSIZE)?fullsize:MMAPSIZE;
|
||||
#ifdef USE_MMAP_MORE
|
||||
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
memset(p, 0, allocsize);
|
||||
setProtection((uintptr_t)p, allocsize, PROT_READ|PROT_WRITE);
|
||||
#else
|
||||
void* p = calloc(1, allocsize);
|
||||
void* p = box_calloc(1, allocsize);
|
||||
#endif
|
||||
p_blocks[i].block = p;
|
||||
p_blocks[i].first = p;
|
||||
p_blocks[i].size = allocsize;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
@@ -277,7 +333,7 @@ void* customMalloc(size_t size)
|
||||
}
|
||||
void* customCalloc(size_t n, size_t size)
|
||||
{
|
||||
size_t newsize = n*size;
|
||||
size_t newsize = roundSize(n*size);
|
||||
void* ret = customMalloc(newsize);
|
||||
memset(ret, 0, newsize);
|
||||
return ret;
|
||||
@@ -286,6 +342,7 @@ void* customRealloc(void* p, size_t size)
|
||||
{
|
||||
if(!p)
|
||||
return customMalloc(size);
|
||||
size = roundSize(size);
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
@@ -293,7 +350,9 @@ void* customRealloc(void* p, size_t size)
|
||||
&& (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);
|
||||
if(sub<p_blocks[i].first && p+size<p_blocks[i].first)
|
||||
p_blocks[i].first = getNextFreeBlock(sub);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return p;
|
||||
}
|
||||
@@ -319,7 +378,10 @@ void customFree(void* p)
|
||||
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));
|
||||
void* n = NEXT_BLOCK((blockmark_t*)sub);
|
||||
size_t newfree = freeBlock(p_blocks[i].block, sub, NULL);
|
||||
if(sub<=p_blocks[i].first)
|
||||
p_blocks[i].first = getPrevFreeBlock(n);
|
||||
if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree;
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return;
|
||||
@@ -346,35 +408,40 @@ 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);
|
||||
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t)) {
|
||||
if(!arm_lock_xchg(&mmaplist[i].locked, 1)) {
|
||||
size_t 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);
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
return ret;
|
||||
} else {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info (requested size=%d)?\n", i, size);
|
||||
if(box86_log >= LOG_DEBUG)
|
||||
printBlock(mmaplist[i].block, mmaplist[i].first);
|
||||
// reset block meta info
|
||||
mmaplist[i].first = getFirstBlock(mmaplist[i].block, 1, &rsize, NULL);
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, NULL);
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,7 +454,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
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));
|
||||
mmaplist = (mmaplist_t*)box_realloc(mmaplist, mmapcap*sizeof(mmaplist_t));
|
||||
}
|
||||
#ifndef USE_MMAP
|
||||
void *p = NULL;
|
||||
@@ -407,10 +474,10 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
#endif
|
||||
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
|
||||
mmaplist[i].locked = 1;
|
||||
arm_lock_store(&mmaplist[i].locked, 1);
|
||||
mmaplist[i].block = p;
|
||||
mmaplist[i].size = MMAPSIZE;
|
||||
mmaplist[i].helper = (uint8_t*)calloc(1, MMAPSIZE);
|
||||
mmaplist[i].helper = (uint8_t*)box_calloc(1, MMAPSIZE);
|
||||
mmaplist[i].first = p;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
@@ -432,7 +499,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
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;
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
return sub;
|
||||
}
|
||||
|
||||
@@ -443,6 +510,12 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if ((addr>(uintptr_t)mmaplist[i].block)
|
||||
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
|
||||
// wait the map is free
|
||||
int cnt = 100;
|
||||
while(my_context && cnt && arm_lock_store_xchg(&mmaplist[i].locked, (void*)1)) {
|
||||
--cnt;
|
||||
sched_yield();
|
||||
}
|
||||
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;
|
||||
@@ -453,10 +526,7 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
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;
|
||||
}
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -531,7 +601,7 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
|
||||
return;
|
||||
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
|
||||
#ifndef USE_MMAP
|
||||
free((void*)addr);
|
||||
box_free((void*)addr);
|
||||
#else
|
||||
munmap((void*)addr, size);
|
||||
#endif
|
||||
@@ -546,9 +616,23 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
|
||||
ActuallyFreeDynarecMap(db, addr, size);
|
||||
}
|
||||
|
||||
dynablocklist_t* getDB(uintptr_t idx)
|
||||
dynablock_t* getDB(uintptr_t addr)
|
||||
{
|
||||
return dynmap[idx];
|
||||
if(isJumpTableDefault((void*)addr))
|
||||
return NULL;
|
||||
uintptr_t ret = getJumpAddress(addr);
|
||||
return *(dynablock_t**)(ret-sizeof(void*));
|
||||
}
|
||||
|
||||
uintptr_t getDefaultSize(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default)
|
||||
return (addr&~((1<<JMPTABL_SHIFT)-1)|0xffff)-addr + 1;
|
||||
uintptr_t idx0 = addr&0xffff;
|
||||
while(box86_jumptable[idx][idx0]==(uintptr_t)arm_next)
|
||||
++idx0;
|
||||
return idx0 - (addr&0xffff);
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
@@ -556,49 +640,41 @@ dynablocklist_t* getDB(uintptr_t idx)
|
||||
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);
|
||||
}
|
||||
}
|
||||
// do nothing, dynablock are allowed based on memory protection flags
|
||||
}
|
||||
|
||||
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) {
|
||||
uintptr_t start_addr = my_context?((addr<my_context->max_db_size)?0:(addr-my_context->max_db_size)):addr;
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?"destroy":"mark");
|
||||
for (uintptr_t i=start_addr; i<addr+size; ++i) {
|
||||
dynablock_t* db = getDB(i);
|
||||
if(db) {
|
||||
if(destroy)
|
||||
FreeRangeDynablock(dblist, addr, size);
|
||||
FreeRangeDynablock(db, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(dblist, addr, size);
|
||||
MarkRangeDynablock(db, addr, size);
|
||||
} else {
|
||||
uintptr_t next = getDefaultSize(i);
|
||||
if(next)
|
||||
i+=next-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM
|
||||
void arm_next(void);
|
||||
#endif
|
||||
|
||||
void addJumpTableIfDefault(void* addr, void* jmp)
|
||||
int 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));
|
||||
uintptr_t* tbl = (uintptr_t*)box_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);
|
||||
box_free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
|
||||
return (arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next)==jmp)?1:0;
|
||||
}
|
||||
void setJumpTableDefault(void* addr)
|
||||
{
|
||||
@@ -609,6 +685,28 @@ void setJumpTableDefault(void* addr)
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
box86_jumptable[idx][off] = (uintptr_t)arm_next;
|
||||
}
|
||||
void setJumpTableDefaultRef(void* addr, void* jmp)
|
||||
{
|
||||
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);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], arm_next, jmp);
|
||||
}
|
||||
void setJumpTableIfRef(void* addr, void* jmp, void* ref)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)box_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)
|
||||
box_free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, ref);
|
||||
}
|
||||
int isJumpTableDefault(void* addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
@@ -627,16 +725,30 @@ 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));
|
||||
uintptr_t* tbl = (uintptr_t*)box_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);
|
||||
box_free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
return (uintptr_t)&box86_jumptable[idx][off];
|
||||
}
|
||||
|
||||
uintptr_t getJumpAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)box_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)
|
||||
box_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)
|
||||
@@ -645,70 +757,311 @@ void protectDB(uintptr_t addr, uintptr_t size)
|
||||
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);
|
||||
}
|
||||
uint32_t prot = memprot[i].prot;
|
||||
uint32_t dyn = prot&PROT_CUSTOM;
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute
|
||||
if(prot&PROT_WRITE) {
|
||||
memprot[i].prot = prot|PROT_DYNAREC;
|
||||
if(!dyn) mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
} else
|
||||
memprot[i].prot = prot|PROT_DYNAREC_R;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size, int mark)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p (mark=%d)\n", (void*)addr, (void*)(addr+size-1), mark);
|
||||
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];
|
||||
uint32_t prot = memprot[i].prot;
|
||||
if(prot&PROT_DYNAREC) {
|
||||
memprot[i] = prot&~PROT_DYNAREC;
|
||||
memprot[i].prot = prot&~PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
}
|
||||
if(mark)
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
} else if(prot&PROT_DYNAREC_R)
|
||||
memprot[i].prot = prot&~(PROT_CUSTOM);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOTPAGE_STEP 16
|
||||
int IsInHotPage(uintptr_t addr) {
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
if(!memprot[idx].hot)
|
||||
return 0;
|
||||
// decrement hot
|
||||
arm_lock_dec_b(&memprot[idx].hot);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AreaInHotPage(uintptr_t start, uintptr_t end_) {
|
||||
//dynarec_log(LOG_DEBUG, "AreaInHotPage %p -> %p => ", (void*)start, (void*)end_);
|
||||
uintptr_t idx = (start>>MEMPROT_SHIFT);
|
||||
uintptr_t end = (end_>>MEMPROT_SHIFT);
|
||||
if(end<idx) { // memory addresses higher than 48bits are not tracked
|
||||
//dynarec_log(LOG_DEBUG, "00\n");
|
||||
return 0;
|
||||
}
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(memprot[i].hot) {
|
||||
// decrement hot
|
||||
arm_lock_dec_b(&memprot[i].hot);
|
||||
//dynarec_log(LOG_DEBUG, "1\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
//dynarec_log(LOG_DEBUG, "0\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void AddHotPage(uintptr_t addr) {
|
||||
int idx = (addr>>MEMPROT_SHIFT);
|
||||
arm_lock_store_b(&memprot[idx].hot, HOTPAGE_STEP);
|
||||
}
|
||||
#endif
|
||||
|
||||
void printMapMem()
|
||||
{
|
||||
mapmem_t* m = mapmem;
|
||||
while(m) {
|
||||
printf_log(LOG_NONE, " %p-%p\n", (void*)m->begin, (void*)m->end);
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
void addMapMem(uintptr_t begin, uintptr_t end)
|
||||
{
|
||||
begin &=~0xfff;
|
||||
end = (end&~0xfff)+0xfff; // full page
|
||||
// sanitize values
|
||||
if(end<0x10000) return;
|
||||
if(!begin) begin = 0x10000;
|
||||
// find attach point (cannot be the 1st one by construction)
|
||||
mapmem_t* m = mapmem;
|
||||
while(m->next && begin>m->next->begin) {
|
||||
m = m->next;
|
||||
}
|
||||
// attach at the end of m
|
||||
mapmem_t* newm;
|
||||
if(m->end>=begin-1) {
|
||||
if(end<=m->end)
|
||||
return; // zone completly inside current block, nothing to do
|
||||
m->end = end; // enlarge block
|
||||
newm = m;
|
||||
} else {
|
||||
// create a new block
|
||||
newm = (mapmem_t*)box_calloc(1, sizeof(mapmem_t));
|
||||
newm->next = m->next;
|
||||
newm->begin = begin;
|
||||
newm->end = end;
|
||||
m->next = newm;
|
||||
}
|
||||
while(newm && newm->next && (newm->next->begin-1)<=newm->end) {
|
||||
// fuse with next
|
||||
if(newm->next->end>newm->end)
|
||||
newm->end = newm->next->end;
|
||||
mapmem_t* tmp = newm->next;
|
||||
newm->next = tmp->next;
|
||||
box_free(tmp);
|
||||
}
|
||||
// all done!
|
||||
}
|
||||
void removeMapMem(uintptr_t begin, uintptr_t end)
|
||||
{
|
||||
begin &=~0xfff;
|
||||
end = (end&~0xfff)+0xfff; // full page
|
||||
// sanitize values
|
||||
if(end<0x10000) return;
|
||||
if(!begin) begin = 0x10000;
|
||||
mapmem_t* m = mapmem, *prev = NULL;
|
||||
while(m) {
|
||||
// check if block is beyond the zone to free
|
||||
if(m->begin > end)
|
||||
return;
|
||||
// check if the block is completly inside the zone to free
|
||||
if(m->begin>=begin && m->end<=end) {
|
||||
// just free the block
|
||||
mapmem_t *tmp = m;
|
||||
if(prev) {
|
||||
prev->next = m->next;
|
||||
m = prev;
|
||||
} else {
|
||||
mapmem = m->next; // change attach, but should never happens
|
||||
m = mapmem;
|
||||
prev = NULL;
|
||||
}
|
||||
box_free(tmp);
|
||||
} else if(begin>m->begin && end<m->end) { // the zone is totaly inside the block => split it!
|
||||
mapmem_t* newm = (mapmem_t*)box_calloc(1, sizeof(mapmem_t)); // create a new "next"
|
||||
newm->end = m->end;
|
||||
m->end = begin - 1;
|
||||
newm->begin = end + 1;
|
||||
newm->next = m->next;
|
||||
m->next = newm;
|
||||
// nothing more to free
|
||||
return;
|
||||
} else if(begin>m->begin && begin<m->end) { // free the tail of the block
|
||||
m->end = begin - 1;
|
||||
} else if(end>m->begin && end<m->end) { // free the head of the block
|
||||
m->begin = end + 1;
|
||||
}
|
||||
prev = m;
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
//dynarec_log(LOG_DEBUG, "updateProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
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
|
||||
uint32_t dyn=(memprot[i].prot&(PROT_DYNAREC|PROT_DYNAREC_R));
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i] = prot|dyn;
|
||||
} else if(dyn && !(prot&PROT_WRITE)) {
|
||||
dyn = PROT_DYNAREC_R;
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
arm_lock_store_b(&memprot[i].prot, prot|dyn);
|
||||
#else
|
||||
memprot[i].prot = prot|dyn;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
//dynarec_log(LOG_DEBUG, "forceProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
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;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_CUSTOM);
|
||||
#ifdef DYNAREC
|
||||
arm_lock_store_b(&memprot[i].prot, prot);
|
||||
#else
|
||||
memprot[i].prot=prot;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
//dynarec_log(LOG_DEBUG, "setProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
if(!mapmem)
|
||||
return;
|
||||
addMapMem(addr, addr+size-1);
|
||||
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;
|
||||
#ifdef DYNAREC
|
||||
arm_lock_store_b(&memprot[i].prot, prot);
|
||||
#else
|
||||
memprot[i].prot=prot;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void freeProtection(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
removeMapMem(addr, addr+size-1);
|
||||
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 = 0;
|
||||
memprot[i].hot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uint32_t ret = memprot[idx];
|
||||
uint32_t ret = memprot[idx].prot;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void allocProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
addMapMem(addr, addr+size-1);
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!memprot[i].prot)
|
||||
memprot[i].prot = prot;
|
||||
}
|
||||
}
|
||||
|
||||
void loadProtectionFromMap()
|
||||
{
|
||||
if(box86_mapclean)
|
||||
return;
|
||||
char buf[500];
|
||||
FILE *f = fopen("/proc/self/maps", "r");
|
||||
uintptr_t current = 0x0;
|
||||
if(box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG) {printf_log(LOG_NONE, "Refresh mmap allocated block start =============\n");}
|
||||
if(!f)
|
||||
return;
|
||||
while(!feof(f)) {
|
||||
char* ret = fgets(buf, sizeof(buf), f);
|
||||
(void)ret;
|
||||
char r, w, x;
|
||||
uintptr_t s, e;
|
||||
if(box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG) {printf_log(LOG_NONE, "\t%s", buf);}
|
||||
if(sscanf(buf, "%lx-%lx %c%c%c", &s, &e, &r, &w, &x)==5) {
|
||||
if(current<s) {
|
||||
removeMapMem(current, s-1);
|
||||
current = e;
|
||||
}
|
||||
int prot = ((r=='r')?PROT_READ:0)|((w=='w')?PROT_WRITE:0)|((x=='x')?PROT_EXEC:0);
|
||||
allocProtection(s, e-s, prot);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if(box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG) {
|
||||
printf_log(LOG_NONE, "Refresh mmap allocated block done =============\n");
|
||||
printMapMem();
|
||||
}
|
||||
box86_mapclean = 1;
|
||||
}
|
||||
|
||||
#define LOWEST (void*)0x10000
|
||||
#define MEDIAN (void*)0x40000000
|
||||
static void* findBlockHinted(void* hint, size_t size)
|
||||
{
|
||||
mapmem_t* m = mapmem;
|
||||
uintptr_t h = (uintptr_t)hint;
|
||||
while(m) {
|
||||
// granularity 0x10000
|
||||
uintptr_t addr = (m->end+1+0xffff)&~0xffff;
|
||||
uintptr_t end = (m->next)?(m->next->begin-1):0xffffffff;
|
||||
// check hint and available size
|
||||
if(addr<=h && end>=h && end-h+1>=size)
|
||||
return hint;
|
||||
if(addr>=h && end-addr+1>=size)
|
||||
return (void*)addr;
|
||||
if(end>=0xc0000000 & h<0xc0000000)
|
||||
return NULL;
|
||||
m = m->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void* findBlockNearHint(void* hint, size_t size)
|
||||
{ void* ret = findBlockHinted(hint, size);
|
||||
return ret?ret:hint;
|
||||
}
|
||||
void* find32bitBlock(size_t size)
|
||||
{
|
||||
void* ret = findBlockHinted(MEDIAN, size);
|
||||
if(!ret) ret = findBlockHinted(LOWEST, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -767,8 +1120,14 @@ void init_custommem_helper(box86context_t* ctx)
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
lockaddress = kh_init(lockaddress);
|
||||
#endif
|
||||
pthread_atfork(NULL, NULL, atfork_child_custommem);
|
||||
// init mapmem list
|
||||
mapmem = (mapmem_t*)box_calloc(1, sizeof(mapmem_t));
|
||||
mapmem->begin = 0x0;
|
||||
mapmem->end = (uintptr_t)LOWEST - 1;
|
||||
loadProtectionFromMap();
|
||||
}
|
||||
|
||||
void fini_custommem_helper(box86context_t *ctx)
|
||||
@@ -784,14 +1143,14 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
#ifdef USE_MMAP
|
||||
munmap(mmaplist[i].block, mmaplist[i].size);
|
||||
#else
|
||||
free(mmaplist[i].block);
|
||||
box_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);
|
||||
box_free(mmaplist[i].helper);
|
||||
mmaplist[i].helper = NULL;
|
||||
}
|
||||
}
|
||||
@@ -801,24 +1160,42 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
}
|
||||
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);
|
||||
box_free(mmaplist);
|
||||
for (int i=0; i<DYNAMAP_SIZE; ++i)
|
||||
if(box86_jumptable[i]!=box86_jmptbl_default)
|
||||
free(box86_jumptable[i]);
|
||||
box_free(box86_jumptable[i]);
|
||||
}
|
||||
kh_destroy(lockaddress, lockaddress);
|
||||
lockaddress = NULL;
|
||||
#endif
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
#ifdef USE_MMAP
|
||||
#ifdef USE_MMAP_MORE
|
||||
munmap(p_blocks[i].block, p_blocks[i].size);
|
||||
#else
|
||||
free(p_blocks[i].block);
|
||||
box_free(p_blocks[i].block);
|
||||
#endif
|
||||
free(p_blocks);
|
||||
box_free(p_blocks);
|
||||
pthread_mutex_destroy(&mutex_blocks);
|
||||
while(mapmem) {
|
||||
mapmem_t *tmp = mapmem;
|
||||
mapmem = mapmem->next;
|
||||
box_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
// add an address to the list of "LOCK"able
|
||||
void addLockAddress(uintptr_t addr)
|
||||
{
|
||||
int ret;
|
||||
kh_put(lockaddress, lockaddress, addr, &ret);
|
||||
}
|
||||
|
||||
// return 1 is the address is used as a LOCK, 0 else
|
||||
int isLockAddress(uintptr_t addr)
|
||||
{
|
||||
khint_t k = kh_get(lockaddress, lockaddress, addr);
|
||||
return (k==kh_end(lockaddress))?0:1;
|
||||
}
|
||||
|
||||
#endif
|
||||
+101
-13
@@ -66,7 +66,7 @@ Op is 20-27
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
// nop
|
||||
#define NOP EMIT(0xe1a00000)
|
||||
#define NOP EMIT(0xe320f000)
|
||||
|
||||
// mov dst, src
|
||||
#define MOV_REG(dst, src) EMIT(0xe1a00000 | ((dst) << 12) | (src) )
|
||||
@@ -213,6 +213,9 @@ Op is 20-27
|
||||
// add dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.c dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x00800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.s dst, src1, src2, lsl #imm
|
||||
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -242,9 +245,12 @@ Op is 20-27
|
||||
// cmp.s dst, src, #imm
|
||||
#define CMPS_IMM8(src, imm8) \
|
||||
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
// cmn.s.cond dst, src, #imm
|
||||
#define CMNS_IMM8_COND(cond, src, imm8) \
|
||||
EMIT((cond) | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
#define CMNS_IMM8(src, imm8) \
|
||||
EMIT(c__ | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// tst.s dst, src1, src2, lsl #imm
|
||||
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
|
||||
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -254,21 +260,33 @@ Op is 20-27
|
||||
// tst.s dst, src1, #imm ror rot*2
|
||||
#define TSTS_IMM8_ROR(src, imm8, rot) \
|
||||
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// tst.s.cond dst, src1, #imm ror rot*2
|
||||
#define TSTS_IMM8_ROR_COND(cond, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// orr dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.cond dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT(cond | 0x01800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl #imm
|
||||
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.cond dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT(cond | 0x01800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsr #imm
|
||||
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl rs
|
||||
#define ORRS_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr.s dst, src1, src2, lsr rs
|
||||
#define ORRS_REG_LSR_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSR(rs, src2) )
|
||||
// orr dst, src1, #imm8
|
||||
#define ORR_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
@@ -281,6 +299,9 @@ Op is 20-27
|
||||
// orr dst, src1, src2, lsl rs
|
||||
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr dst, src1, src2, lsr rs
|
||||
#define ORR_REG_LSR_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSR(rs, src2) )
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -370,6 +391,8 @@ Op is 20-27
|
||||
// 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) )
|
||||
|
||||
#define LDR_litteral(reg, imm12) EMIT(c__ | 0b010<<25 | 0<<24 | ((imm12<0)?0:1)<<23 | 0<<22 | 0<<21 | 1<<20 | 0b1111<<16 | (reg)<<12 | (abs(imm12)))
|
||||
|
||||
// str reg, [addr, #+/-imm9]
|
||||
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// str with cond reg, [addr, #+/-imm9]
|
||||
@@ -443,7 +466,6 @@ Op is 20-27
|
||||
#define LDRH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 0, 1, abs(imm8)))
|
||||
#define LDRH_IMM8_COND(cond, reg, addr, imm8) EMIT(HWS_OFF(cond, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRSH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 1, 1, abs(imm8)))
|
||||
|
||||
#define LDRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 1, addr, reg, 0, 1, rm))
|
||||
#define STRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 0, addr, reg, 0, 1, rm))
|
||||
@@ -466,6 +488,7 @@ Op is 20-27
|
||||
// Mul and MulA
|
||||
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | 0b000000<<22 | (A)<<21 | (S)<<20 | (Rd)<<16 | (Rn)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
|
||||
#define MUL(Rd, Rm, Rn) EMIT(MULMULA(c__, 0, 0, (Rd), 0, (Rm), (Rn)))
|
||||
#define MLA(Rd, Rn, Rm, Ra) EMIT(MULMULA(c__, 1, 0, (Rd), (Ra), (Rm), (Rn)))
|
||||
|
||||
#define MLS_gen(Cond, Rd, Ra, Rm, Rn) (Cond | 0b00000110<<20 | (Rd)<<16 | (Ra)<<12 | (Rm)<<8 | 0b1001<<4 | (Rn))
|
||||
//MLS : Rd = Ra - Rm*Rn
|
||||
@@ -486,6 +509,8 @@ Op is 20-27
|
||||
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// SBFX: Signed Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define SBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111101<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
|
||||
@@ -554,6 +579,16 @@ Op is 20-27
|
||||
#define STREXB(Rd, Rt, Rn) EMIT(STREXB_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXB_COND(cond, Rd, Rt, Rn) EMIT(STREXB_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
#define LDREXH_gen(cond, Rn, Rt) (cond | 0b0001111<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
|
||||
// Load Exclusive Half-Word Rt from Rn (tagging the memory)
|
||||
#define LDREXH(Rt, Rn) EMIT(LDREXH_gen(c__, Rn, Rt))
|
||||
#define LDREXH_COND(cond, Rt, Rn) EMIT(LDREXH_gen(cond, Rn, Rt))
|
||||
|
||||
#define STREXH_gen(cond, Rd, Rn, Rt) (cond | 0b0001111<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
|
||||
// Store Exclusive Half-Word Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
|
||||
#define STREXH(Rd, Rt, Rn) EMIT(STREXH_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXH_COND(cond, Rd, Rt, Rn) EMIT(STREXH_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
// Count leading 0 bit of Rm, store result in Rd
|
||||
#define CLZ(Rd, Rm) EMIT(c__ | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
|
||||
// Reverse bits of Rm, store result in Rd
|
||||
@@ -654,6 +689,10 @@ Op is 20-27
|
||||
// Store to memory to single VSTR Sd, [Rn, #+/-imm8], imm8&3 ignored!
|
||||
#define VSTR_32(Sd, Rn, Imm8) EMIT(c__ | (0b1101<<24) | (((Imm8)<0)?0:1)<<23 | (((Sd)&1)<<22) | (0<<20) | ((Rn)<<16) | ((((Sd)>>1)&15)<<12) | (0b1010<<8) | ((abs(Imm8)>>2)&255))
|
||||
|
||||
#define VSTM_64_gen(cond, P, U, D, W, Rn, Vd, imm8) (cond | 0b110<<25 | (P)<<24 | (U)<<23 | (D)<<22 | (W)<<21 | (Rn)<<16 | (Vd)<<12 | 0b1011<<8 | (imm8))
|
||||
// Store a sery of Dx, post imcrementing Rn
|
||||
#define VSTM_64_W(Dd, Rn) EMIT(VSTM_64_gen(c__, 0, 1, ((Dd)>>4)&1, 1, Rn, (Dd)&15, 2))
|
||||
|
||||
// Convert from single Sm to double Dd
|
||||
#define VCVT_F64_F32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0111<<16) | (((Dd)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (0<<4) | (((Sm)>>1)&15))
|
||||
// Convert from double Dm to single Sd
|
||||
@@ -680,6 +719,42 @@ Op is 20-27
|
||||
// Inplace convert from F64 to S16. Rounding is not selectable
|
||||
#define VCVT_S16_F64(Dd) EMIT(VCVT_FP_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
|
||||
|
||||
#define VRINT_FP_gen(D, RM, Vd, size, M, Vm) (0b111111101<<23 | (D)<<22 | 0b111<<19 | (RM)<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<4 | (Vm))
|
||||
// Round floating-point to integer to Nearest with Ties to Away
|
||||
#define VRINTA_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b00, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer to Nearest with Ties to Away
|
||||
#define VRINTA_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer towards -Infinity
|
||||
#define VRINTM_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b11, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards -Infinity
|
||||
#define VRINTM_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b11, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer to Nearest
|
||||
#define VRINTN_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b01, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer to Nearest
|
||||
#define VRINTN_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer towards +Infinity
|
||||
#define VRINTP_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b10, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards +Infinity
|
||||
#define VRINTP_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTR_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b110<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR
|
||||
#define VRINTR_F32(Sd, Sm) EMIT(VRINTR_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR
|
||||
#define VRINTR_F64(Dd, Dm) EMIT(VRINTR_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTX_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b111<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR with eXecptions if inexact
|
||||
#define VRINTX_F32(Sd, Sm) EMIT(VRINTX_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR with eXecptions if inexact
|
||||
#define VRINTX_F64(Dd, Dm) EMIT(VRINTX_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTZ_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b110<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer towards Zero
|
||||
#define VRINTZ_F32(Sd, Sm) EMIT(VRINTZ_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards Zero
|
||||
#define VRINTZ_F64(Dd, Dm) EMIT(VRINTZ_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
// Mutiply F64 Dd = Dn*Dm
|
||||
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
@@ -719,6 +794,8 @@ Op is 20-27
|
||||
#define VNEG_F64_cond(cond, Dd, Dm) EMIT((cond) | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Neg F32 Dd = - Dm
|
||||
#define VNEG_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
// Neg F32 Dd = - Dm
|
||||
#define VNEG_F32_cond(cond, Sd, Sm) EMIT((cond) | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
|
||||
// Sqrt F64 Dd = - Dm
|
||||
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
@@ -814,19 +891,19 @@ Op is 20-27
|
||||
#define VMOVQ_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 1, 0, (imm8)&15))
|
||||
|
||||
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VLD1LANE_32(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, (index)<<3, 15))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VLD1LANE_32(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, (index)<<3, 15))
|
||||
|
||||
#define VLD1ALL_gen(D, Rn, Vd, size, T, a, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | 0b11<<10| (size)<<6 | (T)<<5 | (a)<<4 | (Rm))
|
||||
#define VLD1ALL_16(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, 0, 0, 15))
|
||||
#define VLD1ALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, 0, 0, 15))
|
||||
#define VLD1QALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, 1, 0, 15))
|
||||
#define VLD1ALL_16(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, 0, 0, 15))
|
||||
#define VLD1ALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, 0, 0, 15))
|
||||
#define VLD1QALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, 1, 0, 15))
|
||||
|
||||
#define VST1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b00<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VST1LANE_8(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VST1LANE_16(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VST1LANE_32(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, (index)<<3, 15))
|
||||
#define VST1LANE_8(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VST1LANE_16(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VST1LANE_32(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, (index)<<3, 15))
|
||||
|
||||
#define VADD_gen(size, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VADD_8(Dd, Dn, Dm) EMIT(VADD_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -870,7 +947,7 @@ Op is 20-27
|
||||
#define VCEQQ_16(Dd, Dn, Dm) EMIT(VCEQ_I_gen(1, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_32(Dd, Dn, Dm) EMIT(VCEQ_I_gen(2, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_32(Dd, Dn, Dm) EMIT(VCEQ_I_gen(2, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
//#define VCEQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15)) // doesn't exist
|
||||
#define VCEQQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_F_gen(sz, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | (sz)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1110<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VCEQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -883,6 +960,7 @@ Op is 20-27
|
||||
#define VCEQQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_F32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VCGT_I_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VCGT_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -1288,7 +1366,17 @@ Op is 20-27
|
||||
|
||||
#define VDUP_sgen(D, imm4, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (imm4)<<16 | (Vd)<<12 | 0b1100<<8 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Dd <= Dup(Dm[x])
|
||||
#define VDUP_8(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<1)|0b1), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_8(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<1)|0b1), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUP_16(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<2)|0b10), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_16(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<2)|0b10), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUP_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_64(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<4)|0b1000), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VREV64_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VREV64_32(Dd, Dm) EMIT(VREV64_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VREV64Q_32(Dd, Dm) EMIT(VREV64_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VABS_vgen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b110<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VABS_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
@@ -179,7 +179,7 @@ INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d64 &g&g param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "arm_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNextTo(void* addr, void* tonext)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
MOV32(x3, (uintptr_t)tonext);
|
||||
BX(x3);
|
||||
}
|
||||
@@ -16,6 +16,11 @@
|
||||
.global arm_lock_xchg
|
||||
.global arm_lock_storeifnull
|
||||
.global arm_lock_storeifref
|
||||
.global arm_lock_store_xchg
|
||||
.global arm_lock_dec
|
||||
.global arm_lock_dec_b
|
||||
.global arm_lock_store
|
||||
.global arm_lock_store_b
|
||||
|
||||
|
||||
arm_lock_read_b:
|
||||
@@ -113,3 +118,46 @@ arm_lock_storeifref_exit:
|
||||
mov r0, r3
|
||||
pop {r4}
|
||||
bx lr
|
||||
|
||||
arm_lock_store_xchg:
|
||||
// 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
|
||||
ldrex r2, [r0]
|
||||
cmp r2, #0
|
||||
bne arm_lock_store_xchg_exit
|
||||
mov r2, r1
|
||||
strex r3, r2, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_store_xchg
|
||||
mov r2, #0
|
||||
arm_lock_store_xchg_exit:
|
||||
mov r0, r2
|
||||
bx lr
|
||||
|
||||
arm_lock_dec:
|
||||
dmb ish
|
||||
ldrex r1, [r0]
|
||||
sub r1, r1, #1
|
||||
strex r2, r1, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_dec
|
||||
bx lr
|
||||
|
||||
arm_lock_dec_b:
|
||||
dmb ish
|
||||
ldrexb r1, [r0]
|
||||
sub r1, r1, #1
|
||||
strexb r2, r1, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_dec_b
|
||||
bx lr
|
||||
|
||||
arm_lock_store:
|
||||
str r1, [r0]
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_store_b:
|
||||
strb r1, [r0]
|
||||
dmb ish
|
||||
bx lr
|
||||
@@ -31,4 +31,19 @@ extern void* arm_lock_storeifnull(void* p, void* val);
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* arm_lock_store_xchg(void* p, void* val);
|
||||
|
||||
// will decrease *p atomicaly
|
||||
extern void arm_lock_dec_b(uint8_t* p);
|
||||
|
||||
// will decrease *p atomicaly
|
||||
extern void arm_lock_dec(int* p);
|
||||
|
||||
// store value, with data memory barrier
|
||||
extern void arm_lock_store_b(uint8_t* p, uint8_t val);
|
||||
|
||||
// store value, with data memory barrier
|
||||
extern void arm_lock_store(int* p, int val);
|
||||
|
||||
#endif //__ARM_LOCK_HELPER__H__
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************
|
||||
* File automatically generated by rebuild_printer.py (v1.2.0.05) *
|
||||
* File automatically generated by rebuild_printer.py (v1.2.0.06) *
|
||||
******************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -1164,7 +1164,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int m = ((opcode >> 5) & 1) << 4 | ((opcode >> 0) & 0xF);
|
||||
int param = (opcode >> 7) & 0x3;
|
||||
|
||||
sprintf(ret, "VREV%d.%d %s, %s", 16 << param, 8 << size, vecname[(q << 5) + 0x20 + d], vecname[(q << 5) + 0x20 + m]);
|
||||
sprintf(ret, "VREV%d.%d %s, %s", 64 >> param, 8 << size, vecname[(q << 5) + 0x20 + d], vecname[(q << 5) + 0x20 + m]);
|
||||
} else if ((opcode & 0xFFB30F10) == 0xF3B00200) {
|
||||
int u = (opcode >> 7) & 1;
|
||||
int size = (opcode >> 18) & 0x3;
|
||||
|
||||
+99
-282
@@ -4,6 +4,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
#ifdef ARM
|
||||
#include "dynarec_arm.h"
|
||||
#include "arm_lock_helper.h"
|
||||
@@ -40,108 +42,36 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
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->text = text;
|
||||
ret->textsz = textsz;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
}
|
||||
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);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, 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);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
FreeDynarecMap(db, (uintptr_t)db->actual_block, db->size);
|
||||
box_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_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
FreeDynablock((*dynablocks)->direct[i], my_context?1:0);
|
||||
}
|
||||
free((*dynablocks)->direct);
|
||||
}
|
||||
(*dynablocks)->direct = NULL;
|
||||
|
||||
free(*dynablocks);
|
||||
*dynablocks = NULL;
|
||||
}
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1;
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -149,80 +79,27 @@ int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintp
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
if(!db)
|
||||
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);
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x86_addr, (void*)db->x86_size);
|
||||
if(!db->need_test)
|
||||
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)
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!db)
|
||||
return 1;
|
||||
|
||||
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);
|
||||
int need_lock = my_context?1:0;
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) {
|
||||
FreeDynablock(db, need_lock);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
@@ -234,66 +111,27 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
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 db;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
const int idx = (addr>>DYNAMAP_SHIFT);
|
||||
return getDB(idx);
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
|
||||
{
|
||||
if(!dynablocks) {
|
||||
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
|
||||
*created = 0;
|
||||
dynablock_t* block;
|
||||
#if 0
|
||||
// check if memory as the correct flags
|
||||
int prot = getProtection(addr);
|
||||
if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) {
|
||||
dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot);
|
||||
return NULL;
|
||||
}
|
||||
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
|
||||
// this should be useless
|
||||
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
|
||||
//*created = 0;
|
||||
//return NULL;
|
||||
return AddNewDynablock(getDBFromAddress(addr), addr, created);
|
||||
}
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
#endif
|
||||
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);
|
||||
block = (dynablock_t*)box_calloc(1, sizeof(dynablock_t));
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -309,39 +147,28 @@ void cancelFillBlock()
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks) {
|
||||
dynablocks = getDBFromAddress(addr);
|
||||
if(!dynablocks) {
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
|
||||
if((block = dynablocks->direct[addr-dynablocks->text]))
|
||||
return block;
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
if(need_lock)
|
||||
@@ -353,68 +180,60 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
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);
|
||||
box_free(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && block->x86_size) {
|
||||
if(block && (block->x86_size || (!block->x86_size && !block->done))) {
|
||||
int blocksz = block->x86_size;
|
||||
if(dynablocks->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
//protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock
|
||||
// but check if it already need test
|
||||
if(block->need_test || (block->father && block->father->need_test))
|
||||
return NULL;
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault(block->x86_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
|
||||
if(!addJumpTableIfDefault(block->x86_addr, block->block)) {
|
||||
FreeDynablock(block, 1);
|
||||
block = getDB(addr);
|
||||
} else {
|
||||
if(block->x86_size)
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(AreaInHotPage((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr + db->x86_size - 1)) {
|
||||
dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr);
|
||||
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);
|
||||
}
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump)) {
|
||||
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, 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);
|
||||
db->need_test = 0;
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -422,27 +241,25 @@ 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))) {
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1);
|
||||
if(db && db->done && db->block && db->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);
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
db->need_test = 0;
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
addJumpTableIfDefault(db->x86_addr, db->block);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x86:4;
|
||||
unsigned int nat:4;
|
||||
unsigned char x86:4;
|
||||
unsigned char nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
int size;
|
||||
void* x86_addr;
|
||||
uintptr_t x86_size;
|
||||
@@ -20,17 +19,8 @@ typedef struct dynablock_s {
|
||||
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;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
int maxsz; // maxblock size (for this block or previous block)
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+16
-19
@@ -20,16 +20,12 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
#include "dynarec_next.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef HAVE_TRACE
|
||||
#include "elfloader.h"
|
||||
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#endif
|
||||
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
@@ -38,12 +34,13 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
void* x86addr = db?(void*)getX86Address(db, (uintptr_t)x2):NULL;
|
||||
const char* pcname = getAddrFunctionName((uintptr_t)x86addr);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p/%s)\n", x2, db, x86addr, pcname);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
if(hasAlternate((void*)addr)) {
|
||||
@@ -51,7 +48,7 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
R_EIP = addr;
|
||||
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
block = DBGetBlock(emu, addr, 1);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
@@ -111,18 +108,15 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
PushExit(emu);
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = block;
|
||||
dynablock_t* block = DBGetBlock(emu, R_EIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
@@ -165,6 +159,7 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
}
|
||||
|
||||
int my_setcontext(x86emu_t* emu, void* ucp);
|
||||
int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
@@ -196,17 +191,15 @@ 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, ¤t);
|
||||
current = block;
|
||||
block = DBGetBlock(emu, R_EIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
@@ -226,6 +219,10 @@ int DynaRun(x86emu_t* emu)
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
else if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear the setjmp
|
||||
|
||||
+196
-160
@@ -3,6 +3,7 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -22,21 +23,22 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "elfloader.h"
|
||||
#include "dynarec_next.h"
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
|
||||
uint32_t a = *(uint32_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x86emu%s\n", (box86_dynarec_dump>1)?"\e[1m":"", (void*)ip, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x86emu%s\n", (box86_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box86_dynarec_dump>1)?"\e[1m":"", (void*)ip, (void*)a, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box86_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (void*)a, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[1m":"", ip, DecodeX86Trace(dec, inst->addr));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[01;33m":"", ip, DecodeX86Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box86_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box86_dynarec_dump>1)?"\e[01;33m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
@@ -60,12 +62,20 @@ void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const cha
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(!box86_dynarec_bigblock)
|
||||
return;
|
||||
// exist?
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
// put in a free slot
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(!dyn->next[i]) {
|
||||
dyn->next[i] = addr;
|
||||
return;
|
||||
}
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
dyn->next = (uintptr_t*)box_realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -75,13 +85,12 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
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;
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
@@ -92,7 +101,9 @@ int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
return 1;
|
||||
if(PK(0)==0x90)
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
|
||||
if(n>1 && PK(0)==0x2E) // if opcode start with 0x2E, and there is more after, than this *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than this *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
@@ -206,7 +217,7 @@ int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 1: // DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
@@ -231,7 +242,7 @@ int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
|
||||
static 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;
|
||||
@@ -241,7 +252,7 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size,
|
||||
toadd = 1 + arm_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
insts = (instsize_t*)box_realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
while(toadd) {
|
||||
if(x86_size>15)
|
||||
@@ -260,6 +271,89 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size,
|
||||
return insts;
|
||||
}
|
||||
|
||||
static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to alocate the array
|
||||
// first compute the jumps
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x86.jmp && dyn->insts[i].x86.jmp_insts!=-1) {
|
||||
++pred_sz;
|
||||
++dyn->insts[dyn->insts[i].x86.jmp_insts].pred_sz;
|
||||
}
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x86.has_next) {
|
||||
++pred_sz;
|
||||
++dyn->insts[i+1].pred_sz;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)box_malloc(pred_sz*sizeof(int));
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
dyn->insts[i].pred = p;
|
||||
p += dyn->insts[i].pred_sz;
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x86.has_next && (!i || dyn->insts[i].pred_sz))
|
||||
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
|
||||
if(dyn->insts[i].x86.jmp && dyn->insts[i].x86.jmp_insts!=-1)
|
||||
dyn->insts[dyn->insts[i].x86.jmp_insts].pred[dyn->insts[dyn->insts[i].x86.jmp_insts].pred_sz++] = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// updateNeed goes backward, from last intruction to top
|
||||
static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x86.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags==SF_SUBSET)) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
}
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags==SF_SET)) {
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x86.set_flags; // SF_SET will compute all flags, it's not SUBSET!
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x86.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x86.set_flags);
|
||||
}
|
||||
dyn->insts[ninst].x86.gen_flags = need&dyn->insts[ninst].x86.set_flags;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags&SF_PENDING))
|
||||
dyn->insts[ninst].x86.gen_flags |= X_PEND;
|
||||
dyn->insts[ninst].x86.need_after = need;
|
||||
need = dyn->insts[ninst].x86.need_after&~dyn->insts[ninst].x86.gen_flags;
|
||||
if(dyn->insts[ninst].x86.may_set)
|
||||
need |= dyn->insts[ninst].x86.gen_flags; // forward the flags
|
||||
// Consume X_PEND if relevant
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.set_flags&SF_PENDING))
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x86.use_flags;
|
||||
if(dyn->insts[ninst].x86.need_before == need)
|
||||
return ninst - 1;
|
||||
dyn->insts[ninst].x86.need_before = need;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLAGS) {
|
||||
need = need?X_PEND:0;
|
||||
}
|
||||
int ok = 0;
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
if(dyn->insts[ninst].pred[i] == ninst-1)
|
||||
ok = 1;
|
||||
else
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], need);
|
||||
}
|
||||
if(!ok)
|
||||
return ninst - 1;
|
||||
--ninst;
|
||||
}
|
||||
return ninst;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -273,20 +367,49 @@ void CancelBlock()
|
||||
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);
|
||||
box_free(helper->next);
|
||||
box_free(helper->insts);
|
||||
box_free(helper->instsize);
|
||||
box_free(helper->predecessor);
|
||||
if(helper->dynablock && helper->dynablock->actual_block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->actual_block, helper->dynablock->size);
|
||||
else if(helper->dynablock && helper->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->block-sizeof(void*), helper->dynablock->size);
|
||||
}
|
||||
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
size_t sz = 4*sizeof(void*);
|
||||
void* actual_p = (void*)AllocDynarecMap(block, sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock();
|
||||
return NULL;
|
||||
}
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
CreateJmpNextTo(block->jmpnext, arm_epilog);
|
||||
block->need_test = 0;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
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");
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
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;
|
||||
@@ -298,46 +421,29 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
helper.insts = (instruction_arm_t*)box_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);
|
||||
box_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);
|
||||
CancelBlock();
|
||||
return (void*)block;
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// calculate barriers
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.jmp) {
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
if(j<start || j>=end) {
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
helper.insts[i].x86.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
@@ -345,101 +451,61 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(helper.insts[i2].x86.addr==j)
|
||||
k=i2;
|
||||
}
|
||||
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
|
||||
helper.insts[k].x86.barrier = 1;
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x86.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x86.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
// check for the optionnal barriers now
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.barrier==3)
|
||||
if(helper.insts[i].x86.jmp_insts == -1) {
|
||||
if(i==helper.size-1 || helper.insts[i+1].x86.barrier)
|
||||
helper.insts[i].x86.barrier=2; // nope, end of block or barrier just after
|
||||
else
|
||||
helper.insts[i].x86.barrier=0; // ok, no need for a barrier here after all
|
||||
} else
|
||||
helper.insts[i].x86.barrier=2;
|
||||
}
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
&& helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1) {
|
||||
int k = helper.insts[i].x86.jmp_insts;
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x86.need_flags)
|
||||
||(helper.insts[k].x86.set_flags==X_ALL
|
||||
&& helper.insts[k].x86.state_flags==SF_SET)
|
||||
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x86.barrier = 4; // remove barrier (keep FPU barrier, and still reset state flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
if(helper.insts[i].x86.barrier==1)
|
||||
// immediate barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
) {
|
||||
if(helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1)
|
||||
// jumpto barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else
|
||||
helper.insts[i].x86.use_flags |= helper.insts[helper.insts[i].x86.jmp_insts].x86.need_flags;
|
||||
}
|
||||
}
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
helper.insts[i].x86.need_flags = 0;
|
||||
last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
}
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
fillPredecessors(&helper);
|
||||
|
||||
// pass 1, float optimisations
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
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(block, sz);
|
||||
if(p==NULL) {
|
||||
// keep size of instructions for signal handling
|
||||
size_t insts_ursize = 0;
|
||||
{
|
||||
size_t insts_size = 0;
|
||||
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;
|
||||
helper.instsize = (instsize_t*)box_calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
helper.instsize = addInst(helper.instsize, &insts_size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
|
||||
helper.instsize = addInst(helper.instsize, &insts_size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
insts_ursize = insts_size*sizeof(instsize_t);
|
||||
}
|
||||
size_t insts_rsize = (insts_ursize+7)&~7; // round the size...
|
||||
size_t sz = sizeof(void*) + helper.arm_size + 4*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) jmpnext code instsize
|
||||
void* actual_p = (void*)AllocDynarecMap(block, sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
void* next = p + helper.arm_size;
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
|
||||
CancelBlock();
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
*(dynablock_t**)actual_p = block;
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
if(box86_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
size_t oldarmsize = helper.arm_size;
|
||||
helper.arm_size = 0;
|
||||
arm_pass3(&helper, addr);
|
||||
if(sz!=helper.arm_size) {
|
||||
if(oldarmsize!=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);
|
||||
@@ -451,32 +517,32 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
}
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
}
|
||||
// all done...
|
||||
__clear_cache(p, p+sz); // need to clear the cache before execution...
|
||||
// keep size of instructions for signal handling
|
||||
{
|
||||
size_t cap = 1;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
|
||||
size_t size = 0;
|
||||
block->instsize = (instsize_t*)calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
|
||||
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
}
|
||||
memcpy(instsize, helper.instsize, insts_ursize);
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
box_free(helper.insts);
|
||||
helper.insts = NULL;
|
||||
free(helper.next);
|
||||
box_free(helper.next);
|
||||
helper.next = NULL;
|
||||
box_free(helper.instsize);
|
||||
helper.instsize = NULL;
|
||||
box_free(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
*(dynablock_t**)next = block;
|
||||
CreateJmpNextTo(block->jmpnext, arm_next);
|
||||
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;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if(block->hash != hash) {
|
||||
@@ -484,37 +550,7 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
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;
|
||||
}
|
||||
}
|
||||
+208
-132
@@ -5,6 +5,7 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
@@ -36,12 +38,16 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint32_t u32;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int fixedaddress;
|
||||
int lock;
|
||||
int cacheupd;
|
||||
|
||||
opcode = F8;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(tmp);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
@@ -340,7 +346,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x27:
|
||||
INST_NAME("DAA");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization DAA\n");
|
||||
READFLAGS(X_AF|X_CF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTB(x1, xEAX, 0);
|
||||
@@ -402,7 +408,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x2F:
|
||||
INST_NAME("DAS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization DAS\n");
|
||||
READFLAGS(X_AF|X_CF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTB(x1, xEAX, 0);
|
||||
@@ -464,7 +470,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x37:
|
||||
INST_NAME("AAA");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization AAA\n");
|
||||
READFLAGS(X_AF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTH(x1, xEAX, 0);
|
||||
@@ -532,7 +538,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x3F:
|
||||
INST_NAME("AAS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization AAS\n");
|
||||
READFLAGS(X_AF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTH(x1, xEAX, 0);
|
||||
@@ -548,7 +554,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC reg");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&0x07);
|
||||
emit_inc32(dyn, ninst, gd, x3, x14);
|
||||
break;
|
||||
@@ -561,7 +567,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC reg");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&0x07);
|
||||
emit_dec32(dyn, ninst, gd, x3, x14);
|
||||
break;
|
||||
@@ -575,7 +581,16 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x57:
|
||||
INST_NAME("PUSH reg");
|
||||
gd = xEAX+(opcode&0x07);
|
||||
#ifdef RPI2
|
||||
if(gd==xESP) {
|
||||
MOV_REG(x1, gd);
|
||||
PUSH1(x1);
|
||||
} else {
|
||||
PUSH1(gd);
|
||||
}
|
||||
#else
|
||||
PUSH1(gd);
|
||||
#endif
|
||||
break;
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
@@ -587,7 +602,16 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x5F:
|
||||
INST_NAME("POP reg");
|
||||
gd = xEAX+(opcode&0x07);
|
||||
#ifdef RPI2
|
||||
if(gd==xESP) {
|
||||
POP1(x1);
|
||||
MOV_REG(gd, x1);
|
||||
} else {
|
||||
POP1(gd);
|
||||
}
|
||||
#else
|
||||
POP1(gd);
|
||||
#endif
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUSHAD");
|
||||
@@ -691,24 +715,29 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F|(dyn->insts[ninst].x86.barrier?0:X_PEND)); \
|
||||
READFLAGS(F); \
|
||||
i8 = F8S; \
|
||||
BARRIER(3); \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8);\
|
||||
Bcond(NO, i32); \
|
||||
if(!dyn->insts[ninst].x86.barrier) \
|
||||
if(!(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
|
||||
case 0x70:
|
||||
@@ -987,7 +1016,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
GETGB(x14);
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
// do the swap with exclusive locking
|
||||
LDREXB(x1, ed);
|
||||
@@ -1013,7 +1042,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
GETGD;
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(ed, 3);
|
||||
B_MARK(cNE);
|
||||
@@ -1058,8 +1087,9 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
eb2 = ((ed&4)>>2); // L or H
|
||||
BFI(eb1, gd, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, &lock);
|
||||
STRB_IMM9(gd, ed, fixedaddress);
|
||||
if(lock) {DMB_ISH();}
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
@@ -1069,8 +1099,9 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, &lock);
|
||||
STR_IMM9(gd, ed, fixedaddress);
|
||||
if(lock) {DMB_ISH();}
|
||||
}
|
||||
break;
|
||||
case 0x8A:
|
||||
@@ -1094,7 +1125,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
(dyn->insts[ninst].x86.barrier || !ninst || (box86_dynarec_strongmem>1) || (ninst && dyn->insts[ninst-1].x86.barrier))) {
|
||||
DMB_ISH();
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, &lock);
|
||||
if(lock) {DMB_ISH();}
|
||||
LDRB_IMM9(x14, wback, fixedaddress);
|
||||
ed = x14;
|
||||
}
|
||||
@@ -1107,11 +1139,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
if(box86_dynarec_strongmem &&
|
||||
(dyn->insts[ninst].x86.barrier || !ninst || (box86_dynarec_strongmem>1) || (ninst && dyn->insts[ninst-1].x86.barrier))) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, &lock);
|
||||
if(lock || (box86_dynarec_strongmem &&
|
||||
(dyn->insts[ninst].x86.barrier || !ninst || (box86_dynarec_strongmem>1) || (ninst && dyn->insts[ninst-1].x86.barrier)))) {
|
||||
DMB_ISH();
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1122,7 +1154,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
LDRH_REG(xEAX+(nextop&7), xEmu, x3);
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDRH_REG(x3, xEmu, x3);
|
||||
STRH_IMM8(x3, ed, fixedaddress);
|
||||
}
|
||||
@@ -1134,7 +1166,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(gd!=ed) { // it's sometimes used as a 3 bytes NOP
|
||||
MOV_REG(gd, ed);
|
||||
}
|
||||
@@ -1146,7 +1178,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1167,7 +1199,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
POP1(xEAX+(nextop&7));
|
||||
} else {
|
||||
POP1(x2); // so this can handle POP [ESP] and maybe some variant too
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
if(ed==xESP) {
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
} else {
|
||||
@@ -1377,7 +1409,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Eb, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
u8 = F8;
|
||||
emit_rol8c(dyn, ninst, x1, u8&0x1f, x2, x14);
|
||||
@@ -1385,7 +1417,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Eb, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
u8 = F8;
|
||||
emit_ror8c(dyn, ninst, x1, u8&0x1f, x2, x14);
|
||||
@@ -1393,7 +1425,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEB(x1);
|
||||
@@ -1404,7 +1436,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEB(x1);
|
||||
@@ -1467,7 +1499,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rol32c(dyn, ninst, ed, u8, x3, x14);
|
||||
@@ -1475,7 +1507,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_ror32c(dyn, ninst, ed, u8, x3, x14);
|
||||
@@ -1483,14 +1515,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEDW(x14, x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
WBACK;
|
||||
WBACK; // no SBACK here because ret value is ed directly
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, Ib");
|
||||
@@ -1498,7 +1530,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDW(x14, x1);
|
||||
u8 = F8&0x1f;
|
||||
if(u8==1) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(ed, xEmu, offsetof(x86emu_t, op1));
|
||||
MOVW(x3, u8);
|
||||
@@ -1521,13 +1553,13 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BFC_COND(cCC, xFlags, F_CF, 1);
|
||||
|
||||
}
|
||||
WBACK;
|
||||
WBACK; // no SBACK here because ed has been used all along and not x1
|
||||
} else if(u8>1) {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, u8);
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
WBACK;
|
||||
WBACK; // no SBACK here because ret value is ed directly
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
@@ -1564,8 +1596,10 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC2:
|
||||
INST_NAME("RETN");
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
BARRIER(2);
|
||||
if(box86_dynarec_safeflags) {
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ninst, i32);
|
||||
*need_epilog = 0;
|
||||
@@ -1575,8 +1609,10 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RET");
|
||||
// SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
// ^^^ that hack break PlantsVsZombies and GOG Setup under wine....
|
||||
READFLAGS(X_PEND); // so instead, force the defered flags, so it's not too slow, and flags are not lost
|
||||
BARRIER(2);
|
||||
if(box86_dynarec_safeflags) {
|
||||
READFLAGS(X_PEND); // so instead, force the defered flags, so it's not too slow, and flags are not lost
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -1593,10 +1629,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOVW(x3, u8);
|
||||
BFI(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, &lock);
|
||||
u8 = F8;
|
||||
MOVW(x3, u8);
|
||||
STRB_IMM9(x3, ed, fixedaddress);
|
||||
if(lock) {DMB_ISH();}
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
@@ -1607,10 +1644,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, &lock);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_IMM9(x3, ed, fixedaddress);
|
||||
if(lock) {DMB_ISH();}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1624,7 +1662,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
if(PK(0)=='S' && PK(1)=='C') {
|
||||
addr+=2;
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
INST_NAME("Special Box86 instruction");
|
||||
if((PK(0)==0) && (PK(1)==0) && (PK(2)==0) && (PK(3)==0))
|
||||
{
|
||||
@@ -1639,7 +1677,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", GetNativeName(GetNativeFnc(ip)));
|
||||
x87_forget(dyn, ninst, x3, x14, 0);
|
||||
if(box86_log<2) { // call the wrapper directly
|
||||
if((box86_log<2) && !cycle_log) { // call the wrapper directly
|
||||
uintptr_t ncall[2]; // to avoid BUSERROR!!!
|
||||
memcpy(ncall, (void*)addr, 2*sizeof(void*)); // the wrapper + function
|
||||
addr+=8;
|
||||
@@ -1684,7 +1722,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(PK(0)==0x80) {
|
||||
INST_NAME("Syscall");
|
||||
u8 = F8;
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
MOV32(xEIP, ip+2);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP)|(1<<xEIP)|(1<<xFlags));
|
||||
CALL_S(x86Syscall, -1, 0);
|
||||
@@ -1706,7 +1744,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCF:
|
||||
INST_NAME("IRET");
|
||||
SETFLAGS(X_ALL, SF_SET); // Not a hack, EFLAGS are restored
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
iret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -1718,14 +1756,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("ROL Eb, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_rol8c(dyn, ninst, ed, 1, x2, x14);
|
||||
EBBACK;
|
||||
} else {
|
||||
INST_NAME("ROL Eb, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization ROL 8b\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEB(x1);
|
||||
CALL_(rol8, x1, (1<<x3));
|
||||
@@ -1736,7 +1774,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("ROR Eb, 1");
|
||||
MOVW(x2, 1);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_ror8c(dyn, ninst, ed, 1, x2, x14);
|
||||
EBBACK;
|
||||
@@ -1744,7 +1782,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("ROR Eb, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization ROR 8b\n");
|
||||
GETEB(x1);
|
||||
CALL_(ror8, x1, (1<<x3));
|
||||
EBBACK;
|
||||
@@ -1752,7 +1790,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD0) {INST_NAME("RCL Eb, 1");} else {INST_NAME("RCL Eb, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL 8b\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD0) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
@@ -1762,7 +1800,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD0) {INST_NAME("RCR Eb, 1");} else {INST_NAME("RCR Eb, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR 8b\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD0) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
@@ -1826,36 +1864,55 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, 1);
|
||||
GETEDW(x14, x1);
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
WBACK;
|
||||
WBACK; // no SBACK here because ret value is ed directly
|
||||
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);
|
||||
GETEDW(x14, x1);
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(ed, xEmu, offsetof(x86emu_t, op1));
|
||||
MOVW(x3, 1);
|
||||
STR_IMM9(x3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(x3, d_rcr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(x3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
XOR_REG_LSR_IMM8(x3, xFlags, ed, 31);
|
||||
BFI(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
MOVS_REG_LSR_IMM5(x3, xFlags, 1); // load CC (F_CF==0) into ARM CF
|
||||
MOVS_REG_RRX(ed, ed);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(ed, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1, 0);
|
||||
BFC_COND(cCC, xFlags, F_CF, 1);
|
||||
|
||||
}
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1931,23 +1988,23 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
GETEDW(x14, x1);
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
WBACK;
|
||||
WBACK; // no SBACK here because ret value is ed directly
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
GETEDW(x14, x1);
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
WBACK;
|
||||
WBACK; // no SBACK here because ret value is ed directly
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -2035,20 +2092,27 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDF:
|
||||
addr = dynarecDF(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ");
|
||||
@@ -2094,7 +2158,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
#if STEP < 2
|
||||
if (i32==0)
|
||||
tmp = dyn->insts[ninst].pass2choice = 1;
|
||||
else if (((u32)>0x10000) && (PKa(u32+0)==0x8B) && (((PKa(u32+1))&0xC7)==0x04) && (PKa(u32+2)==0x24) && (PKa(u32+3)==0xC3))
|
||||
else if ((getProtection(u32)&PROT_READ) && (PKa(u32+0)==0x8B) && (((PKa(u32+1))&0xC7)==0x04) && (PKa(u32+2)==0x24) && (PKa(u32+3)==0xC3))
|
||||
tmp = dyn->insts[ninst].pass2choice = 2;
|
||||
/*else if(isNativeCall(dyn, u32, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
tmp = dyn->insts[ninst].pass2choice = 3;*/
|
||||
@@ -2120,14 +2184,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// disabling this to avoid fetching data outside current block (in case this part changed, this block will not been marck as dirty)
|
||||
/*case 3:
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall-1)), dyn->insts[ninst].retn);
|
||||
// calling a native function
|
||||
x87_forget(dyn, ninst, x3, x14, 0);
|
||||
if(box86_log<2 && dyn->insts[ninst].natcall) { // call the wrapper directly
|
||||
if((box86_log<2) && !cycle_log && dyn->insts[ninst].natcall) { // call the wrapper directly
|
||||
uintptr_t ncall[2];
|
||||
memcpy(ncall, (void*)(dyn->insts[ninst].natcall+2), 2*sizeof(void*)); // the wrapper + function
|
||||
MOV32(xEIP, dyn->insts[ninst].natcall+2+4+4);
|
||||
@@ -2159,18 +2223,16 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
jump_to_epilog(dyn, 0, xEIP, ninst);
|
||||
break;*/
|
||||
default:
|
||||
if(ninst && dyn->insts[ninst-1].x86.set_flags) {
|
||||
if((box86_dynarec_safeflags>1) || (ninst && dyn->insts[ninst-1].x86.set_flags)) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
if(u32==0) { // self modifying code maybe? so use indirect address fetching
|
||||
@@ -2184,7 +2246,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
BARRIER(1);
|
||||
BARRIER(BARRIER_MAYBE);
|
||||
if(opcode==0xE9) {
|
||||
INST_NAME("JMP Id");
|
||||
i32 = F32S;
|
||||
@@ -2193,18 +2255,18 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i32 = F8S;
|
||||
}
|
||||
JUMP(addr+i32, 0);
|
||||
if(dyn->insts) {
|
||||
PASS2IF(dyn->insts[ninst].x86.jmp_insts==-1, 1) {
|
||||
// out of the block
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) {
|
||||
// out of the block
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
} else {
|
||||
// inside the block
|
||||
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
|
||||
tmp = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);
|
||||
if(tmp==-4) {
|
||||
NOP;
|
||||
} else {
|
||||
// inside the block
|
||||
tmp = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);
|
||||
if(tmp==-4) {
|
||||
NOP;
|
||||
} else {
|
||||
Bcond(c__, tmp);
|
||||
}
|
||||
Bcond(c__, tmp);
|
||||
}
|
||||
}
|
||||
*need_epilog = 0;
|
||||
@@ -2255,7 +2317,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xAF:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3, 2);
|
||||
@@ -2314,8 +2377,12 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xC3:
|
||||
INST_NAME("(REPZ) RET");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
BARRIER(2);
|
||||
if(box86_dynarec_safeflags>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -2346,7 +2413,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xA6:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ CMPSB");} else {INST_NAME("REPZ CMPSB");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3,1);
|
||||
@@ -2370,7 +2438,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xA7:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ CMPSD");} else {INST_NAME("REPZ CMPSD");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3,4);
|
||||
@@ -2435,7 +2504,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xAE:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ SCASB");} else {INST_NAME("REPZ SCASB");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3,1);
|
||||
@@ -2459,7 +2529,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xAF:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ SCASD");} else {INST_NAME("REPZ SCASD");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3,4);
|
||||
@@ -2537,7 +2608,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AL, Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization IMUL 8b\n");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEB(x1);
|
||||
STM(xEmu, (1<<xEAX));
|
||||
@@ -2546,7 +2617,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization DIV 8b\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEB(x1);
|
||||
STM(xEmu, (1<<xEAX));
|
||||
@@ -2555,7 +2626,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization IDIV 8b\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEB(x1);
|
||||
STM(xEmu, (1<<xEAX));
|
||||
@@ -2612,7 +2683,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(arm_div && ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x86.addr)==0x31
|
||||
&& (*(uint8_t*)(dyn->insts[ninst-1].x86.addr)==0x31
|
||||
|| *(uint8_t*)(dyn->insts[ninst-1].x86.addr)==0x33)
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x86.addr+1)==0xD2) {
|
||||
// previous instruction is XOR EDX, EDX, so its 32bits / 32bits
|
||||
SET_DFNONE(x2); // flags are undefined
|
||||
@@ -2655,9 +2727,15 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
GETEDH(x1);
|
||||
if(arm_div) {
|
||||
// check if a 32bits division is enough
|
||||
CMPS_IMM8(xEDX, 0); // compare to 0
|
||||
CMNS_IMM8_COND(cNE, xEDX, 1); // compare to FFFFFFFF if not 0
|
||||
TSTS_IMM8_ROR_COND(cEQ, xEAX, 0b10, 1); // also test that xEAX is not signed!
|
||||
B_MARK(cEQ);
|
||||
CMNS_IMM8(xEDX, 1); // compare to FFFFFFFF if not 0
|
||||
B_MARK2(cNE);
|
||||
TSTS_IMM8_ROR(xEAX, 0b10, 1); // also test that xEAX is signed!
|
||||
B_MARK(cNE);
|
||||
MARK2;
|
||||
}
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
|
||||
@@ -2711,14 +2789,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_inc8(dyn, ninst, x1, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_dec8(dyn, ninst, x1, x2, x14);
|
||||
EBBACK;
|
||||
@@ -2733,39 +2811,37 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_inc32(dyn, ninst, ed, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF(ninst && dyn->insts[ninst-1].x86.set_flags, 1) {
|
||||
PASS2IF((box86_dynarec_safeflags>1) || (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
|
||||
//SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDH(xEIP);
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
BARRIER(1);
|
||||
BARRIER(BARRIER_FULL);
|
||||
GETEDH(xEIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
*need_epilog = 0;
|
||||
|
||||
+355
-173
@@ -31,7 +31,7 @@
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7, w); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL); \
|
||||
a = fpu_get_scratch_quad(dyn); \
|
||||
VLD1Q_64(a, ed); \
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL); \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
VLD1_64(a, ed); \
|
||||
}
|
||||
@@ -66,6 +66,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
int cacheupd;
|
||||
MAYUSE(s0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v2);
|
||||
@@ -75,6 +76,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP == 3
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
@@ -87,6 +89,20 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
//CALL(arm_ud, -1, 0);
|
||||
UDF(0);
|
||||
break;
|
||||
|
||||
case 0x0D:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("PREFETCHW");
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
addr = fakeed(dyn,addr, ninst, nextop);
|
||||
// should use PLDW, but it's not available on cortex-a8 for example
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -97,7 +113,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
//LDRD also have alignment requirements
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -116,7 +132,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-16, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-16, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
// cannot use STRD, this needs alignement too
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
@@ -136,7 +152,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -152,12 +168,12 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1_32(v0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -196,7 +212,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1_64(v0+1, ed);
|
||||
}
|
||||
break;
|
||||
@@ -210,12 +226,12 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1_64(v0+1, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0+1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -232,7 +248,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 2:
|
||||
case 3:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xffff, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xffff, 0, 0, NULL);
|
||||
MOVW(x3, fixedaddress);
|
||||
if(fixedaddress<0) {
|
||||
PLDn(ed, x3);
|
||||
@@ -262,7 +278,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -275,7 +291,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -287,7 +303,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_double(dyn);
|
||||
VLD1_32(v1, ed);
|
||||
}
|
||||
@@ -302,7 +318,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -314,7 +330,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_double(dyn);
|
||||
VLD1_32(v1, ed);
|
||||
}
|
||||
@@ -328,7 +344,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_double(dyn);
|
||||
VLD1_32(v1, ed);
|
||||
}
|
||||
@@ -370,7 +386,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -428,11 +444,60 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEM(d1);
|
||||
VQRDMULH_S16(d0, d0, d1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
REV(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(gd, ed, fixedaddress);
|
||||
REV(gd, gd);
|
||||
}
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("MOVBE Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
REV(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
REV(x1, gd);
|
||||
STR_IMM9(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3A: // these are some more SSSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0F:
|
||||
INST_NAME("PALIGNR Gm, Em, Ib");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1);
|
||||
u8 = F8;
|
||||
if(u8>15) {
|
||||
VEOR(q0, q0, q0);
|
||||
} else if(u8>7) {
|
||||
d0 = fpu_get_scratch_quad(dyn);
|
||||
VEOR(d0, d0, d0);
|
||||
VEXT_8(q0, q0, d0, u8-8);
|
||||
} else {
|
||||
VEXT_8(q0, q1, q0, u8);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
@@ -443,7 +508,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7); \
|
||||
MOV_REG_COND(YES, gd, ed); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDR_IMM9_COND(YES, gd, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
@@ -555,7 +620,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BFI(gd, x3, 3, 1);
|
||||
} else {
|
||||
// EX is memory
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4096-16, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4096-16, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
UBFX(x3, x2, 31, 1);
|
||||
BFI(gd, x3, 0, 1);
|
||||
@@ -577,23 +642,37 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
#if 0
|
||||
VRSQRTEQ_F32(v2, q0);
|
||||
//step?
|
||||
VRECPEQ_F32(v0, v2);
|
||||
//step?
|
||||
#else
|
||||
// more precise
|
||||
if(v0==q0)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = v0;
|
||||
VRSQRTEQ_F32(v2, q0);
|
||||
VMULQ_F32(v1, v2, q0);
|
||||
VRSQRTSQ_F32(v1, v1, v2);
|
||||
VMULQ_F32(v1, v1, v2);
|
||||
VMULQ_F32(v0, v1, q0);
|
||||
#endif
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
// Newton-Raphson: Xn+1 = Xn*(3-d*Xn²)/2 converge to 1/sqrt(d) with X0 = result of VSQRTE
|
||||
// and VSQRTS is (3-A*B)/2
|
||||
// so VSQRTE(d) -> X is initial step
|
||||
// VSQRTS(d,X*X)*X -> X loop
|
||||
// than d*X -> SQRT(d) (because X ~ 1/sqrt(d))
|
||||
VRSQRTEQ_F32(v2, q0); // v2 = X0 (=X), q0 = d
|
||||
VMULQ_F32(v1, v2, v2); // v1 = X0²
|
||||
VRSQRTSQ_F32(v1, v1, q0); // v1 = (3-d*X0²)/2
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X0*(3-d*X0²)/2 = X1
|
||||
VMULQ_F32(v1, v2, v2); // v1 = x1²
|
||||
VRSQRTSQ_F32(v1, v1, q0); // v1 = (3-d*X1²)/2
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X1*(3-d*X1²)/2 = X2
|
||||
if(!box86_dynarec_fastnan) {
|
||||
// need to preserve v0, in case it's == q0
|
||||
VMULQ_F32(v1, v2, q0); // v1 = X2*d ~ SQRT(d)
|
||||
if(v0<dyn->n.fpu_scratch || v0!=q0)
|
||||
q1 = v0; // v0 is a scratch register
|
||||
else
|
||||
q1 = fpu_get_scratch_quad(dyn); // need a new scratch
|
||||
VCEQQ_0_F32(q1, q0); // prepare mask, 111 when == 0.0
|
||||
VMOVQ_H32(v2, 0xff); // prepare +inf
|
||||
VSHRQ_U32(v2, v2, 1); // 0xff000000 -> 0x7f800000 == +inf
|
||||
VCEQQ_32(v2, v2, q0); // v2 mask: 111 when == +inf
|
||||
VORRQ(q1, q1, v2); // q1 mask: 111 when ==0 || == +inf
|
||||
VBICQ(v1, v1, q1); // mask value in result
|
||||
VANDQ(q1, q0, q1); // keep original value that are 0 or +inf
|
||||
VORRQ(v0, v1, q1); // copy over
|
||||
} else {
|
||||
VMULQ_F32(v0, v2, q0); // v0 = X2*d ~ SQRT(d)
|
||||
}
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
@@ -601,21 +680,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
#if 0
|
||||
VRSQRTEQ_F32(v0, q0);
|
||||
//step?
|
||||
#else
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
// more precise
|
||||
if(v0==q0)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = v0;
|
||||
VRSQRTEQ_F32(v2, q0);
|
||||
VMULQ_F32(v1, v2, q0);
|
||||
VRSQRTSQ_F32(v1, v1, v2);
|
||||
VMULQ_F32(v0, v1, v2);
|
||||
#endif
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
@@ -623,14 +688,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(q0 == v0)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = v0;
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(v2, q0);
|
||||
VRECPSQ_F32(v1, v2, q0);
|
||||
VMULQ_F32(v0, v2, v1);
|
||||
VRECPEQ_F32(v0, q0);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
@@ -719,16 +777,19 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0);
|
||||
GETGX(v0, 1);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(q0, v1);
|
||||
VRECPSQ_F32(q1, q0, v1);
|
||||
VMULQ_F32(q0, q0, q1);
|
||||
VRECPSQ_F32(q1, q0, v1);
|
||||
VMULQ_F32(q0, q0, q1);
|
||||
VMULQ_F32(v0, v0, q0);
|
||||
GETEX(q0, 0);
|
||||
GETGX(q1, 1);
|
||||
// use Gx * 1/Ex, using RECP
|
||||
// Newton-Raphson: Xn+1 = Xn*(2-d*Xn) converge to 1/d if X0 if result of VRECPE(d)
|
||||
// VRECPE is 2-A*B
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(v2, q0); // v2 = X0, q0 = d
|
||||
VRECPSQ_F32(v1, q0, v2); // v1 = 2-d*X0
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X0*(2-d*X0) = X1
|
||||
VRECPSQ_F32(v1, q0, v2); // v1 = 2-d*X1
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X1*(2-d*X1) = X2 ~ 1/d
|
||||
VMULQ_F32(q1, q1, v2);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPS Gx, Ex");
|
||||
@@ -810,7 +871,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOVD(q0+1, d1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1_64(q0+1, ed);
|
||||
}
|
||||
VMOVD(q0, d0);
|
||||
@@ -857,9 +918,13 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(q0+0, v0);
|
||||
VMOVD(q0+1, v1);
|
||||
if(!(v0&1) && (v1==(v0+1))) {
|
||||
q0 = v0; // no need to move the regs...
|
||||
} else {
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(q0+0, v0);
|
||||
VMOVD(q0+1, v1);
|
||||
}
|
||||
VQMOVN_S32(v0, q0);
|
||||
break;
|
||||
|
||||
@@ -882,7 +947,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOVD(v0, v1);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1_64(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -916,7 +981,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
ADD_IMM8(xSP, xSP, 4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
for (int i=0; i<4; ++i) {
|
||||
@@ -940,7 +1005,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
d0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1_16(d0, ed);
|
||||
}
|
||||
@@ -961,7 +1026,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
d0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1_16(d0, ed);
|
||||
}
|
||||
@@ -978,7 +1043,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
d0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1_16(d0, ed);
|
||||
}
|
||||
@@ -1104,7 +1169,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOVfrDx_32(ed, v0, 0);
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0); // there can be some bus error is storing the VFPU reg directly
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1118,11 +1183,11 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v0, ed, fixedaddress);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -1130,24 +1195,29 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F|(dyn->insts[ninst].x86.barrier?0:X_PEND)); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(3); \
|
||||
JUMP(addr+i32_, 1); \
|
||||
GETFLAGS; \
|
||||
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); \
|
||||
if(!dyn->insts[ninst].x86.barrier) \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i32_, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i32_, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
|
||||
case 0x80:
|
||||
@@ -1249,7 +1319,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
eb2 = ((ed&4)>>2); \
|
||||
BFI(eb1, x3, eb2*8, 8); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);\
|
||||
STRB_IMM9(x3, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
@@ -1373,7 +1443,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
MOV_REG_ASR_IMM5(x1, gd, 5); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x1, ed, x1, 2); //(&ed)+=r1*4;
|
||||
LDR_IMM9(x1, x1, fixedaddress);
|
||||
@@ -1396,13 +1466,11 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTB(x3, xECX, 0);
|
||||
GETEDW(x14, x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETED;
|
||||
GETGD;
|
||||
MOV_REG(x2, gd);
|
||||
CALL(shld32, ed, (wback?(1<<wback):0));
|
||||
emit_shld32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
@@ -1431,7 +1499,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
MOV_REG_ASR_IMM5(x1, gd, 5); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
LDR_IMM9(x1, x3, fixedaddress);
|
||||
@@ -1495,7 +1563,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fxsave, -1, 0);
|
||||
}
|
||||
@@ -1507,7 +1575,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fxrstor, -1, 0);
|
||||
}
|
||||
@@ -1523,7 +1591,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
LDR_IMM9(ed, xEmu, offsetof(x86emu_t, mxcsr));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, mxcsr));
|
||||
STR_IMM9(x14, ed, fixedaddress);
|
||||
}
|
||||
@@ -1606,7 +1674,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
MOV_REG_ASR_IMM5(x1, gd, 5); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
wback = x3;
|
||||
@@ -1638,7 +1706,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
UXTB(gd, eb1, eb2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDRB_IMM9(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1650,7 +1718,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
UXTH(gd, ed, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1666,7 +1734,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1686,7 +1754,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1716,7 +1784,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1746,7 +1814,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1784,7 +1852,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL);
|
||||
MOV_REG_ASR_IMM5(x1, gd, 5); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
LDR_IMM9(x1, x3, fixedaddress);
|
||||
@@ -1856,7 +1924,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
SXTB(gd, eb1, eb2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSB_IMM8(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1868,7 +1936,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
SXTH(gd, ed, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSH_IMM8(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1935,7 +2003,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd); // doesn't exist
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
STR_IMM9(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1948,7 +2016,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
VMOVtoDx_16(d0, u8, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = (F8)&3;
|
||||
VLD1LANE_16(d0, wback, u8);
|
||||
}
|
||||
@@ -1962,7 +2030,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
u8 = (F8)&3;
|
||||
VMOVfrDx_U16(gd, d0, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-8, 0, 0, NULL);
|
||||
u8 = (F8)&3;
|
||||
LDRH_IMM8(gd, wback, fixedaddress+u8*2);
|
||||
}
|
||||
@@ -1971,68 +2039,182 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
i32 = -1;
|
||||
j32 = 0;
|
||||
GETGX(v0, 1);
|
||||
q0 = fpu_get_scratch_quad(dyn); // temporary storage
|
||||
// use stack as temporary storage
|
||||
SUB_IMM8(xSP, xSP, 4);
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
u8 = F8;
|
||||
// first two elements from Gx
|
||||
for (int i=0; i<2; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
VST1LANE_32(v0+(idx/2), xSP, idx&1);
|
||||
i32 = idx;
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
if((nextop&0xC0)!=0xC0) {
|
||||
// from memory
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
q0 = v0;
|
||||
// Low part
|
||||
switch (u8&0xf) {
|
||||
case 0b0000: VDUP_32(q0, v0, 0); break;
|
||||
case 0b0001: VREV64_32(q0, v0); break; // reverse low part
|
||||
case 0b0010: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v2, v0, 4); break;
|
||||
case 0b0011: VEXT_8(q0, v0+1, v0, 4); break;
|
||||
case 0b0100: break; // same
|
||||
case 0b0101: VDUP_32(q0, v0, 1); break;
|
||||
case 0b0110: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v2, v0, 4); break;
|
||||
case 0b0111: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v0+1, v2, 4); break;
|
||||
case 0b1000: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v2, v0+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0, v0, v0+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0, v0+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0, v0+1); break;
|
||||
case 0b1100: VEXT_8(q0, v0+1, v0, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b1101: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v0, v2, 4); break;
|
||||
case 0b1110: VMOVD(q0, v0+1); break;
|
||||
case 0b1111: VDUP_32(q0, v0+1, 1); break;
|
||||
}
|
||||
VLD1LANE_32(q0+(i/2), xSP, i&1);
|
||||
}
|
||||
i32 = -1;
|
||||
// next two from Ex
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
for (int i=2; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
VST1LANE_32(v1+(idx/2), xSP, idx&1);
|
||||
i32 = idx;
|
||||
// High part
|
||||
if(((u8>>4)&3) == ((u8>>6)&3)) {
|
||||
if((u8>>4)&3) {
|
||||
ADD_IMM8(x3, wback, ((u8>>4)&3)*4);
|
||||
}
|
||||
VLD1LANE_32(q0+(i/2), xSP, i&1);
|
||||
VLD1ALL_32(q0+1, ((u8>>4)&3)?x3:wback);
|
||||
} else {
|
||||
if((u8>>4)&3) {
|
||||
ADD_IMM8(x3, wback, ((u8>>4)&3)*4);
|
||||
}
|
||||
VLD1LANE_32(q0+1, ((u8>>4)&3)?x3:wback, 0);
|
||||
if((u8>>6)&3) {
|
||||
ADD_IMM8(x3, wback, ((u8>>6)&3)*4);
|
||||
}
|
||||
VLD1LANE_32(q0+1, ((u8>>6)&3)?x3:wback, 1);
|
||||
}
|
||||
} else {
|
||||
for (int i=2; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
ADD_IMM8(x2, ed, idx*4);
|
||||
i32 = idx;
|
||||
// from register
|
||||
wback = 0; ed = nextop&7;
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
u8 = F8;
|
||||
if((v0==v1) && ((u8==0) || (u8==0b01010101) || (u8==0b10101010) || (u8==0b11111111))) {
|
||||
// same value duplicated all along
|
||||
q0 = v0;
|
||||
VDUPQ_32(v0, v0+((u8>>1)&1), u8&1);
|
||||
} else if ((v0==v1) && (u8==0b01000100)) {
|
||||
q0 = v0;
|
||||
VMOVD(v0+1, v0);
|
||||
} else if ((v0==v1) && (u8==0b11101110)) {
|
||||
q0 = v0;
|
||||
VMOVD(v0, v0+1);
|
||||
} else if ((v0==v1) && (u8==0b10110001)) {
|
||||
q0 = v0;
|
||||
VREV64Q_32(v0, v0);
|
||||
} else if ((v0==v1) && (u8==0b01001110)) {
|
||||
q0 = v0;
|
||||
VSWP(v0, v0+1);
|
||||
} else if ((v0==v1) && (u8==0b11011000)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0, v0+1);
|
||||
} else if ((v0==v1) && (u8==0b00100111)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0+1, v0);
|
||||
} else if ((v0==v1) && (u8==0b01110010)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0, v0+1);
|
||||
VREV64Q_32(v0, v0);
|
||||
} else if ((v0==v1) && (u8==0b10001101)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0+1, v0);
|
||||
VREV64Q_32(v0, v0);
|
||||
} else {
|
||||
if(v1!=v0)
|
||||
q0 = v0; // no need for temp storage
|
||||
else if((u8&0b10100000)==0b10100000)
|
||||
q0 = v0; // no need for temp if only low/low and high/high are shuffled
|
||||
else
|
||||
q0 = fpu_get_scratch_quad(dyn); // temporary storage
|
||||
// Low part
|
||||
switch (u8&0xf) {
|
||||
case 0b0000: VDUP_32(q0, v0, 0); break;
|
||||
case 0b0001: VREV64_32(q0, v0); break; // reverse low part
|
||||
case 0b0010: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v2, v0, 4); break;
|
||||
case 0b0011: VEXT_8(q0, v0+1, v0, 4); break;
|
||||
case 0b0100: VMOVD(q0, v0); break; // same
|
||||
case 0b0101: VDUP_32(q0, v0, 1); break;
|
||||
case 0b0110: VEXT_8(q0, v0, v0+1, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b0111: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v0+1, v2, 4); break;
|
||||
case 0b1000: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v2, v0+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0, v0, v0+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0, v0+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0, v0+1); break;
|
||||
case 0b1100: VEXT_8(q0, v0+1, v0, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b1101: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v0, v2, 4); break;
|
||||
case 0b1110: VMOVD(q0, v0+1); break;
|
||||
case 0b1111: VDUP_32(q0, v0+1, 1); break;
|
||||
}
|
||||
// High part
|
||||
switch ((u8>>4)&0xf) {
|
||||
case 0b0000: VDUP_32(q0+1, v1, 0); break;
|
||||
case 0b0001: VREV64_32(q0+1, v1); break; // reverse low part
|
||||
case 0b0010: VREV64_32(v2, v1+1);
|
||||
VEXT_8(q0+1, v2, v1, 4); break;
|
||||
case 0b0011: VEXT_8(q0+1, v1+1, v1, 4); break;
|
||||
case 0b0100: VMOVD(q0+1, v1); break; // same
|
||||
case 0b0101: VDUP_32(q0+1, v1, 1); break;
|
||||
case 0b0110: VEXT_8(q0+1, v1, v1+1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b0111: VREV64_32(v2, v1);
|
||||
VEXT_8(q0+1, v1+1, v2, 4); break;
|
||||
case 0b1000: VREV64_32(v2, v1);
|
||||
VEXT_8(q0+1, v2, v1+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0+1, v1, v1+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0+1, v1+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0+1, v1+1); break;
|
||||
case 0b1100: VEXT_8(q0+1, v1+1, v1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b1101: VREV64_32(v2, v1+1);
|
||||
VEXT_8(q0+1, v1, v2, 4); break;
|
||||
case 0b1110: VMOVD(q0+1, v1+1); break;
|
||||
case 0b1111: VDUP_32(q0+1, v1+1, 1); break;
|
||||
}
|
||||
VLD1LANE_32(q0+(i/2), x2, i&1);
|
||||
}
|
||||
}
|
||||
ADD_IMM8(xSP, xSP, 4);
|
||||
VMOVQ(v0, q0);
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x1, wback, fixedaddress+0);
|
||||
LDR_IMM9(x2, wback, fixedaddress+4);
|
||||
CMPS_REG_LSL_IMM5(xEAX, x1, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x2, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
STR_IMM9(xEBX, wback, fixedaddress+0);
|
||||
STR_IMM9(xECX, wback, fixedaddress+4);
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x1);
|
||||
MOV_REG(xEDX, x2);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x1, wback, fixedaddress+0);
|
||||
LDR_IMM9(x2, wback, fixedaddress+4);
|
||||
CMPS_REG_LSL_IMM5(xEAX, x1, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x2, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
STR_IMM9(xEBX, wback, fixedaddress+0);
|
||||
STR_IMM9(xECX, wback, fixedaddress+4);
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x1);
|
||||
MOV_REG(xEDX, x2);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -2250,7 +2432,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
} else {
|
||||
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1_64(v0, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -28,7 +29,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint8_t wback, u8;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
@@ -184,7 +185,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
@@ -197,7 +198,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
@@ -209,7 +210,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP1(xEAX+(nextop&7));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
}
|
||||
@@ -260,6 +261,15 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA8:
|
||||
INST_NAME("TEST AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTB(x1, xEAX, 0);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
@@ -269,7 +279,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
@@ -296,16 +306,12 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
|
||||
}
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst!=dyn->size-1) {
|
||||
} else {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
BARRIER(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
@@ -315,7 +321,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -28,16 +29,30 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
uint8_t wback, wb1, wb2, wb, eb1, eb2;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
MAYUSE(wback);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("ADD GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -137,6 +152,16 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, ed, gd, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -347,7 +372,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
@@ -360,7 +385,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
@@ -372,7 +397,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP1((xEAX+(nextop&7)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
}
|
||||
@@ -400,6 +425,24 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(xEAX, x2, 0);
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV GS:Eb, Ib");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= u8
|
||||
u8 = F8;
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
MOVW(x3, u8);
|
||||
BFI(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
MOVW(x3, u8);
|
||||
STRB_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
@@ -409,7 +452,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
@@ -422,14 +465,14 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEDO2(x14);
|
||||
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEDO2(x14);
|
||||
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
@@ -597,7 +640,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
|
||||
@@ -33,12 +33,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int lock;
|
||||
int fixedaddress;
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u8);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(lock);
|
||||
while(opcode==0x66) opcode = F8; // "unlimited" 0x66 as prefix for variable sized NOP
|
||||
if(opcode==0x2E) opcode = F8; // cs: is ignored
|
||||
if((opcode==0x26) || (opcode==0x2E) || (opcode==0x36) || (opcode==0x3E)) opcode = F8; // segment prefix are ignored
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
@@ -175,6 +177,12 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PUSH DS");
|
||||
MOVW(x1, offsetof(x86emu_t, segs[_DS]));
|
||||
LDRH_REG(x2, xEmu, x1);
|
||||
PUSH16(x2, xESP);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
@@ -295,7 +303,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg16");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
@@ -310,7 +318,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg16");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
@@ -510,7 +518,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
GETGD;
|
||||
UXTH(x14, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
#if 0
|
||||
MARKLOCK;
|
||||
// do the swap with exclusive locking
|
||||
@@ -537,8 +545,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BFI(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, &lock);
|
||||
STRH_IMM8(gd, ed, fixedaddress);
|
||||
if(lock) {DMB_ISH();}
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
@@ -551,7 +560,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BFI(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, &lock);
|
||||
if(lock) {DMB_ISH();}
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
BFI(gd, x1, 0, 16);
|
||||
}
|
||||
@@ -565,7 +575,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
BFI(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
STRH_IMM8(x1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -578,7 +588,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
STRH_REG(ed, xEmu, x2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
STRH_REG(x1, xEmu, x2);
|
||||
@@ -681,6 +691,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, 2);
|
||||
UXTH(x1, xEAX, 0);
|
||||
LDRHAI_REG_LSL_IMM5(x2, xEDI, x3);
|
||||
@@ -791,7 +802,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOVW(x1, u16);
|
||||
BFI(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
u16 = F16;
|
||||
MOVW(x1, u16);
|
||||
STRH_IMM8(x1, ed, fixedaddress);
|
||||
@@ -898,6 +909,10 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec66F0(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
@@ -928,7 +943,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xA7:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3, 2);
|
||||
@@ -964,7 +980,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xAF:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3, 2);
|
||||
@@ -991,6 +1008,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("CMC");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
XOR_IMM8(xFlags, xFlags, 1<<F_CF);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -1045,8 +1069,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ORR_REG_LSL_IMM5(x2, x2, xEDX, 16);
|
||||
UDIV(x3, x2, ed);
|
||||
MLS(x14, x3, ed, x2); // x14 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFI(xEAX, x3, 1, 16);
|
||||
BFI(xEDX, x14, 1, 16);
|
||||
BFI(xEAX, x3, 0, 16);
|
||||
BFI(xEDX, x14, 0, 16);
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
@@ -1086,14 +1110,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
emit_dec16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
|
||||
+269
-132
@@ -27,7 +27,7 @@
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7, w); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL); \
|
||||
a = fpu_get_scratch_quad(dyn); \
|
||||
VLD1Q_8(a, ed); \
|
||||
}
|
||||
@@ -71,7 +71,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -89,7 +89,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 255-16, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 255-16, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -109,10 +109,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -129,11 +129,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v0, ed, fixedaddress);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0+1, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0+1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -159,7 +159,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0+1, v1+1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023-4, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023-4, 3, 0, NULL);
|
||||
VLDR_64(v0+1, ed, fixedaddress+4);
|
||||
}
|
||||
break;
|
||||
@@ -174,10 +174,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0+1, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0+1,x2, x3);
|
||||
@@ -194,11 +194,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v0+1, ed, fixedaddress);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0+1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -233,7 +233,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -262,7 +262,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1Q_64(q1, ed);
|
||||
v0 = q1;
|
||||
}
|
||||
@@ -469,7 +469,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);\
|
||||
LDRH_IMM8_COND(YES, x1, ed, fixedaddress); \
|
||||
ed = x1; \
|
||||
} \
|
||||
@@ -619,17 +619,55 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("ADDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VADD_F64(v0, v0, q0);
|
||||
VADD_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
VMSR(x14); // restore fpscr
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VMUL_F64(v0, v0, q0);
|
||||
VMUL_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
VMSR(x14); // restore fpscr
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPD2PS Gx, Ex");
|
||||
@@ -656,9 +694,28 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SUBPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VSUB_F64(v0, v0, q0);
|
||||
VSUB_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
VMSR(x14); // restore fpscr
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINPD Gx, Ex");
|
||||
@@ -677,9 +734,28 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VDIV_F64(v0, v0, q0);
|
||||
VDIV_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPSCR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
VMSR(x14); // restore fpscr
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPD Gx, Ex");
|
||||
@@ -817,7 +893,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0+1, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0+1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -830,7 +906,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(q0+1, q1+1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023-8, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023-8, 3, 0, NULL);
|
||||
VLDR_64(q0+1, ed, fixedaddress+8);
|
||||
}
|
||||
break;
|
||||
@@ -853,7 +929,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1Q_64(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -866,51 +942,116 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
u8 = F8;
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(u8==0x4E) {
|
||||
if ((u8==0) || (u8==0b01010101) || (u8==0b10101010) || (u8==0b11111111)) {
|
||||
VDUPQ_32(v0, v1+((u8>>1)&1), u8&1);
|
||||
} else if (u8==0b01000100) {
|
||||
VMOVD(v0+1, v1);
|
||||
VMOVD(v0, v1);
|
||||
} else if (u8==0b11101110) {
|
||||
VMOVD(v0, v1+1);
|
||||
VMOVD(v0+1, v1+1);
|
||||
} else if (u8==0b10110001) {
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if (u8==0b01010001) {
|
||||
VDUP_32(v0+1, v1, 1);
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if (u8==0b00011011) {
|
||||
VREV64Q_32(v0, v1);
|
||||
VSWP(v0, v0+1);
|
||||
} else if (u8==0b01001110) {
|
||||
if(v0==v1) {
|
||||
VSWP(v0, v0+1);
|
||||
} else {
|
||||
VMOVD(v0, v1+1);
|
||||
VMOVD(v0+1, v1);
|
||||
}
|
||||
} else if (u8==0b11011000) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VMOVQ(v0, v1);
|
||||
VTRN_32(v0, v0+1);
|
||||
} else if (u8==0b00100111) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VMOVQ(v0, v1);
|
||||
VTRN_32(v0+1, v0);
|
||||
} else if (u8==0b10001101) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VREV64Q_32(v0, v1); // 10 11 00 01
|
||||
VTRN_32(v0, v0+1); // 10 00 11 01
|
||||
} else if (u8==0b01110010) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VREV64Q_32(v0, v1); // 10 11 00 01
|
||||
VTRN_32(v0+1, v0); // 01 11 00 10
|
||||
} else {
|
||||
uint32_t swp[4] = {
|
||||
(0)|(1<<8)|(2<<16)|(3<<24),
|
||||
(4)|(5<<8)|(6<<16)|(7<<24),
|
||||
(8)|(9<<8)|(10<<16)|(11<<24),
|
||||
(12)|(13<<8)|(14<<16)|(15<<24)
|
||||
};
|
||||
q0 = fpu_get_scratch_quad(dyn); // temporary storage
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
if(v0==v1) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else
|
||||
q1 = v1;
|
||||
uint32_t a1, a2, a3, a4;
|
||||
a1 = swp[(u8>>(0*2))&3];
|
||||
a2 = swp[(u8>>(1*2))&3];
|
||||
MOV32(x2, a1);
|
||||
if(a1==a2) {MOV_REG(x3, x2);} else {MOV32(x3, a2);}
|
||||
VMOVtoV_D(d0, x2, x3);
|
||||
VTBL2_8(v0+0, q1, d0);
|
||||
a3 = swp[(u8>>(2*2))&3];
|
||||
a4 = swp[(u8>>(3*2))&3];
|
||||
if(a3!=a1 || a4!=a2) {
|
||||
if(a3!=a1) {
|
||||
if(a3==a2) {MOV_REG(x2, x3);} else {MOV32(x2, a3);}
|
||||
}
|
||||
if(a4!=a2) {
|
||||
if(a4==a3) {MOV_REG(x3, x2);} else {MOV32(x3, a4);}
|
||||
}
|
||||
VMOVtoV_D(d0, x2, x3);
|
||||
if(v1!=v0)
|
||||
q0 = v0; // no need for temp storage
|
||||
else if((u8&0xf)==((u8>>4)&0xf))
|
||||
q0 = v0;
|
||||
// Low part
|
||||
switch (u8&0xf) {
|
||||
case 0b0000: VDUP_32(q0, v1, 0); break;
|
||||
case 0b0001: VREV64_32(q0, v1); break; // reverse low part
|
||||
case 0b0010: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0, d0, v1, 4); break;
|
||||
case 0b0011: VEXT_8(q0, v1+1, v1, 4); break;
|
||||
case 0b0100: VMOVD(q0, v1); break; // same
|
||||
case 0b0101: VDUP_32(q0, v1, 1); break;
|
||||
case 0b0110: VEXT_8(q0, v1, v1+1, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b0111: VREV64_32(d0, v1);
|
||||
VEXT_8(q0, v1+1, d0, 4); break;
|
||||
case 0b1000: VREV64_32(d0, v1);
|
||||
VEXT_8(q0, d0, v1+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0, v1, v1+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0, v1+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0, v1+1); break;
|
||||
case 0b1100: VEXT_8(q0, v1+1, v1, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b1101: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0, v1, d0, 4); break;
|
||||
case 0b1110: VMOVD(q0, v1+1); break;
|
||||
case 0b1111: VDUP_32(q0, v1+1, 1); break;
|
||||
}
|
||||
VTBL2_8(v0+1, q1, d0);
|
||||
// High part
|
||||
if((u8&0xf)==((u8>>4)&0xf)) {
|
||||
VMOVD(q0+1, q0);
|
||||
} else switch ((u8>>4)&0xf) {
|
||||
case 0b0000: VDUP_32(q0+1, v1, 0); break;
|
||||
case 0b0001: VREV64_32(q0+1, v1); break; // reverse low part
|
||||
case 0b0010: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0+1, d0, v1, 4); break;
|
||||
case 0b0011: VEXT_8(q0+1, v1+1, v1, 4); break;
|
||||
case 0b0100: VMOVD(q0+1, v1); break; // same
|
||||
case 0b0101: VDUP_32(q0+1, v1, 1); break;
|
||||
case 0b0110: VEXT_8(q0+1, v1, v1+1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b0111: VREV64_32(d0, v1);
|
||||
VEXT_8(q0+1, v1+1, d0, 4); break;
|
||||
case 0b1000: VREV64_32(d0, v1);
|
||||
VEXT_8(q0+1, d0, v1+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0+1, v1, v1+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0+1, v1+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0+1, v1+1); break;
|
||||
case 0b1100: VEXT_8(q0+1, v1+1, v1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b1101: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0+1, v1, d0, 4); break;
|
||||
case 0b1110: VMOVD(q0+1, v1+1); break;
|
||||
case 0b1111: VDUP_32(q0+1, v1+1, 1); break;
|
||||
}
|
||||
VMOVQ(v0, q0);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if ((u8==0) || (u8==0b01010101) || (u8==0b10101010) || (u8==0b11111111)) {
|
||||
if(u8&3) {
|
||||
ADD_IMM8(x3, ed, (u8&3)*4);
|
||||
}
|
||||
VLD1QALL_32(v0, (u8&3)?x3:ed);
|
||||
} else {
|
||||
for (int i=0; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
@@ -919,8 +1060,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
VLD1LANE_32(v0+(i/2), x2, i&1);
|
||||
}
|
||||
} else {
|
||||
VLD1QALL_32(v0, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -932,7 +1071,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_16(q0, ed);
|
||||
}
|
||||
@@ -953,7 +1092,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_16(q0, ed);
|
||||
}
|
||||
@@ -970,7 +1109,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_16(q0, ed);
|
||||
}
|
||||
@@ -999,7 +1138,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_32(q0, ed);
|
||||
}
|
||||
@@ -1020,7 +1159,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_32(q0, ed);
|
||||
}
|
||||
@@ -1037,7 +1176,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_32(q0, ed);
|
||||
}
|
||||
@@ -1065,7 +1204,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q0, ed);
|
||||
}
|
||||
@@ -1086,7 +1225,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q0, ed);
|
||||
}
|
||||
@@ -1109,7 +1248,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q0, ed);
|
||||
}
|
||||
@@ -1130,7 +1269,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q0, ed);
|
||||
}
|
||||
@@ -1184,7 +1323,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVfrDx_32(ed, v0, 0);
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0); // to avoid Bus Error, using regular store
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -1196,7 +1335,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -1210,7 +1349,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7); // no need for extract
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
SBFX(x1, gd, 4, 12); // r1 = (gw>>4);
|
||||
ADD_REG_LSL_IMM5(x1, ed, x1, 1); //(&ed)+=r1*2;
|
||||
LDRH_IMM8(x1, x1, fixedaddress);
|
||||
@@ -1252,7 +1391,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0; // no need for extract
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
SBFX(x14, gd, 4, 12); // r14 = (gw>>4);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x14, 1); //(&ew)+=r14*2;
|
||||
LDRH_IMM8(x14, x3, fixedaddress);
|
||||
@@ -1300,7 +1439,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1320,7 +1459,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0; // no need for extract
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
SBFX(x14, gd, 4, 12); // r14 = (gw>>4);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x14, 1); //(&ew)+=r14*2;
|
||||
LDRH_IMM8(x14, x3, fixedaddress);
|
||||
@@ -1349,7 +1488,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
UXTB(x1, eb1, eb2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDRB_IMM9(x1, ed, fixedaddress);
|
||||
}
|
||||
BFI(gd, x1, 0, 16);
|
||||
@@ -1362,7 +1501,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX + (nextop&7);
|
||||
UXTH(x1, ed, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
}
|
||||
BFI(gd, x1, 0, 16);
|
||||
@@ -1378,7 +1517,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1398,7 +1537,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1427,7 +1566,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1456,7 +1595,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -1490,7 +1629,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0; // no need for extract
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
SBFX(x14, gd, 4, 12); // r14 = (gw>>4);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x14, 1); //(&ew)+=r14*2;
|
||||
LDRH_IMM8(x14, x3, fixedaddress);
|
||||
@@ -1549,11 +1688,18 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
SXTB(x1, eb1, eb2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSB_IMM8(x1, ed, fixedaddress);
|
||||
}
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0xBF:
|
||||
INST_NAME("MOVSX Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1);
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Gw, Ew");
|
||||
@@ -1562,7 +1708,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16); // GW <- EW
|
||||
emit_add16(dyn, ninst, x1, x2, x14, x3, 1);
|
||||
emit_add16(dyn, ninst, x2, x1, x14, x3, 1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
@@ -1571,42 +1717,34 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
u8 = F8;
|
||||
u8 = F8&7;
|
||||
// 0
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0, v0);
|
||||
} else {
|
||||
VCMP_F64(v0, d0);
|
||||
}
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 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(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
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);
|
||||
// 1
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0+1, v0+1);
|
||||
} else {
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
}
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 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(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
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+1, x2, x2);
|
||||
@@ -1621,7 +1759,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX+(nextop&7);
|
||||
VMOVtoDx_16(v0+(u8/4), u8&3, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = (F8)&7;
|
||||
VLD1LANE_16(v0+(u8/4), wback, u8&3);
|
||||
}
|
||||
@@ -1635,7 +1773,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
u8 = (F8)&7;
|
||||
VMOVfrDx_U16(gd, v0+(u8/4), (u8&3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-14, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-14, 0, 0, NULL);
|
||||
u8 = (F8)&7;
|
||||
LDRH_IMM8(gd, wback, fixedaddress+u8*2);
|
||||
}
|
||||
@@ -1646,17 +1784,21 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0);
|
||||
u8 = F8;
|
||||
if(v0==v1 && u8==0) {
|
||||
VMOVD(v0+1, v0);
|
||||
if(v0==v1) {
|
||||
switch (u8&3) {
|
||||
case 0b00: VMOVD(v0+1, v0); break;
|
||||
case 0b01: VSWP(v0, v0+1); break;
|
||||
case 0b10: break;
|
||||
case 0b11: VMOVD(v0, v0+1); break;
|
||||
}
|
||||
} else {
|
||||
if(v0==v1)
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
q0 = v0;
|
||||
VMOVD(q0, v0+(u8&1));
|
||||
VMOVD(q0+1, v1+((u8>>1)&1));
|
||||
if(v0==v1) {
|
||||
VMOVQ(v0, q0);
|
||||
switch(u8&1) {
|
||||
case 0: break;
|
||||
case 1: VMOVD(v0, v0+1); break;
|
||||
}
|
||||
switch((u8>>1)&1) {
|
||||
case 0: VMOVD(v0+1, v1); break;
|
||||
case 1: VMOVD(v0+1, v1+1); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1688,13 +1830,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(v0, q1);
|
||||
VMOVD(v0+1, q1);
|
||||
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
|
||||
VMOVD(v0+1, v0);
|
||||
VQMOVN_S32(v0, v0); // 4*q1 in 16bits now
|
||||
VNEGN_16(v0, v0); // because we want SHR and not SHL
|
||||
VMOVD(v0+1, v0);
|
||||
VDUPQ_16(v0, q1, 0);
|
||||
VNEGNQ_16(v0, v0); // because we want SHR and not SHL
|
||||
VSHLQ_U16(q0, q0, v0);
|
||||
break;
|
||||
case 0xD2:
|
||||
@@ -1749,10 +1886,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
// can be unaligned sometimes
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(q0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, q0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -1938,7 +2075,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_64(v0, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode = F8;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
uint8_t ed, gd, u8;
|
||||
int fixedaddress;
|
||||
int32_t i32, j32;
|
||||
int16_t i16;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
switch(opcode) {
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
DMB_ISH();
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
DMB_ISH();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add16c(dyn, ninst, ed, i16, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 0x1);
|
||||
B_MARK(cNE);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_add16c(dyn, ninst, x1, i16, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
DMB_ISH();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x14, wback);
|
||||
BFI(x1, x14, 0, 8); // re-inject
|
||||
emit_add16c(dyn, ninst, x1, i16, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0); // put the whole value
|
||||
}
|
||||
DMB_ISH();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
DMB_ISH();
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
DMB_ISH();
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Ew
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 1);
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
DMB_ISH();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
MARK;
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETEW(x1);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 1);
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
DMB_ISH();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
MARK;
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// default to NO LOCK
|
||||
addr-=2;
|
||||
}
|
||||
DMB_ISH();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -29,9 +30,11 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
int fixedaddress;
|
||||
int cacheupd;
|
||||
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
nextop = F8;
|
||||
|
||||
@@ -132,20 +135,27 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
|
||||
@@ -190,7 +190,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -210,7 +210,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -230,7 +230,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -251,7 +251,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -273,7 +273,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -293,7 +293,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -313,7 +313,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -333,7 +333,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
|
||||
+177
-69
@@ -34,11 +34,15 @@ static const float f_pi = PI;
|
||||
static const float f_lg2 = LG2;
|
||||
static const float f_ln2 = LN2;
|
||||
|
||||
extern int arm_v8;
|
||||
|
||||
static const void* round_map[4] = {nearbyint, floor, ceil, trunc};
|
||||
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
@@ -50,6 +54,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j32);
|
||||
(void)u8;
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
@@ -69,9 +74,12 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMOV_64(v2, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("FXCH ST0");
|
||||
break;
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
@@ -81,17 +89,8 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
i1 = x87_get_cache(dyn, ninst, 1, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
@@ -106,6 +105,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VNEG_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
@@ -115,6 +115,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VABS_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -136,7 +137,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// 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;
|
||||
i2 = -dyn->n.x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
@@ -154,7 +155,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
B_MARK3(cEQ);
|
||||
} else {
|
||||
// simply move from cache reg to r2/r3
|
||||
v1 = dyn->x87reg[i1];
|
||||
v1 = dyn->n.x87reg[i1];
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
}
|
||||
// get exponant in r1
|
||||
@@ -199,6 +200,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
@@ -210,6 +212,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
@@ -221,6 +224,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
@@ -232,6 +236,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
@@ -243,6 +248,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
@@ -254,6 +260,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
@@ -263,41 +270,32 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMOV_8(v1, 0); // cannot use VMOV_i_F64
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// use C helper for now, nothing staightforward is available
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_frndint, -1, 0);
|
||||
/*
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
VCVT_S32_F64(x1, v1); // limit to 32bits....
|
||||
VCVT_F64_S32(v1, x1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
*/
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
//if(ST0.d!=0.0)
|
||||
// ST0.d = exp2(ST0.d)-1.0;
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(exp2, 0); // return is d0
|
||||
if((PK(0)==0xD9 && PK(1)==0xE8) && // next inst is FLD1
|
||||
(PK(2)==0xDE && PK(3)==0xC1)) {
|
||||
MESSAGE(LOG_DUMP, "Hack for fld1 / faddp st1, st0\n");
|
||||
VMOV_64(v1, 0);
|
||||
addr+=4;
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000); // 1.0
|
||||
VSUB_F64(v1, 0, v1);
|
||||
}
|
||||
#endif
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
@@ -307,24 +305,30 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d)*ST(1).d
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
INST_NAME("FPTAN");
|
||||
v2 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, 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;
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C1 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C1 C2 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
|
||||
// and want 1.0 = 0x3ff0000000000000
|
||||
// so 00111111 11110000 00000000 00000000....
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v2, 0b01110000);
|
||||
} else {
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
@@ -335,6 +339,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CALL_2D(atan2, 0);
|
||||
VMOV_64(v2, 0); //ST(1).d = atan2(ST1.d, ST0.d);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
@@ -342,13 +347,48 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1, 0);
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch_double(dyn);
|
||||
VDIV_F64(s0, v1, v2);
|
||||
// set rounding to Nearest
|
||||
MOVW(x2, 1); // Nearest
|
||||
VMRS(x1); // get fpscr
|
||||
MOV_REG(x14, x1);
|
||||
BFI(x1, x2, 22, 2); // inject new round
|
||||
VMSR(x1); // put new fpscr
|
||||
VCVTR_S32_F64(s0*2, s0); // => Q
|
||||
// set back rounding
|
||||
VMSR(x14);
|
||||
// get Q
|
||||
VMOVfrV(x14, s0*2);
|
||||
// Put back Q in a double
|
||||
VCVT_F64_S32(s0, s0*2);
|
||||
VMUL_F64(s0, s0, v2);
|
||||
VSUB_F64(v1, v1, s0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFC(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFI(x1, x14, 9, 1);
|
||||
// set C3 = Q1
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 14, 1);
|
||||
// Set C0 = Q2
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 8, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -357,6 +397,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SUB_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
@@ -365,13 +406,40 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ADD_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch_double(dyn);
|
||||
VDIV_F64(s0, v1, v2);
|
||||
VCVT_S32_F64(s0*2, s0); // => Q
|
||||
// get Q
|
||||
VMOVfrV(x14, s0*2);
|
||||
// Put back Q in a double
|
||||
VCVT_F64_S32(s0, s0*2);
|
||||
VMUL_F64(s0, s0, v2);
|
||||
VSUB_F64(v1, v1, s0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFC(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFI(x1, x14, 9, 1);
|
||||
// set C3 = Q1
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 14, 1);
|
||||
// Set C0 = Q2
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 8, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
@@ -382,21 +450,56 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(sin, 0);
|
||||
VSWP(v1, 0);
|
||||
CALL_1D(cos, 0);
|
||||
CALL_1D(cos, 0); // would it be faster to do sqrt(1-sin()²) ???
|
||||
VMOV_64(v2, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if(!arm_v8) {
|
||||
// check if finite first
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
// load round mode
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x2, x1, 10, 2); // extract round...
|
||||
MOV32(x1, round_map);
|
||||
LDR_REG_LSL_IMM5(x2, x1, x2, 2);
|
||||
VMOV_64(0, v1); // prepare call to fpu_round
|
||||
CALL_1DR(x2, x3, 0);
|
||||
VMOV_64(v1, 0);
|
||||
} else {
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VRINTR_F64(v1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
@@ -406,9 +509,15 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cEQ);
|
||||
VMOV_64(0, v2);
|
||||
CALL_1DD(trunc, exp2, 0);
|
||||
if(!arm_v8) {
|
||||
VMOV_64(0, v2);
|
||||
CALL_1DD(trunc, exp2, 0);
|
||||
} else {
|
||||
VRINTZ_F64(0, v2);
|
||||
CALL_1D(exp2, 0);
|
||||
}
|
||||
VMUL_F64(v1, v1, 0);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
@@ -416,9 +525,9 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOV_64(0, v1); // prepare call to sin
|
||||
CALL_1D(sin, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFF:
|
||||
@@ -427,9 +536,9 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOV_64(0, v1); // prepare call to cos
|
||||
CALL_1D(cos, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
|
||||
@@ -459,23 +568,24 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
if(!ST_IS_F(0)) {
|
||||
VCVT_F64_F32(v1, s0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
@@ -488,10 +598,10 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
@@ -507,10 +617,10 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
@@ -520,7 +630,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
@@ -531,14 +641,12 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1);
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x1, x1, 10, 2); // extract round
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, round));
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
@@ -547,7 +655,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw));
|
||||
|
||||
@@ -122,9 +122,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
MOVW(x1, 0);
|
||||
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFI(x2, x1, 15, 1); // B
|
||||
BFC(x2, 0, 8); // IE .. PE, SF, ES
|
||||
BFC(x2, 15, 1); // B
|
||||
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
@@ -188,7 +187,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -203,13 +202,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x14); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
@@ -229,13 +228,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
ed = x1;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
ed = x1; // will not be writen immediatly, so x1 is safe for now
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x1, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
@@ -254,13 +253,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// The FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x1, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
@@ -274,7 +273,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDR_IMM9(x2, ed, 0);
|
||||
@@ -284,28 +283,110 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
} else {
|
||||
#if 0
|
||||
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);
|
||||
#else
|
||||
v1 = x87_do_push(dyn, ninst, x2, NEON_CACHE_ST_D);
|
||||
// copy 10bytes of *ED to STld(0)
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, top));
|
||||
int a = -dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUB_IMM8(x3, x3, -a);
|
||||
} else {
|
||||
ADD_IMM8(x3, x3, a);
|
||||
}
|
||||
AND_IMM8(x3, x3, 7);
|
||||
}
|
||||
ADD_IMM8(x2, xEmu, offsetof(x86emu_t, fpu_ld)+offsetof(fpu_ld_t, ld));
|
||||
MOVW(x14, sizeof(fpu_ld_t));
|
||||
MLA(x2, x3, x14, x2);
|
||||
LDR_IMM9(x14, ed, 0);
|
||||
STR_IMM9(x14, x2, 0);
|
||||
LDR_IMM9(x14, ed, 4);
|
||||
STR_IMM9(x14, x2, 4);
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
STRH_IMM8(x14, x2, 8);
|
||||
// convert 10bytes -> double
|
||||
CALL_1RD(FromLD, ed, x2, (1<<x3)|(1<<xFlags)|(1<<x2));
|
||||
// store ref to STld(0).uref, but can be unaligned...
|
||||
VMOVfrV_D(x3, x14, 0);
|
||||
// also, store result to ST0
|
||||
VMOVD(v1, 0);
|
||||
STR_IMM9(x3, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld));
|
||||
STR_IMM9(x14, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld)+4);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
// get top in x3
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, top));
|
||||
int a = -dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUB_IMM8(x3, x3, -a);
|
||||
} else {
|
||||
ADD_IMM8(x3, x3, a);
|
||||
}
|
||||
AND_IMM8(x3, x3, 7);
|
||||
}
|
||||
// get STld(0)
|
||||
ADD_IMM8(x2, xEmu, offsetof(x86emu_t, fpu_ld)+offsetof(fpu_ld_t, ld));
|
||||
MOVW(x14, sizeof(fpu_ld_t));
|
||||
MLA(x2, x3, x14, x2);
|
||||
// compare uref with actual value, top is not used anymore, so x3 is free
|
||||
LDR_IMM9(x14, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld));
|
||||
LDR_IMM9(x3, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld)+4);
|
||||
VMOVtoV_D(v2, x14, x3);
|
||||
VCEQ_32(v2, v2, v1); // same?
|
||||
VMOVfrV_D(x14, x3, v2);
|
||||
TSTS_REG_LSL_IMM5(x14, x3, 0);
|
||||
B_MARK(cEQ); // different, do the conversion
|
||||
// same... copy STld(0).ld
|
||||
LDR_IMM9(x14, x2, 0);
|
||||
LDR_IMM9(x3, x2, 4);
|
||||
STR_IMM9(x14, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
LDRH_IMM8(x14, x2, 8);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
B_MARK2(c__);
|
||||
MARK;
|
||||
// different, call D2LD
|
||||
SUB_IMM8(xSP, xSP, 8);
|
||||
VSTR_64(v1, xSP, 0);
|
||||
PUSH(xSP, (1<<xEmu)|(1<<xFlags));
|
||||
ADD_IMM8(0, xSP, 8); //1st arg is &d
|
||||
if(ed!=x1) {
|
||||
MOV_REG_LSL_IMM5(x1, ed, 0); //2nd arg is ed
|
||||
}
|
||||
CALL_S(D2LD, -2, 0);
|
||||
POP(xSP, (1<<xEmu)|(1<<xFlags));
|
||||
ADD_IMM8(xSP, xSP, 8);
|
||||
MARK2;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -184,10 +184,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -200,10 +200,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -216,10 +216,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -233,10 +233,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -251,10 +251,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -267,10 +267,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -283,10 +283,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -299,10 +299,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
|
||||
@@ -80,17 +80,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
i1 = x87_get_cache(dyn, ninst, 0, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
@@ -166,10 +156,10 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress + 4);
|
||||
VMOVtoV_D(v1, x2, x3);
|
||||
@@ -178,7 +168,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistt64, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
@@ -188,10 +178,10 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -202,10 +192,10 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -215,28 +205,28 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1, 0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
ADD_IMM8(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
|
||||
@@ -166,11 +166,27 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v2, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
if(ST_IS_F(0)) {
|
||||
VNEG_F32_cond(cNE, v2, v2);
|
||||
} else {
|
||||
VNEG_F64_cond(cNE, v2, v2);
|
||||
}
|
||||
VMSR(x14); // restore fpscr
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
static const void* round_map[4] = {arm_fist64_0, arm_fist64_1, arm_fist64_2, arm_fist64_3};
|
||||
uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
@@ -31,7 +31,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t j32;
|
||||
uint8_t wback;
|
||||
uint8_t ed;
|
||||
int v0, v1, v2;
|
||||
int /*v0, */v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
@@ -39,7 +39,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v0);
|
||||
//MAYUSE(v0);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(nextop) {
|
||||
@@ -60,12 +60,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
ADD_IMM8(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
@@ -162,7 +162,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVtoV(v1, x1);
|
||||
@@ -176,13 +176,13 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x14); // get fpscr
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -204,12 +204,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x1, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -230,12 +230,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x1, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -257,7 +257,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbld, -1, 0);
|
||||
break;
|
||||
@@ -267,7 +267,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(parity) {
|
||||
LDRD_IMM8(x2, wback, 0); // x2/x3 is 64bits
|
||||
} else {
|
||||
@@ -281,48 +281,46 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Hack for FILD/FISTP i64");
|
||||
} else {
|
||||
// Save xFlags to use it as scratch...
|
||||
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
// set STll(0).ll=i64 and ref=ST(0).q later (emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top])
|
||||
// get TOP
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(xFlags, xFlags, -a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
SUB_IMM8(x1, x1, -a);
|
||||
AND_IMM8(x1, x1, 7);
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(xFlags, xFlags, a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
ADD_IMM8(x1, x1, a);
|
||||
AND_IMM8(x1, x1, 7);
|
||||
}
|
||||
ADD_REG_LSL_IMM5(xFlags, xEmu, xFlags, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(xFlags, xFlags, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, xFlags, 8); // save ll
|
||||
// ed (and so x1) is not use anymore.
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x1, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(x1, x1, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, x1, 8); // save ll
|
||||
// continue with conversion
|
||||
MOVS_REG_LSR_IMM5(x14, x3, 31); // x14 is sign bit
|
||||
B_MARK(cEQ); // no NEG is no sign bit
|
||||
RSBS_IMM8(x2, x2, 0);
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
MARK;
|
||||
VMOVtoV(s0, x3);
|
||||
VMOVtoV(s0, x3); // last time x3 is used
|
||||
VCVT_F64_U32(v1, s0);
|
||||
VEOR(v2, v2, v2);
|
||||
MOVW(x1, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x1);
|
||||
MOVW(x3, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x3);
|
||||
VMUL_F64(v1, v1, v2); // v1 = double high part of i64
|
||||
VMOVtoV(s0, x2);
|
||||
VCVT_F64_U32(v2, s0);
|
||||
VADD_F64(v1, v1, v2);
|
||||
TSTS_IMM8(x14, 1);
|
||||
VNEG_F64_cond(cNE, v1, v1);
|
||||
VST1_64(v1, xFlags); // Store STll(0).ref
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
VST1_64(v1, x1); // Store STll(0).ref
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
@@ -330,7 +328,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 7: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ninst
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)dyn->insts[ninst-1].x86.addr==0xDF
|
||||
@@ -343,16 +341,51 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
#if 1
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0, NEON_CACHE_ST_D);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
fpu_get_scratch_double(dyn); // to alocate v0
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
#if 1
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(x14, x14, a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, offsetof(fpu_ll_t, sref));
|
||||
VLDR_64(v2, x14, 0);
|
||||
VCEQ_32(v2, v2, v1); // compare
|
||||
VMOVfrV_D(x2, x3, v2);
|
||||
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
|
||||
B_MARK(cEQ); // do the i64 conversion
|
||||
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
LDRD_IMM8(x2, x14, offsetof(fpu_ll_t, sq)); // load ll
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
// load round mode
|
||||
LDRH_IMM8(x14, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x2, x14, 10, 2); // extract round...
|
||||
MOV32(x14, round_map);
|
||||
LDR_REG_LSL_IMM5(x2, x14, x2, 2);
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1DR_U64(x2, x2, x3, x14, (1<<x1));
|
||||
MARK3;
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
#else
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// check STll(0).ref==ST(0).q so emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top]
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
@@ -380,7 +413,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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
|
||||
ORR_IMM8(x3, x2, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_U32_F64(s0, v2); // convert high part to U32
|
||||
@@ -407,6 +440,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK3;
|
||||
STR_IMM9(x2, x1, 0);
|
||||
STR_IMM9(x3, x1, 4);
|
||||
#endif
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x2, x3, 0);
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -63,9 +61,6 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -77,7 +72,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
MOV32(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -109,8 +104,6 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -145,9 +138,6 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -159,7 +149,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
MOV32(s3, c);
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -191,8 +181,6 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -227,9 +215,6 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -248,7 +233,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BIC_IMM8(s1, s1, ~c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
MOV32(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -281,8 +266,6 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -317,9 +300,6 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -354,8 +334,6 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -390,9 +368,6 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -427,8 +402,6 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -463,9 +436,6 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -501,8 +471,6 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -537,9 +505,6 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -551,7 +516,7 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
MOVW(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -583,8 +548,6 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -619,9 +582,6 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -633,7 +593,7 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
MOVW(s3, c);
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -665,8 +625,6 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -701,9 +659,6 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -715,7 +670,7 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
AND_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
MOVW(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
|
||||
@@ -76,7 +76,7 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit ADD32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.need_flags==X_PEND || dyn->insts[ninst].x86.need_flags==X_ALL)))
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.gen_flags==X_PEND || dyn->insts[ninst].x86.gen_flags==X_ALL)))
|
||||
{
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<256) {
|
||||
@@ -210,7 +210,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit SUB32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.need_flags==X_PEND || dyn->insts[ninst].x86.need_flags==X_ALL)))
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.gen_flags==X_PEND || dyn->insts[ninst].x86.gen_flags==X_ALL)))
|
||||
{
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<256) {
|
||||
|
||||
@@ -469,6 +469,7 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
@@ -521,6 +522,69 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHLD32 instruction, from s1, fill s2 , shift s3, store result in s1 using s4 and s3 as scratch
|
||||
void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shl32
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
CMPS_IMM8(s3, 0);
|
||||
IFX(F_OF) {
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_CF) {
|
||||
RSB_IMM8(s4, s3, 32);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVS_REG_LSL_REG(s1, s1, s3);
|
||||
} else {
|
||||
MOV_REG_LSL_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVW_COND(cCS, s4, 1);
|
||||
MOVW_COND(cCC, s4, 0);
|
||||
CMPS_IMM8(s3, 1);
|
||||
ORR_REG_LSR_IMM5_COND(cEQ, s4, s4, s1, 30);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
//else
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
RSB_IMM8(s3, s3, 32);
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSR_REG(s1, s1, s2, s3);
|
||||
} else {
|
||||
ORR_REG_LSR_REG(s1, s1, s2, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, 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)
|
||||
{
|
||||
|
||||
@@ -374,7 +374,7 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch. May destroy s2 also
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
@@ -401,10 +401,9 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
AND_IMM8(s2, 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);
|
||||
LDR_REG_LSR_IMM5(s4, s4, s2, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
|
||||
+145
-116
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
@@ -50,7 +51,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_add8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_add8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
@@ -70,7 +71,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_add32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -94,7 +95,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_or8(dyn, ninst, x1, x2, x14, x3);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
GETGB(x2);
|
||||
LDREXB(x1, wback);
|
||||
@@ -115,7 +116,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_or32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_or32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -140,7 +141,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_adc8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_adc8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
@@ -161,7 +162,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_adc32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_adc32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -186,7 +187,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_sbb8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
@@ -207,7 +208,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sbb32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_sbb32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -231,7 +232,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_and8(dyn, ninst, x1, x2, x14, x3);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
GETGB(x2);
|
||||
LDREXB(x1, wback);
|
||||
@@ -252,7 +253,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_and32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_and32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -276,7 +277,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_sub8(dyn, ninst, x1, x2, x14, x3, 0);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_sub8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
|
||||
@@ -296,7 +297,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sub32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_sub32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -320,7 +321,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_xor8(dyn, ninst, x1, x2, x14, x3);
|
||||
BFI(wback, ed, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
GETGB(x2);
|
||||
LDREXB(x1, wback);
|
||||
@@ -341,7 +342,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_xor32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
emit_xor32(dyn, ninst, x1, gd, x3, x14);
|
||||
@@ -351,6 +352,10 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
DMB_ISH();
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
return dynarec66F0(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
@@ -369,7 +374,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 0x3);
|
||||
@@ -410,7 +415,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
@@ -431,7 +436,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
@@ -452,7 +457,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
@@ -472,7 +477,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
@@ -492,7 +497,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 0x3);
|
||||
@@ -533,7 +538,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
LDREX(x1, wback);
|
||||
@@ -608,7 +613,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = x2;
|
||||
wb1 = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x2, wback);
|
||||
ed = x2;
|
||||
@@ -637,7 +642,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK3;
|
||||
DMB_ISH();
|
||||
// done, do the cmp now
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x1, x2, x3, x14);}
|
||||
break;
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
@@ -647,50 +652,68 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DMB_ISH();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
MARKLOCK;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
TSTS_IMM8(wback, 3); // can be unaligned it seems
|
||||
LDREX_COND(cEQ, x1, wback);
|
||||
LDR_IMM9_COND(cNE, x1, wback, 0);
|
||||
LDREXB_COND(cNE, x3, wback); // dummy read, to arm the write...
|
||||
} else {
|
||||
LDREX(x1, wback);
|
||||
}
|
||||
ed = x1;
|
||||
}
|
||||
CMPS_REG_LSL_IMM5(xEAX, ed, 0);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
if(wback) {
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
TSTS_IMM8(wback, 3);
|
||||
STREX_COND(cEQ, x14, gd, wback);
|
||||
STREXB_COND(cNE, x14, gd, wback);
|
||||
} else {
|
||||
STREX(x14, gd, wback);
|
||||
}
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
TSTS_IMM8(wback, 3); // anoying, all those test
|
||||
STR_IMM9_COND(cNE, gd, wback, 0);
|
||||
}
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
|
||||
} else {
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
|
||||
// same as no lock, all in regs...
|
||||
CMPS_REG_LSL_IMM5(xEAX, ed, 0);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
MOV_REG(x3, ed);
|
||||
MOV_REG(ed, gd);
|
||||
emit_cmp32(dyn, ninst, xEAX, x3, x1, x14);
|
||||
B_NEXT(c__);
|
||||
MARK;
|
||||
// EAX != Ed
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x3, x14);
|
||||
MOV_REG(xEAX, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
ed = x1;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
if(!fixedaddress) {
|
||||
// alignment is undetermined
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK2(cNE);
|
||||
MARKLOCK;
|
||||
// aligned
|
||||
LDREX(ed, wback);
|
||||
CMPS_REG_LSL_IMM5(xEAX, ed, 0);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STREX(x14, gd, wback);
|
||||
DMB_ISH();
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
B_MARK(c__);
|
||||
}
|
||||
// unaligned
|
||||
MARK2;
|
||||
LDR_IMM9(x1, wback, 0);
|
||||
LDREXB( x3, wback); // dummy read, to arm the write...
|
||||
CMPS_REG_LSL_IMM5(xEAX, ed, 0);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STREXB(x14, gd, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARK2(cNE);
|
||||
STR_IMM9(gd, wback, 0);
|
||||
DMB_ISH();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
// alignment is good
|
||||
LDREX(ed, wback);
|
||||
CMPS_REG_LSL_IMM5(xEAX, ed, 0);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STREX(x14, gd, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
DMB_ISH();
|
||||
}
|
||||
// end of EAX == Ed or EAX != Ed
|
||||
MARK;
|
||||
UFLAG_IF { MOV_REG(x2, xEAX); }
|
||||
MOV_REG(xEAX, ed);
|
||||
UFLAG_IF { emit_cmp32(dyn, ninst, x2, ed, x3, x14); }
|
||||
}
|
||||
// done
|
||||
B_MARK3(c__); // not next, in case its called with a LOCK prefix
|
||||
MARK;
|
||||
// EAX != Ed
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x3, x14);
|
||||
MOV_REG(xEAX, ed);
|
||||
MARK3
|
||||
DMB_ISH();
|
||||
break;
|
||||
case 0xB3:
|
||||
INST_NAME("LOCK BTR Ed, Gd");
|
||||
@@ -703,7 +726,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MOV_REG_ASR_IMM5(x1, gd, 5); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
wback = x3;
|
||||
@@ -739,7 +762,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095-32, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095-32, 0, 0, LOCK_LOCK);
|
||||
LDR_IMM9(x1, ed, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -762,7 +785,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOVW(gd, u8&0x1f);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
u8 = F8;
|
||||
ed = x1;
|
||||
MOVW(gd, u8&0x1f);
|
||||
@@ -793,7 +816,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOVW(gd, u8&0x1f);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
u8 = F8;
|
||||
ed = x1;
|
||||
MOVW(gd, u8&0x1f);
|
||||
@@ -829,7 +852,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MOV_REG_ASR_IMM5(x1, gd, 5); // r1 = (gd>>5);
|
||||
ADD_REG_LSL_IMM5(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
MARKLOCK;
|
||||
@@ -864,7 +887,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wb1 = 0;
|
||||
ed = x2;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x2, wback);
|
||||
wb1 = 1;
|
||||
@@ -896,7 +919,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK(cNE); // unaligned
|
||||
@@ -936,48 +959,54 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
DMB_ISH();
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 1);
|
||||
MARKLOCK;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
LDREXD_COND(cEQ, x2, wback);
|
||||
LDREX_COND(cNE, x2, wback);
|
||||
LDR_IMM9_COND(cNE, x3, wback, 4);
|
||||
} else {
|
||||
LDREXD(x2, wback);
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
LDREXD_COND(cEQ, x2, wback);
|
||||
LDR_IMM9_COND(cNE, x3, wback, 4);
|
||||
LDREX_COND(cNE, x2, wback);
|
||||
} else {
|
||||
LDREXD(x2, wback);
|
||||
}
|
||||
CMPS_REG_LSL_IMM5(xEAX, x2, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x3, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
MOV_REG(x2, xEBX);
|
||||
MOV_REG(x3, xECX);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STREXD_COND(cEQ, x14, x2, wback);
|
||||
STREX_COND(cNE, x14, x2, wback);
|
||||
} else {
|
||||
STREXD(x14, x2, wback);
|
||||
}
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STR_IMM9_COND(cNE, x3, wback, 4);
|
||||
}
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x2);
|
||||
MOV_REG(xEDX, x3);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
DMB_ISH();
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
CMPS_REG_LSL_IMM5(xEAX, x2, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x3, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
MOV_REG(x2, xEBX);
|
||||
MOV_REG(x3, xECX);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STREXD_COND(cEQ, x14, x2, wback);
|
||||
STREX_COND(cNE, x14, x2, wback);
|
||||
} else {
|
||||
STREXD(x14, x2, wback);
|
||||
}
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STR_IMM9_COND(cNE, x3, wback, 4);
|
||||
}
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x2);
|
||||
MOV_REG(xEDX, x3);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
DMB_ISH();
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -993,12 +1022,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_inc32(dyn, ninst, ed, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK(cNE); // unaligned
|
||||
@@ -1030,12 +1059,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 3);
|
||||
B_MARK(cNE); // unaligned
|
||||
|
||||
+100
-10
@@ -30,16 +30,20 @@
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3); \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
if(parity) { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL); \
|
||||
VLDR_64(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);\
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);\
|
||||
LDR_IMM9(x2, ed, fixedaddress+0); \
|
||||
LDR_IMM9(x3, ed, fixedaddress+4); \
|
||||
VMOVtoV_D(a, x2, x3); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
@@ -69,7 +73,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(v0, d0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -86,7 +90,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(d0, v0);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -101,7 +105,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(v0, d0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -128,7 +132,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
@@ -144,7 +148,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
@@ -159,7 +163,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSQRT_F64(v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -168,7 +184,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
@@ -176,7 +204,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
@@ -200,7 +240,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
@@ -219,7 +271,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
@@ -241,7 +305,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -276,7 +340,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -288,6 +352,24 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x86:
|
||||
case 0x87:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8A:
|
||||
case 0x8B:
|
||||
case 0x8C:
|
||||
case 0x8D:
|
||||
case 0x8E:
|
||||
case 0x8F:
|
||||
return dynarec0F(dyn, addr-1, ip, ninst, ok, need_epilog);
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -311,6 +393,14 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0);
|
||||
VMOV_64(v0, v1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -321,7 +411,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
a = b*2; \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2); \
|
||||
if(parity) { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0, NULL); \
|
||||
VLDR_32(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
GETED; \
|
||||
@@ -50,6 +50,9 @@
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -98,10 +101,17 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity && (v0<16)) {
|
||||
VEORQ(v0, v0, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(v0*2, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -128,9 +138,15 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(q0, d1);
|
||||
}
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity && (v0<16)) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VSTR_32(v0*2, ed, fixedaddress);
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -140,7 +156,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
@@ -156,7 +172,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
@@ -214,10 +230,10 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
@@ -243,10 +259,10 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
@@ -380,7 +396,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -485,7 +501,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -502,7 +518,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -539,7 +555,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1_64(v0, ed);
|
||||
}
|
||||
VEOR(v0+1, v0+1, v0+1);
|
||||
@@ -553,7 +569,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -614,6 +630,28 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ2DQ Gx, Em");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV_64(v0, v1);
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -629,10 +667,10 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -66,12 +67,12 @@ void arm_fxtract(x86emu_t* emu)
|
||||
}
|
||||
void arm_fprem(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
int64_t tmp64s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp64s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
emu->sw.f.F87_C1 = (tmp64s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp64s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
}
|
||||
void arm_frndint(x86emu_t* emu)
|
||||
{
|
||||
@@ -116,6 +117,43 @@ void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
}
|
||||
}
|
||||
|
||||
int64_t arm_fist64_0(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = nearbyint(d);
|
||||
return tmp;
|
||||
}
|
||||
int64_t arm_fist64_1(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = floor(d);
|
||||
return tmp;
|
||||
}
|
||||
int64_t arm_fist64_2(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = ceil(d);
|
||||
return tmp;
|
||||
}
|
||||
int64_t arm_fist64_3(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = trunc(d);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
@@ -126,7 +164,7 @@ void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
LD2D(&STld(0).ld, &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
}
|
||||
|
||||
@@ -142,7 +180,7 @@ void arm_fsave(x86emu_t* emu, uint8_t* ed)
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +191,7 @@ void arm_frstor(x86emu_t* emu, uint8_t* ed)
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
@@ -162,48 +200,48 @@ void arm_frstor(x86emu_t* emu, uint8_t* ed)
|
||||
void arm_fprem1(x86emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
int64_t tmp64s = lrint(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp64s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
emu->sw.f.F87_C1 = (tmp64s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp64s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
}
|
||||
|
||||
|
||||
// Get a FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn)
|
||||
{
|
||||
return dyn->fpu_scratch++; // return an Sx
|
||||
return dyn->n.fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Get a FPU double scratch reg
|
||||
int fpu_get_scratch_double(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i = (dyn->fpu_scratch+1)&(~1);
|
||||
dyn->fpu_scratch = i+2;
|
||||
int i = (dyn->n.fpu_scratch+1)&(~1);
|
||||
dyn->n.fpu_scratch = i+2;
|
||||
return i/2; // return a Dx
|
||||
}
|
||||
// Get a FPU quad scratch reg
|
||||
int fpu_get_scratch_quad(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->fpu_scratch>4) {
|
||||
if(dyn->fpu_extra_qscratch) {
|
||||
if(dyn->n.fpu_scratch>4) {
|
||||
if(dyn->n.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;
|
||||
dyn->n.fpu_extra_qscratch = fpu_get_reg_quad(dyn, NEON_CACHE_SCR, 0);
|
||||
return dyn->n.fpu_extra_qscratch;
|
||||
}
|
||||
int i = (dyn->fpu_scratch+3)&(~3);
|
||||
dyn->fpu_scratch = i+4;
|
||||
int i = (dyn->n.fpu_scratch+3)&(~3);
|
||||
dyn->n.fpu_scratch = i+4;
|
||||
return i/2; // Return a Dx, not a Qx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
if(dyn->fpu_extra_qscratch) {
|
||||
fpu_free_reg_quad(dyn, dyn->fpu_extra_qscratch);
|
||||
dyn->fpu_extra_qscratch = 0;
|
||||
dyn->n.fpu_scratch = 0;
|
||||
if(dyn->n.fpu_extra_qscratch) {
|
||||
fpu_free_reg_quad(dyn, dyn->n.fpu_extra_qscratch);
|
||||
dyn->n.fpu_extra_qscratch = 0;
|
||||
}
|
||||
}
|
||||
// Get a FPU double reg
|
||||
@@ -211,10 +249,13 @@ 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;
|
||||
while (dyn->n.fpuused[i] && (i<24)) ++i;
|
||||
assert(i<24);
|
||||
|
||||
dyn->n.fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.news |= (1<<i);
|
||||
return i+FPUFIRST; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
@@ -222,7 +263,7 @@ void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = 0;
|
||||
dyn->n.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;
|
||||
}
|
||||
@@ -230,36 +271,42 @@ void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
|
||||
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;
|
||||
while ((dyn->n.fpuused[i] || dyn->n.fpuused[i+1]) && (i<24)) i+=2;
|
||||
assert(i<24);
|
||||
dyn->n.fpuused[i] = dyn->n.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;
|
||||
dyn->n.news |= (3<<i);
|
||||
return i+FPUFIRST; // Return a Dx, not a Qx
|
||||
}
|
||||
// Free a FPU quad reg
|
||||
void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
|
||||
dyn->n.fpuused[i] = dyn->n.fpuused[i+1] = 0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
dyn->n.neoncache[i+1].v = 0;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_reg = 0;
|
||||
dyn->n.fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i) {
|
||||
dyn->fpuused[i]=0;
|
||||
dyn->n.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;
|
||||
if (dyn->insts[ninst].n.swapped) {
|
||||
if(dyn->insts[ninst].n.combined1 == a)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if(dyn->insts[ninst].n.combined2 == a)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
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)
|
||||
@@ -283,114 +330,141 @@ int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if(a+dyn->insts[ninst].n.stack_next-st<0)
|
||||
/*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;
|
||||
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)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
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)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a, int st)
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a)
|
||||
{
|
||||
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)
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
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)
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
|
||||
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
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(a == dyn->insts[ninst].n.combined1 || a == dyn->insts[ninst].n.combined2) {
|
||||
if(a == dyn->insts[ninst].n.combined1) {
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
} else
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_combined, ninst=%d combined%c %d i=%d (stack:%d/%d)\n", ninst, (a == dyn->insts[ninst].n.combined2)?'2':'1', a ,i, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
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);
|
||||
if(!dyn->insts[ninst].n.barrier)
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, a-dyn->insts[ninst].n.stack_push);
|
||||
// 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);
|
||||
if(a-dyn->insts[ninst].n.stack_pop>=0)
|
||||
if(!dyn->insts[ninst+1].n.barrier)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, a-dyn->insts[ninst].n.stack_pop);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void neoncache_promote_double_internal(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)
|
||||
{
|
||||
if(dyn->insts[ninst+1].n.barrier)
|
||||
return;
|
||||
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);
|
||||
a+=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: add pop'd ST (going backward)
|
||||
int i = neoncache_get_st_f(dyn, ninst, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d, i=%d\n", ninst, a, 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);
|
||||
if(dyn->insts[ninst].n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
} else {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
|
||||
--ninst;
|
||||
if(ninst<0 || a<0 || dyn->insts[ninst].n.barrier)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
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);
|
||||
while((ninst!=-1) && (ninst<maxinst) && (a>=0)) {
|
||||
a+=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: add push'd ST (going forward)
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && dyn->insts[ninst].n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d(%d/%d), i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop, 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);
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && !dyn->insts[ninst].n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
++ninst;
|
||||
a-=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: remove pop'd ST (going forward)
|
||||
if(dyn->insts[ninst].x86.has_next && !dyn->insts[ninst].n.barrier)
|
||||
++ninst;
|
||||
else
|
||||
ninst=-1;
|
||||
}
|
||||
neoncache_promote_double(dyn, ninst, a, st);
|
||||
if(ninst==maxinst)
|
||||
neoncache_promote_double(dyn, ninst, a);
|
||||
}
|
||||
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
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);
|
||||
int i = neoncache_get_current_st_f(dyn, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d i=%d\n", ninst, a, 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;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// 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(dyn->n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d swapped! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
a = dyn->n.combined2;
|
||||
else if(dyn->n.combined2 == a)
|
||||
a = dyn->n.combined1;
|
||||
} else {
|
||||
//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);
|
||||
else if(dyn->n.combined2 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined1);
|
||||
}
|
||||
}
|
||||
if(!ninst) return;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, ninst, a, st);
|
||||
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
|
||||
if(!ninst || a<0) return;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, ninst, a);
|
||||
}
|
||||
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
@@ -403,6 +477,158 @@ int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
if(dyn->insts[ninst].pred[i]==pred)
|
||||
return pred;
|
||||
return -1;
|
||||
}
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst) {
|
||||
if((ninst<=0) || !dyn->insts[ninst].pred_sz)
|
||||
return -1;
|
||||
if(isPred(dyn, ninst, ninst-1)!=-1)
|
||||
return ninst-1;
|
||||
return dyn->insts[ninst].pred[0];
|
||||
}
|
||||
|
||||
static int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int i2 = dyn->insts[ninst].x86.jmp_insts;
|
||||
if(i2<0)
|
||||
return 1;
|
||||
if((dyn->insts[i2].x86.barrier&BARRIER_FLOAT))
|
||||
return ((dyn->insts[ninst].x86.barrier&BARRIER_FLOAT))?0:1; // if the barrier as already been apply, no transform needed
|
||||
int ret = 0;
|
||||
if(!i2) { // just purge
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 1;
|
||||
}
|
||||
for(int i=0; i<24 && !ret; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Check if ninst can be compatible to i2
|
||||
if(dyn->insts[ninst].n.stack_next != dyn->insts[i2].n.stack-dyn->insts[i2].n.stack_push) {
|
||||
return 1;
|
||||
}
|
||||
neoncache_t cache_i2 = dyn->insts[i2].n;
|
||||
neoncacheUnwind(&cache_i2);
|
||||
|
||||
for(int i=0; i<24; ++i) {
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
ret = 1;
|
||||
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
|
||||
if(dyn->insts[ninst].n.neoncache[i].n!=cache_i2.neoncache[i].n) { // not the same x86 reg
|
||||
ret = 1;
|
||||
}
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{/* nothing */ }
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
} else if(cache_i2.neoncache[i].v)
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neoncacheUnwind(neoncache_t* cache)
|
||||
{
|
||||
if(cache->swapped) {
|
||||
// unswap
|
||||
int a = -1;
|
||||
int b = -1;
|
||||
for(int j=0; j<24 && ((a==-1) || (b==-1)); ++j)
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n == cache->combined1)
|
||||
a = j;
|
||||
else if(cache->neoncache[j].n == cache->combined2)
|
||||
b = j;
|
||||
}
|
||||
if(a!=-1 && b!=-1) {
|
||||
int tmp = cache->neoncache[a].n;
|
||||
cache->neoncache[a].n = cache->neoncache[b].n;
|
||||
cache->neoncache[b].n = tmp;
|
||||
}
|
||||
cache->swapped = 0;
|
||||
cache->combined1 = cache->combined2 = 0;
|
||||
}
|
||||
if(cache->news) {
|
||||
// reove the newly created neoncache
|
||||
for(int i=0; i<24; ++i)
|
||||
if(cache->news&(1<<i))
|
||||
cache->neoncache[i].v = 0;
|
||||
cache->news = 0;
|
||||
}
|
||||
if(cache->stack_push) {
|
||||
// unpush
|
||||
for(int j=0; j<24; ++j) {
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n<cache->stack_push)
|
||||
cache->neoncache[j].v = 0;
|
||||
else
|
||||
cache->neoncache[j].n-=cache->stack_push;
|
||||
}
|
||||
}
|
||||
cache->x87stack-=cache->stack_push;
|
||||
cache->stack-=cache->stack_push;
|
||||
cache->stack_push = 0;
|
||||
}
|
||||
cache->x87stack+=cache->stack_pop;
|
||||
cache->stack_next = cache->stack;
|
||||
cache->stack_pop = 0;
|
||||
cache->barrier = 0;
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
cache->mmxcount = 0;
|
||||
cache->fpu_scratch = 0;
|
||||
cache->fpu_extra_qscratch = 0;
|
||||
cache->fpu_reg = 0;
|
||||
for(int i=0; i<8; ++i) {
|
||||
cache->x87cache[i] = -1;
|
||||
cache->mmxcache[i] = -1;
|
||||
cache->ssecache[i].v = -1;
|
||||
cache->x87reg[i] = 0;
|
||||
}
|
||||
int x87reg = 0;
|
||||
for(int i=0; i<24; ++i) {
|
||||
if(cache->neoncache[i].v) {
|
||||
cache->fpuused[i] = 1;
|
||||
switch (cache->neoncache[i].t) {
|
||||
case NEON_CACHE_MM:
|
||||
cache->mmxcache[cache->neoncache[i].n] = i+FPUFIRST;
|
||||
++cache->mmxcount;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_XMMW:
|
||||
cache->ssecache[cache->neoncache[i].n].reg = i+FPUFIRST;
|
||||
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
|
||||
++cache->fpu_reg;
|
||||
++i; // next next
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
case NEON_CACHE_ST_D:
|
||||
cache->x87cache[x87reg] = cache->neoncache[i].n;
|
||||
cache->x87reg[x87reg] = i+FPUFIRST;
|
||||
++x87reg;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_SCR:
|
||||
cache->fpuused[i] = 0;
|
||||
cache->neoncache[i].v = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cache->fpuused[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -496,3 +722,77 @@ int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int
|
||||
#undef PK
|
||||
}
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
static char buff[20];
|
||||
switch(t) {
|
||||
case NEON_CACHE_ST_D: sprintf(buff, "ST%d", n); break;
|
||||
case NEON_CACHE_ST_F: sprintf(buff, "st%d", n); break;
|
||||
case NEON_CACHE_MM: sprintf(buff, "MM%d", n); break;
|
||||
case NEON_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
|
||||
case NEON_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
|
||||
case NEON_CACHE_SCR: sprintf(buff, "Scratch"); break;
|
||||
case NEON_CACHE_NONE: buff[0]='\0'; break;
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
// check flags cache
|
||||
if(dyn->insts[ninst].f_entry.dfnone || dyn->insts[ninst].f_entry.pending)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].x86.state_flags)
|
||||
return 0;
|
||||
// check neoncache
|
||||
neoncache_t* n = &dyn->insts[ninst].n;
|
||||
if(n->news || n->stack || n->stack_next)
|
||||
return 0;
|
||||
for(int i=0; i<24; ++i)
|
||||
if(n->neoncache[i].v)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int flagsCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int jmp = dyn->insts[ninst].x86.jmp_insts;
|
||||
if(jmp<0)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].f_exit.dfnone) // flags are fully known, nothing we can do more
|
||||
return 0;
|
||||
/* if((dyn->f.pending!=SF_SET)
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) {
|
||||
if(dyn->f.pending!=SF_PENDING) {*/
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
case SF_SET:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET && dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int ret = 0;
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=1;
|
||||
if (flagsCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
return ret;
|
||||
}
|
||||
@@ -23,6 +23,11 @@ void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x86emu_t* emu);
|
||||
|
||||
int64_t arm_fist64_0(double d);
|
||||
int64_t arm_fist64_1(double d);
|
||||
int64_t arm_fist64_2(double d);
|
||||
int64_t arm_fist64_3(double d);
|
||||
|
||||
void arm_ud(x86emu_t* emu);
|
||||
|
||||
#define FPUFIRST 8
|
||||
@@ -50,13 +55,29 @@ void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
// Get type for STx
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or DOUBLE
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual type for STx
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual STx is FLOAT or DOUBLE
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a);
|
||||
// Back-propagate a change float->double
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Combine and propagate if needed (pass 1 only)
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
|
||||
|
||||
// FPU Cache transformation (for loops)
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
|
||||
// Do the GETED, but don't emit anything...
|
||||
@@ -65,4 +86,6 @@ 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);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
+793
-236
File diff suppressed because it is too large.
Load diff
@@ -27,6 +27,9 @@
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
#define PKa(a) *(uint8_t*)(a)
|
||||
|
||||
//LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
|
||||
// GETGD get x86 register in gd
|
||||
#define GETGD gd = xEAX+((nextop&0x38)>>3)
|
||||
//GETED can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
@@ -34,7 +37,7 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDR_IMM9(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -43,7 +46,7 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDR_IMM9(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
@@ -53,7 +56,7 @@
|
||||
MOV_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
ed = ret; \
|
||||
LDR_IMM9(ed, wback, fixedaddress); \
|
||||
}
|
||||
@@ -66,7 +69,7 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL); \
|
||||
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -75,8 +78,9 @@
|
||||
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);\
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL); \
|
||||
ADD_REG_LSL_IMM5(x2, wback, O, 0); \
|
||||
if(wback != x2) wback = x2; \
|
||||
LDR_IMM9(x1, wback, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -94,7 +98,7 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -106,7 +110,7 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -118,7 +122,7 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRSH_IMM8(i, wback, fixedaddress);\
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -138,7 +142,7 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
@@ -152,9 +156,10 @@
|
||||
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); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, NULL); \
|
||||
ADD_REG_LSL_IMM5(x3, wback, i, 0); \
|
||||
if(wback!=x3) wback = x3; \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
@@ -167,7 +172,7 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRSB_IMM8(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
@@ -211,6 +216,12 @@
|
||||
#define CALL_2D(F, M) call_d(dyn, ninst, F, NULL, 2, x3, -1, M, 0)
|
||||
// CALL_1DD will use x3 for the call address. Return value in D0, 1 ARG in D0, cals 2 functions in a row
|
||||
#define CALL_1DD(F, F2, M) call_d(dyn, ninst, F, F2, 1, x3, -1, M, 0)
|
||||
// CALL_1D_U64 will use S as scratch. Return value in ret/ret2, 1 ARG in D0
|
||||
#define CALL_1DR_U64(R, ret, ret2, S, M) call_dr(dyn, ninst, R, 1, S, ret, ret2, M, 1)
|
||||
// CALL_1D will use S as scratch. Return value in D0, 1 ARG in D0
|
||||
#define CALL_1DR(R, S, M) call_dr(dyn, ninst, R, 1, S, -1, -1, M, 0)
|
||||
// CALL_1RD will use S as scratch. Return value in D0, 1 ARG in R
|
||||
#define CALL_1RD(F, R, S, M) call_rd(dyn, ninst, F, R, S, M, 0);
|
||||
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
@@ -239,7 +250,7 @@
|
||||
Bcond(cond, j32)
|
||||
// Branch to next instruction if cond (use j32)
|
||||
#define B_NEXT(cond) \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
|
||||
j32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKSEG if cond (use j32)
|
||||
#define B_MARKSEG(cond) \
|
||||
@@ -250,11 +261,11 @@
|
||||
j32 = GETMARKLOCK-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
|
||||
#define IFX(A) if((dyn->insts[ninst].x86.need_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x86.need_flags&(X_PEND) || !dyn->insts[ninst].x86.need_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x86.need_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x86.need_flags&(A) && !(dyn->insts[ninst].x86.need_flags&(B))))
|
||||
#define IFX(A) if((dyn->insts[ninst].x86.gen_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x86.gen_flags&(X_PEND) || !dyn->insts[ninst].x86.gen_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x86.gen_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x86.gen_flags==(A) || dyn->insts[ninst].x86.gen_flags==(B) || dyn->insts[ninst].x86.gen_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x86.gen_flags&(A) && !(dyn->insts[ninst].x86.gen_flags&(B))))
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2) \
|
||||
@@ -284,15 +295,20 @@
|
||||
} \
|
||||
|
||||
|
||||
#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
|
||||
#define SET_DFNONE(S) if(!dyn->f.dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->f.dfnone=1;}
|
||||
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->f.dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS()
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET && dyn->state_flags!=SF_SET_PENDING) { \
|
||||
if(dyn->state_flags!=SF_PENDING) { \
|
||||
if((dyn->f.pending!=SF_SET) \
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) { \
|
||||
if(dyn->f.pending!=SF_PENDING) { \
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0); \
|
||||
j32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
@@ -300,16 +316,26 @@
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)/*|X_PEND*/)))) \
|
||||
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A)|X_PEND)); \
|
||||
dyn->state_flags = (B==SF_SUBSET)?SF_SET: \
|
||||
((B==SF_SET_PENDING && !(dyn->insts[ninst].x86.need_flags&X_PEND)?SF_SET:B))
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->f.pending!=SF_SET \
|
||||
&& ((B)&SF_SUB) \
|
||||
&& (dyn->insts[ninst].x86.gen_flags&(~(A)))) \
|
||||
READFLAGS(((dyn->insts[ninst].x86.gen_flags&X_PEND)?X_ALL:dyn->insts[ninst].x86.gen_flags)&(~(A)));\
|
||||
if(dyn->insts[ninst].x86.gen_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
|
||||
case SF_SUBSET_PENDING: \
|
||||
case SF_SET_PENDING: \
|
||||
dyn->f.pending = (dyn->insts[ninst].x86.gen_flags&X_PEND)?SF_SET_PENDING:SF_SET; \
|
||||
break; \
|
||||
} else dyn->f.pending = SF_SET
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A, C)
|
||||
@@ -320,17 +346,14 @@
|
||||
#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)
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x86.gen_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x86.gen_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
#ifndef NEW_BARRIER_INST
|
||||
#define NEW_BARRIER_INST
|
||||
#define DEFAULT *ok = -1; BARRIER(BARRIER_NOFLAGS)
|
||||
#endif
|
||||
|
||||
#if STEP < 2
|
||||
@@ -368,6 +391,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define dynarecDF STEPNAME(dynarecDF)
|
||||
#define dynarecF0 STEPNAME(dynarecF0)
|
||||
#define dynarec660F STEPNAME(dynarec660F)
|
||||
#define dynarec66F0 STEPNAME(dynarec66F0)
|
||||
#define dynarecF20F STEPNAME(dynarecF20F)
|
||||
#define dynarecF30F STEPNAME(dynarecF30F)
|
||||
|
||||
@@ -380,6 +404,8 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog_)
|
||||
#define call_c STEPNAME(call_c_)
|
||||
#define call_d STEPNAME(call_d_)
|
||||
#define call_dr STEPNAME(call_dr_)
|
||||
#define call_rd STEPNAME(call_rd_)
|
||||
#define grab_fsdata STEPNAME(grab_fsdata_)
|
||||
#define grab_tlsdata STEPNAME(grab_tlsdata_)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
@@ -454,6 +480,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
#define emit_shrd32 STEPNAME(emit_shrd32)
|
||||
#define emit_shld32 STEPNAME(emit_shld32)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
@@ -471,6 +498,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define x87_swapreg STEPNAME(x87_swapreg)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
@@ -492,8 +520,10 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
// put back (if needed) the single reg in place
|
||||
#define fpu_putback_single_reg STEPNAME(fpu_putback_single_reg)
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly);
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly, int* l);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
|
||||
@@ -507,10 +537,10 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_dr(dynarec_arm_t* dyn, int ninst, int reg, int n, int s1, int ret, int ret2, uint32_t mask, int saveflags);
|
||||
void call_rd(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int s1, uint32_t mask, int saveflags);
|
||||
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_unlock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -583,6 +613,7 @@ 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_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
@@ -615,9 +646,19 @@ 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);
|
||||
// swap 2 x87 regs
|
||||
void x87_swapreg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int b);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
#if STEP < 2
|
||||
#define CHECK_CACHE() 0
|
||||
#else
|
||||
#define CHECK_CACHE() (cacheupd = CacheNeedsTransform(dyn, ninst))
|
||||
#endif
|
||||
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
|
||||
@@ -656,7 +697,7 @@ 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);
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
// 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);
|
||||
@@ -688,6 +729,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
|
||||
|
||||
+122
-21
@@ -30,21 +30,77 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
int j32;
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t init_addr = addr;
|
||||
MAYUSE(init_addr);
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
fpu_reset(dyn, ninst);
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
fpu_reset(dyn);
|
||||
int reset_n = -1;
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
ip = addr;
|
||||
if((dyn->insts[ninst].x86.barrier==1)) {
|
||||
NEW_BARRIER_INST;
|
||||
if (reset_n!=-1) {
|
||||
if(reset_n==-2) {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
} else {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box86_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
fpu_reset(dyn);
|
||||
}
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLAGS) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
}
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
@@ -58,8 +114,14 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
NEW_INST;
|
||||
fpu_reset_scratch(dyn);
|
||||
if((dyn->insts[ninst].x86.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x86.need_before&~X_PEND);
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box86_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
@@ -80,43 +142,82 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
int next = ninst+1;
|
||||
#if STEP > 0
|
||||
if(!dyn->insts[ninst].x86.has_next && dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts!=-1)
|
||||
next = dyn->insts[ninst].x86.jmp_insts;
|
||||
#endif
|
||||
if(dyn->insts[ninst].x86.has_next && dyn->insts[next].x86.barrier) {
|
||||
if(dyn->insts[next].x86.barrier&BARRIER_FLOAT)
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[next].x86.barrier&BARRIER_FLAGS) {
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
}
|
||||
}
|
||||
#if STEP != 0
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
while(ii<dyn->size && !dyn->insts[ii].pred_sz)
|
||||
++ii;
|
||||
if((dyn->insts[ii].x86.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
reset_n = -2; // hack to say Barrier!
|
||||
else {
|
||||
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are availble
|
||||
if(reset_n==-1) {
|
||||
reset_n = -2;
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#if STEP == 0
|
||||
if(!ok && !need_epilog && box86_dynarec_bigblock && getProtection(addr+3))
|
||||
#else
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
if(!ok && !need_epilog && box86_dynarec_bigblock && (getProtection(addr+3)&PROT_READ))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
&& (((box86_dynarec_bigblock<2) && isJumpTableDefault((void*)next)) || (box86_dynarec_bigblock>1))
|
||||
/*||(((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;
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
reset_n = -2;
|
||||
for(int ii=0; ii<ninst; ++ii)
|
||||
if(dyn->insts[ii].x86.jmp == next) {
|
||||
reset_n = ii;
|
||||
ii=ninst;
|
||||
}
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %p -> %p (ninst=%d, jump from %d)\n", dyn, (void*)addr, (void*)next, ninst, reset_n);
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "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))
|
||||
if((ok && !isJumpTableDefault((void*)addr) && (box86_dynarec_bigblock<2)) ||
|
||||
(ok && dyn->size >= 2000))
|
||||
#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);
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x86.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].x86.need_after |= X_PEND;
|
||||
#endif
|
||||
BARRIER(2);
|
||||
++ninst;
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
@@ -127,6 +228,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size);
|
||||
return addr;
|
||||
}
|
||||
@@ -5,30 +5,43 @@
|
||||
dyn->insts[ninst].x86.addr = addr;\
|
||||
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr
|
||||
#define MESSAGE(A, ...)
|
||||
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
|
||||
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x86.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x86.use_flags = A; dyn->f.dfnone = 1;\
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x86.set_flags = A; \
|
||||
dyn->insts[ninst].x86.state_flags = B; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x86.barrier = A
|
||||
#define JUMP(A, C) 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) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x86.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst+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); \
|
||||
dyn->insts = (instruction_arm_t*)box_realloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2); \
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
dyn->insts[ninst].x86.addr = ip; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;}
|
||||
|
||||
#define INST_EPILOG
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].x86.has_next = ok;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box86_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
if(box86_dynarec_log>=LOG_INFO || box86_dynarec_dump) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped @ %s (%s:%u) because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, __FUNCTION__, __FILE__, __LINE__, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define READFLAGS(A)
|
||||
#define SETFLAGS(A,B)
|
||||
|
||||
#define NEW_INST dyn->n.combined1 = dyn->n.combined2 = 0
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0
|
||||
|
||||
#define INST_EPILOG dyn->insts[ninst].n = dyn->n
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
|
||||
#define INST_NAME(name)
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
|
||||
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define 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
|
||||
@@ -7,46 +7,52 @@
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST
|
||||
#define NEW_INST \
|
||||
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box86_dynarec_dump) {\
|
||||
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d, set=%X, use=%X, need=%X", \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%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->f.pending, \
|
||||
dyn->f.dfnone, \
|
||||
dyn->insts[ninst].x86.may_set?"may":"set", \
|
||||
dyn->insts[ninst].x86.set_flags, \
|
||||
dyn->insts[ninst].x86.gen_flags, \
|
||||
dyn->insts[ninst].x86.use_flags, \
|
||||
dyn->insts[ninst].x86.need_flags); \
|
||||
dyn->insts[ninst].x86.need_before, \
|
||||
dyn->insts[ninst].x86.need_after); \
|
||||
if(dyn->insts[ninst].pred_sz) { \
|
||||
dynarec_log(LOG_NONE, ", pred="); \
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)\
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);\
|
||||
} \
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts>=0)\
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x86.jmp_insts);\
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts==-1)\
|
||||
dynarec_log(LOG_NONE, ", jmp=out");\
|
||||
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_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", (ii+8)*2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); 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; \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack) \
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack); \
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
@@ -20,31 +23,6 @@ typedef union neon_cache_s {
|
||||
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 {
|
||||
@@ -52,6 +30,57 @@ typedef union sse_cache_s {
|
||||
uint8_t write;
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
// Neon cache
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
int8_t stack_push;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int8_t mmxcache[8];// cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int8_t fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch;// scratch counter
|
||||
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x86_t x86;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
int barrier_maybe;
|
||||
flagcache_t f_exit; // flags status at end of intruction
|
||||
neoncache_t n; // neoncache at end of intruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_arm_t;
|
||||
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm_t *insts;
|
||||
@@ -62,31 +91,20 @@ typedef struct dynarec_arm_s {
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
int arm_size; // size of emitted arm code
|
||||
int state_flags;// actual state for on-demand flags
|
||||
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int x87reg[8]; // reg used for x87cache entry
|
||||
int mmxcache[8];// cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
flagcache_t f;
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
int x87stack; // cache stack counter
|
||||
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
} 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);
|
||||
void CreateJmpNextTo(void* addr, void* tonext);
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef __DYNAREC_NEXT_H__
|
||||
#define __DYNAREC_NEXT_H__
|
||||
|
||||
void arm_next(void) EXPORTDYN;
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
|
||||
#endif //__DYNAREC_NEXT_H__
|
||||
@@ -1,6 +1,11 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
#define BARRIER_NONE 0
|
||||
#define BARRIER_FLAGS 1
|
||||
#define BARRIER_FLOAT 2
|
||||
#define BARRIER_FULL 3
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
@@ -9,27 +14,32 @@
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x1000)
|
||||
#define X_PEND (0x80)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_SET_PENDING 3
|
||||
#define SF_MAYSET 4
|
||||
#define SF_SUBSET 5
|
||||
#define SF_SET_PENDING (SF_SET|SF_PENDING)
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
|
||||
typedef struct instruction_x86_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
int barrier; // next instruction is a jump point, so no optim allowed
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_cond; // 1 of conditionnal jump
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint32_t use_flags; // 0 or combination of X_?F
|
||||
uint32_t set_flags; // 0 or combination of X_?F
|
||||
uint32_t need_flags; // calculated
|
||||
int state_flags; // One of SF_XXX state
|
||||
uint8_t jmp_cond; // 1 of conditionnal jump
|
||||
uint8_t has_next; // does this opcode can continue to the next?
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
uint8_t use_flags; // 0 or combination of X_?F
|
||||
uint8_t set_flags; // 0 or combination of X_?F
|
||||
uint8_t may_set; // 1 if the flags may not be set
|
||||
uint8_t gen_flags; // calculated
|
||||
uint8_t need_before; // calculated
|
||||
uint8_t need_after; // calculated
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
|
||||
@@ -83,7 +83,7 @@ INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d64 &g&g param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
|
||||
|
||||
+721
-334
File diff suppressed because it is too large.
Load diff
@@ -1,14 +1,12 @@
|
||||
#ifndef __ELFLOADER_PRIVATE_H_
|
||||
#define __ELFLOADER_PRIVATE_H_
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
#endif
|
||||
|
||||
typedef struct library_s library_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
|
||||
#include <pthread.h>
|
||||
#include <elf.h>
|
||||
#include "elfloader.h"
|
||||
|
||||
struct elfheader_s {
|
||||
char* name;
|
||||
@@ -66,11 +64,14 @@ struct elfheader_s {
|
||||
uintptr_t plt_end;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
uintptr_t bss;
|
||||
int bsssz;
|
||||
|
||||
uintptr_t paddr;
|
||||
uintptr_t vaddr;
|
||||
int align;
|
||||
uint32_t memsz;
|
||||
uint32_t reserve;
|
||||
uint32_t stacksz;
|
||||
int stackalign;
|
||||
uintptr_t tlsaddr;
|
||||
@@ -91,6 +92,10 @@ struct elfheader_s {
|
||||
|
||||
library_t *lib;
|
||||
needed_libs_t *neededlibs;
|
||||
|
||||
kh_mapsymbols_t *mapsymbols;
|
||||
kh_mapsymbols_t *weaksymbols;
|
||||
kh_mapsymbols_t *localsymbols;
|
||||
};
|
||||
|
||||
#define R_386_NONE 0
|
||||
|
||||
+78
-64
@@ -17,16 +17,16 @@
|
||||
int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type)
|
||||
{
|
||||
if(type && (s->sh_type != type)) {
|
||||
printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
|
||||
printf_dump(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
|
||||
return -1;
|
||||
}
|
||||
if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf32_Sym)) {
|
||||
printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %d)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
|
||||
printf_dump(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %d)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
|
||||
}
|
||||
*SH = calloc(1, s->sh_size);
|
||||
*SH = box_calloc(1, s->sh_size);
|
||||
fseeko64(f, s->sh_offset ,SEEK_SET);
|
||||
if(fread(*SH, s->sh_size, 1, f)!=1) {
|
||||
printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
|
||||
printf_dump(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name)
|
||||
void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, int* num)
|
||||
{
|
||||
int n = FindSection(s, size, SHStrTab, name);
|
||||
printf_log(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
|
||||
printf_dump(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
|
||||
if(n)
|
||||
LoadSH(f, s+n, what, name, type);
|
||||
if(type==SHT_SYMTAB || type==SHT_DYNSYM) {
|
||||
@@ -63,59 +63,59 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
Elf32_Ehdr header;
|
||||
int level = (exec)?LOG_INFO:LOG_DEBUG;
|
||||
if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
|
||||
printf_log(level, "Cannot read ELF Header\n");
|
||||
printf_dump(level, "Cannot read ELF Header\n");
|
||||
return NULL;
|
||||
}
|
||||
if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
|
||||
printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
|
||||
printf_dump(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
|
||||
if(header.e_ident[EI_CLASS]==ELFCLASS64) {
|
||||
printf_log(LOG_INFO, "This is a 64bits ELF! box86 can only run 32bits ELF!\n");
|
||||
printf_dump(LOG_INFO, "This is a 64bits ELF! box86 can only run 32bits ELF!\n");
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
printf_dump(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
|
||||
printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
|
||||
printf_dump(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
|
||||
printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
|
||||
printf_dump(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) {
|
||||
printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
|
||||
printf_dump(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_type != ET_EXEC && header.e_type != ET_DYN) {
|
||||
printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
|
||||
printf_dump(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_machine != EM_386) {
|
||||
printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
printf_dump(level, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_entry == 0 && exec) {
|
||||
printf_log(LOG_INFO, "No entry point in ELF\n");
|
||||
printf_dump(LOG_INFO, "No entry point in ELF\n");
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_phentsize != sizeof(Elf32_Phdr)) {
|
||||
printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %d)\n", header.e_phentsize, sizeof(Elf32_Phdr));
|
||||
printf_dump(LOG_INFO, "Program Header Entry size incorrect (%d != %d)\n", header.e_phentsize, sizeof(Elf32_Phdr));
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_shentsize != sizeof(Elf32_Shdr) && header.e_shentsize != 0) {
|
||||
printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %d)\n", header.e_shentsize, sizeof(Elf32_Shdr));
|
||||
printf_dump(LOG_INFO, "Section Header Entry size incorrect (%d != %d)\n", header.e_shentsize, sizeof(Elf32_Shdr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elfheader_t *h = calloc(1, sizeof(elfheader_t));
|
||||
h->name = strdup(name);
|
||||
elfheader_t *h = box_calloc(1, sizeof(elfheader_t));
|
||||
h->name = box_strdup(name);
|
||||
h->entrypoint = header.e_entry;
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
@@ -124,55 +124,55 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
fseeko64(f, header.e_shoff, SEEK_SET);
|
||||
Elf32_Shdr section;
|
||||
if(fread(§ion, sizeof(Elf32_Shdr), 1, f)!=1) {
|
||||
free(h);
|
||||
printf_log(LOG_INFO, "Cannot read Initial Section Header\n");
|
||||
box_free(h);
|
||||
printf_dump(LOG_INFO, "Cannot read Initial Section Header\n");
|
||||
return NULL;
|
||||
}
|
||||
h->numSHEntries = section.sh_size;
|
||||
}
|
||||
// now read all section headers
|
||||
printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf32_Shdr*)calloc(h->numSHEntries, sizeof(Elf32_Shdr));
|
||||
printf_dump(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf32_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf32_Shdr));
|
||||
fseeko64(f, header.e_shoff ,SEEK_SET);
|
||||
if(fread(h->SHEntries, sizeof(Elf32_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
|
||||
FreeElfHeader(&h);
|
||||
printf_log(LOG_INFO, "Cannot read all Section Header\n");
|
||||
printf_dump(LOG_INFO, "Cannot read all Section Header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(h->numPHEntries == PN_XNUM) {
|
||||
printf_log(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
h->numPHEntries = h->SHEntries[0].sh_info;
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf32_Phdr*)calloc(h->numPHEntries, sizeof(Elf32_Phdr));
|
||||
printf_dump(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf32_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf32_Phdr));
|
||||
fseeko64(f, header.e_phoff ,SEEK_SET);
|
||||
if(fread(h->PHEntries, sizeof(Elf32_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
|
||||
FreeElfHeader(&h);
|
||||
printf_log(LOG_INFO, "Cannot read all Program Header\n");
|
||||
printf_dump(LOG_INFO, "Cannot read all Program Header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
if(h->SHIdx == SHN_XINDEX) {
|
||||
printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
h->SHIdx = h->SHEntries[0].sh_link;
|
||||
}
|
||||
if(h->SHIdx > h->numSHEntries) {
|
||||
printf_log(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
|
||||
printf_dump(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
// load Section table
|
||||
printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
|
||||
printf_dump(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
|
||||
if(LoadSH(f, h->SHEntries+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
@@ -231,61 +231,65 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
break;
|
||||
case DT_INIT: // Entry point
|
||||
h->initentry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
break;
|
||||
case DT_INIT_ARRAY:
|
||||
h->initarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
|
||||
break;
|
||||
case DT_INIT_ARRAYSZ:
|
||||
h->initarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
if(val)
|
||||
printf_dump(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
printf_dump(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
break;
|
||||
case DT_FINI_ARRAY:
|
||||
h->finiarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
|
||||
printf_dump(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
|
||||
break;
|
||||
case DT_FINI_ARRAYSZ:
|
||||
h->finiarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
|
||||
printf_dump(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
|
||||
break;
|
||||
case DT_VERNEEDNUM:
|
||||
h->szVerNeed = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
break;
|
||||
case DT_VERNEED:
|
||||
h->VerNeed = (Elf32_Verneed*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
break;
|
||||
case DT_VERDEFNUM:
|
||||
h->szVerDef = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
h->VerDef = (Elf32_Verdef*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(h->rel) {
|
||||
if(h->relent != sizeof(Elf32_Rel)) {
|
||||
printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%x)\n", h->relent, sizeof(Elf32_Rel));
|
||||
printf_dump(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%x)\n", h->relent, sizeof(Elf32_Rel));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
printf_dump(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
}
|
||||
if(h->rela) {
|
||||
if(h->relaent != sizeof(Elf32_Rela)) {
|
||||
printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%x)\n", h->relaent, sizeof(Elf32_Rela));
|
||||
printf_dump(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%x)\n", h->relaent, sizeof(Elf32_Rela));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
printf_dump(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
}
|
||||
if(h->jmprel) {
|
||||
if(h->pltrel == DT_REL) {
|
||||
@@ -293,16 +297,16 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
} else if(h->pltrel == DT_RELA) {
|
||||
h->pltent = sizeof(Elf32_Rela);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel);
|
||||
printf_dump(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
if((h->pltsz / h->pltent)*h->pltent != h->pltsz) {
|
||||
printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel);
|
||||
printf_dump(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
printf_dump(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
}
|
||||
if(h->DynStrTab && h->szDynStrTab) {
|
||||
//DumpDynamicNeeded(h); cannot dump now, it's not loaded yet
|
||||
@@ -313,32 +317,39 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
if(ii) {
|
||||
h->gotplt = h->SHEntries[ii].sh_addr;
|
||||
h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
printf_dump(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
|
||||
if(ii) {
|
||||
h->got = h->SHEntries[ii].sh_addr;
|
||||
h->got_end = h->got + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
printf_dump(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
|
||||
if(ii) {
|
||||
h->plt = h->SHEntries[ii].sh_addr;
|
||||
h->plt_end = h->plt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
printf_dump(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
}
|
||||
// grab version of symbols
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
|
||||
if(ii) {
|
||||
h->VerSym = (Elf32_Half*)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
printf_dump(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
}
|
||||
// grab .text for main code
|
||||
// grab .bss for main code
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
|
||||
if(ii) {
|
||||
h->text = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->textsz = h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The .text is at address %p, and is %d big\n", (void*)h->text, h->textsz);
|
||||
printf_dump(LOG_DEBUG, "The .text is at address %p, and is %d big\n", (void*)h->text, h->textsz);
|
||||
}
|
||||
// grab .bss to find brk
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".bss");
|
||||
if(ii) {
|
||||
h->bss = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->bsssz = h->SHEntries[ii].sh_size;
|
||||
printf_dump(LOG_DEBUG, "The .bss is at address %p, and is %d big\n", (void*)h->bss, h->bsssz);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
@@ -350,19 +361,22 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
if(!h->VerNeed || (version<2))
|
||||
version&=0x7fff; // remove bit15 that switch between hidden/public
|
||||
if(version<2)
|
||||
return NULL;
|
||||
/*if(version==1)
|
||||
return "*";*/
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(aux->vna_other==version)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
if(h->VerNeed) {
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(aux->vna_other==version)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead
|
||||
}
|
||||
|
||||
+66
-17
@@ -60,6 +60,26 @@
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
_0f_0x0D: /* PREFETCH group */
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1: /* PREFETCHW */
|
||||
GET_ED; //nothing for now. Could maybe use some builtin prefetch instruction
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
_0f_0x0E: /* FEMMS */
|
||||
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;
|
||||
GET_EX;
|
||||
@@ -227,7 +247,7 @@
|
||||
if(EM->ub[i]&128)
|
||||
GM.ub[i] = 0;
|
||||
else
|
||||
GM.ub[i] = eax1.ub[EM->ub[i]&7];
|
||||
GM.ub[i] = eam1.ub[EM->ub[i]&7];
|
||||
}
|
||||
break;
|
||||
case 0x04: /* PMADDUBSW Gm,Em */
|
||||
@@ -280,6 +300,17 @@
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0: /* MOVBE Gd, Ed*/
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GD.dword[0] = __builtin_bswap32(ED->dword[0]);
|
||||
break;
|
||||
case 0xF1: /* MOVBE Ed, Gd*/
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
ED->dword[0] = __builtin_bswap32(GD.dword[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
@@ -288,7 +319,7 @@
|
||||
_0f_0x3A:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0xF: /* palignr */
|
||||
case 0x0F: /* palignr */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
tmp8u = F8;
|
||||
@@ -297,8 +328,10 @@
|
||||
} else if (tmp8u > 8) {
|
||||
tmp8u -= 8;
|
||||
GM.q >>= tmp8u*8;
|
||||
} else if (tmp8u == 8 || tmp8u == 0) {
|
||||
|
||||
} else if (tmp8u == 8) {
|
||||
// nothing
|
||||
} else if (tmp8u == 0) {
|
||||
GM.q = EM->q;
|
||||
} else {
|
||||
GM.q <<= (8-tmp8u)*8;
|
||||
GM.q |= (EM->q >> tmp8u*8);
|
||||
@@ -435,8 +468,18 @@
|
||||
_0f_0x52: /* RSQRTPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.f[i] = 1.0f/sqrtf(EX->f[i]);
|
||||
for(int i=0; i<4; ++i) {
|
||||
if(EX->f[i]==0)
|
||||
GX.f[i] = 1.0f/EX->f[i];
|
||||
else if (EX->f[i]<0)
|
||||
GX.f[i] = NAN;
|
||||
else if (isnan(EX->f[i]))
|
||||
GX.f[i] = EX->f[i];
|
||||
else if (isinf(EX->f[i]))
|
||||
GX.f[i] = 0.0;
|
||||
else
|
||||
GX.f[i] = 1.0f/sqrtf(EX->f[i]);
|
||||
}
|
||||
NEXT;
|
||||
_0f_0x53: /* RCPPS Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -1093,19 +1136,25 @@
|
||||
GX.q[1] = eax1.q[1];
|
||||
NEXT;
|
||||
_0f_0xC7: /* CMPXCHG8B Gq */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
CHECK_FLAGS(emu);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
_0f_0xC8:
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0x1E: /* PUSH DS */
|
||||
Push16(emu, emu->segs[_DS]);
|
||||
NEXT;
|
||||
_66_0x1F: /* POP DS */
|
||||
emu->segs[_DS] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_DS] = 0;
|
||||
@@ -86,6 +89,10 @@
|
||||
_66_0x3D:
|
||||
cmp16(emu, R_AX, F16);
|
||||
NEXT;
|
||||
_66_0x3E: /* DS: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
_66_0x40:
|
||||
_66_0x41:
|
||||
@@ -482,6 +489,11 @@
|
||||
R_ECX = tmp32u;
|
||||
NEXT;
|
||||
|
||||
_66_0xF5: /* CMC */
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!ACCESS_FLAG(F_CF), F_CF);
|
||||
NEXT;
|
||||
|
||||
_66_0xF7: /* GRP3 Ew(,Iw) */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
|
||||
+17
-3
@@ -23,6 +23,7 @@
|
||||
ll = ST(nextop&7).sq;
|
||||
ST(nextop&7).sq = ST0.sq;
|
||||
ST0.sq = ll;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
|
||||
case 0xD0: /* FNOP */
|
||||
@@ -30,9 +31,11 @@
|
||||
|
||||
case 0xE0: /* FCHS */
|
||||
ST0.d = -ST0.d;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xE1: /* FABS */
|
||||
ST0.d = fabs(ST0.d);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
|
||||
case 0xE4: /* FTST */
|
||||
@@ -73,25 +76,30 @@
|
||||
|
||||
case 0xF0: /* F2XM1 */
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF1: /* FYL2X */
|
||||
ST(1).d *= log2(ST0.d);
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF2: /* FPTAN */
|
||||
ST0.d = tan(ST0.d);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = 1.0;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF3: /* FPATAN */
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF4: /* FXTRACT */
|
||||
ST0.d = frexp(ST0.d, &tmp32s);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = tmp32s;
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
|
||||
case 0xF8: /* FPREM */
|
||||
@@ -146,30 +154,37 @@
|
||||
case 0xF9: /* FYL2XP1 */
|
||||
ST(1).d *= log2(ST0.d + 1.0);
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFA: /* FSQRT */
|
||||
ST0.d = sqrt(ST0.d);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFB: /* FSINCOS */
|
||||
fpu_do_push(emu);
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFC: /* FRNDINT */
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFD: /* FSCALE */
|
||||
// this could probably be done by just altering the exponant part of the float...
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFE: /* FSIN */
|
||||
ST0.d = sin(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFF: /* FCOS */
|
||||
ST0.d = cos(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
|
||||
|
||||
@@ -230,9 +245,8 @@
|
||||
break;
|
||||
case 5: /* FLDCW Ew */
|
||||
GET_EW;
|
||||
emu->cw = EW->word[0];
|
||||
emu->cw.x16 = EW->word[0];
|
||||
// do something with cw?
|
||||
emu->round = (fpu_round_t)((emu->cw >> 10) & 3);
|
||||
break;
|
||||
case 6: /* FNSTENV m */
|
||||
// warning, incomplete
|
||||
@@ -244,7 +258,7 @@
|
||||
break;
|
||||
case 7: /* FNSTCW Ew */
|
||||
GET_EW;
|
||||
EW->word[0] = emu->cw;
|
||||
EW->word[0] = emu->cw.x16;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
memcpy(&STld(0).ld, ED, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
LD2D(&STld(0).ld, &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
|
||||
+30
-2
@@ -53,17 +53,32 @@
|
||||
case 0x51: /* SQRTSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] = sqrt(EX->d[0]);
|
||||
if(EX->d[0]<0.0 )
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
GX.d[0] = sqrt(EX->d[0]);
|
||||
break;
|
||||
|
||||
case 0x58: /* ADDSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
// add generate a -NAN only if doing inf + -inf
|
||||
if((isinf(GX.d[0]) && isinf(EX->d[0]) && (EX->q[0]&0x8000000000000000LL)!=(GX.q[0]&0x8000000000000000LL)))
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[0] += EX->d[0];
|
||||
break;
|
||||
case 0x59: /* MULSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
// mul generate a -NAN only if doing (+/-)inf * (+/-)0
|
||||
if((isinf(GX.d[0]) && EX->d[0]==0.0) || (isinf(EX->d[0]) && GX.d[0]==0.0))
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[0] *= EX->d[0];
|
||||
break;
|
||||
case 0x5A: /* CVTSD2SS Gx, Ex */
|
||||
@@ -75,18 +90,31 @@
|
||||
case 0x5C: /* SUBSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
// sub generate a -NAN only if doing inf - inf
|
||||
if((isinf(GX.d[0]) && isinf(EX->d[0]) && (EX->q[0]&0x8000000000000000LL)==(GX.q[0]&0x8000000000000000LL)))
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[0] -= EX->d[0];
|
||||
break;
|
||||
case 0x5D: /* MINSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if (isnan(GX.d[0]) || isnan(EX->d[0]) || isless(EX->d[0], GX.d[0]))
|
||||
if (isnan(GX.d[0]) || isnan(EX->d[0]) || (EX->d[0]<=GX.d[0]))
|
||||
GX.d[0] = EX->d[0];
|
||||
break;
|
||||
case 0x5E: /* DIVSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[0]) || isnan(EX->d[0]);
|
||||
#endif
|
||||
GX.d[0] /= EX->d[0];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[0]))
|
||||
GX.d[0] = -NAN;
|
||||
#endif
|
||||
break;
|
||||
case 0x5F: /* MAXSD Gx, Ex */
|
||||
nextop = F8;
|
||||
|
||||
+8
-9
@@ -89,7 +89,7 @@ x86emu_t *NewX86Emu(box86context_t *context, uintptr_t start, uintptr_t stack, i
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Allocate a new X86 Emu, with EIP=%p and Stack=%p/0x%X\n", (void*)start, (void*)stack, stacksize);
|
||||
|
||||
x86emu_t *emu = (x86emu_t*)calloc(1, sizeof(x86emu_t));
|
||||
x86emu_t *emu = (x86emu_t*)box_calloc(1, sizeof(x86emu_t));
|
||||
|
||||
internalX86Setup(emu, context, start, stack, stacksize, ownstack);
|
||||
|
||||
@@ -130,7 +130,7 @@ void AddCleanup(x86emu_t *emu, void *p)
|
||||
{
|
||||
if(my_context->clean_sz == my_context->clean_cap) {
|
||||
my_context->clean_cap += 4;
|
||||
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
my_context->cleanups = (cleanup_t*)box_realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
}
|
||||
my_context->cleanups[my_context->clean_sz].arg = 0;
|
||||
my_context->cleanups[my_context->clean_sz].a = NULL;
|
||||
@@ -141,7 +141,7 @@ void AddCleanup1Arg(x86emu_t *emu, void *p, void* a)
|
||||
{
|
||||
if(my_context->clean_sz == my_context->clean_cap) {
|
||||
my_context->clean_cap += 4;
|
||||
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
my_context->cleanups = (cleanup_t*)box_realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
}
|
||||
my_context->cleanups[my_context->clean_sz].arg = 1;
|
||||
my_context->cleanups[my_context->clean_sz].a = a;
|
||||
@@ -171,7 +171,7 @@ void CallAllCleanup(x86emu_t *emu)
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
|
||||
}
|
||||
my_context->clean_sz = 0;
|
||||
free(my_context->cleanups);
|
||||
box_free(my_context->cleanups);
|
||||
my_context->cleanups = NULL;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ void FreeX86Emu(x86emu_t **emu)
|
||||
|
||||
internalFreeX86(*emu);
|
||||
|
||||
free(*emu);
|
||||
box_free(*emu);
|
||||
*emu = NULL;
|
||||
}
|
||||
|
||||
@@ -217,10 +217,9 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
newemu->cw = emu->cw;
|
||||
memcpy(&newemu->sw, &emu->sw, sizeof(emu->sw));
|
||||
newemu->sw = emu->sw;
|
||||
newemu->top = emu->top;
|
||||
newemu->fpu_stack = emu->fpu_stack;
|
||||
memcpy(&newemu->round, &emu->round, sizeof(emu->round));
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
@@ -323,14 +322,14 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
}
|
||||
// start with FPU regs...
|
||||
if(emu->fpu_stack) {
|
||||
if(emu->fpu_stack<8)
|
||||
if(emu->fpu_stack<9)
|
||||
for (int i=0; i<emu->fpu_stack; i++) {
|
||||
//if(i==4) strcat(buff, "\n");
|
||||
sprintf(tmp, "ST%d=%f", i, emu->x87[(emu->top+i)&7].d);
|
||||
strcat(buff, tmp);
|
||||
int c = 10-strlen(tmp);
|
||||
if(c<1) c=1;
|
||||
while(c--) strcat(buff, " ");
|
||||
if(i==3) strcat(buff, "\n");
|
||||
}
|
||||
else {
|
||||
sprintf(tmp, "Warning, incoherent fpu_stack=%d", emu->fpu_stack);
|
||||
|
||||
@@ -29,13 +29,12 @@ typedef struct x86emu_s {
|
||||
x86flags_t eflags;
|
||||
reg32_t ip;
|
||||
// fpu / mmx
|
||||
x87control_t cw;
|
||||
x87flags_t sw;
|
||||
mmx87_regs_t x87[8];
|
||||
mmx87_regs_t mmx[8];
|
||||
uint16_t cw;
|
||||
x87flags_t sw;
|
||||
uint32_t top; // top is part of sw, but it's faster to have it separatly
|
||||
int fpu_stack;
|
||||
fpu_round_t round;
|
||||
fpu_ld_t fpu_ld[8]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[8]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[8];
|
||||
|
||||
+50
-29
@@ -85,11 +85,16 @@ void x86Int3(x86emu_t* emu)
|
||||
elfheader_t *h = FindElfAddress(my_context, *(uintptr_t*)(R_ESP));
|
||||
int have_trace = 0;
|
||||
if(h && strstr(ElfName(h), "libMiles")) have_trace = 1;*/
|
||||
if(box86_log>=LOG_DEBUG /*|| have_trace*/) {
|
||||
if(box86_log>=LOG_DEBUG || cycle_log) {
|
||||
int tid = GetTID();
|
||||
char buff[256] = "\0";
|
||||
char t_buff[256] = "\0";
|
||||
char buff2[64] = "\0";
|
||||
char buff3[64] = "\0";
|
||||
char* buff = cycle_log?my_context->log_call[my_context->current_line]:t_buff;
|
||||
char* buffret = cycle_log?my_context->log_ret[my_context->current_line]:NULL;
|
||||
if(buffret) buffret[0] = '\0';
|
||||
if(cycle_log)
|
||||
my_context->current_line = (my_context->current_line+1)&(CYCLE_LOG-1);
|
||||
char *tmp;
|
||||
int post = 0;
|
||||
int perr = 0;
|
||||
@@ -97,7 +102,7 @@ void x86Int3(x86emu_t* emu)
|
||||
const char *s = NULL;
|
||||
s = GetNativeName((void*)addr);
|
||||
if(addr==(uintptr_t)PltResolver) {
|
||||
snprintf(buff, 256, "%s", " ... ");
|
||||
snprintf(buff, 256, "%s", cycle_log?"PltResolver ":" ... ");
|
||||
} else
|
||||
if(strstr(s, "SDL_RWFromFile")==s || strstr(s, "SDL_RWFromFile")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%s, %s)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
@@ -119,16 +124,20 @@ void x86Int3(x86emu_t* emu)
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "shm_open")) {
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strcmp(s, "mkdir")==0) {
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "fopen")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
perr = 1;
|
||||
perr = 2;
|
||||
} else if(!strcmp(s, "freopen")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", %p)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
perr = 2;
|
||||
} else if(!strcmp(s, "fopen64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
perr = 2;
|
||||
@@ -138,9 +147,14 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(strstr(s, "getenv")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
post = 2;
|
||||
} else if(strstr(s, "putenv")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "pread")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u, %d)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12), *(int32_t*)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "read")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "ioctl")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, 0x%x, %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(int32_t*)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
@@ -150,13 +164,13 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "rindex")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "my___xstat64")==s) {
|
||||
} else if(strstr(s, "__xstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strcmp(s, "my___xstat")==0) {
|
||||
} else if(strcmp(s, "__xstat")==0) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "my___lxstat64")==s) {
|
||||
} else if(strstr(s, "__lxstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "sem_timedwait")==s) {
|
||||
@@ -174,10 +188,10 @@ void x86Int3(x86emu_t* emu)
|
||||
int16_t* p16 = *(int16_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/0x%x], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "my_mmap64")) {
|
||||
} else if(!strcmp(s, "mmap64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %lld)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int64_t*)(R_ESP+24));
|
||||
perr = 3;
|
||||
} else if(!strcmp(s, "my_mmap")) {
|
||||
} else if(!strcmp(s, "mmap")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %d)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int*)(R_ESP+24));
|
||||
perr = 3;
|
||||
} else if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
|
||||
@@ -190,54 +204,58 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%.127s\", \"%.127s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "strlen")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
|
||||
} else if(strstr(s, "my_vsnprintf")==s) {
|
||||
} else if(strstr(s, "vsnprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_vsprintf")==s) {
|
||||
} else if(strstr(s, "vsprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my___vsprintf_chk")==s) {
|
||||
} else if(strstr(s, "__vsprintf_chk")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %d, %zu, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(int*)(R_ESP+8), *(size_t*)(R_ESP+12), *(char**)(R_ESP+16), *(void**)(R_ESP+20));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my___snprintf_chk")==s) {
|
||||
} else if(strstr(s, "__snprintf_chk")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %d, %d, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(char**)(R_ESP+20), *(void**)(R_ESP+24));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_snprintf")==s) {
|
||||
} else if(strstr(s, "snprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(char**)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_sprintf")==s) {
|
||||
} else if(strstr(s, "sprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_printf")==s) {
|
||||
} else if(strstr(s, "printf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "my_wprintf")==s) {
|
||||
} else if(strstr(s, "wprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%S\"...)", tid, *(void**)(R_ESP), s, pu32?((wchar_t*)(pu32)):L"nil");
|
||||
} else if(strstr(s, "my___vswprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%S\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(wchar_t**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 6;
|
||||
} else if(strstr(s, "__vswprintf")==s) {
|
||||
if(*(size_t*)(R_ESP+12)<2) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %p, %p, %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16), *(void**)(R_ESP+20));
|
||||
} else {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%S\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(wchar_t**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 6;
|
||||
}
|
||||
} else if(strstr(s, "puts")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "fputs")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %p...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_fprintf")==s) {
|
||||
} else if(strstr(s, "fprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a __fprint_chk
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "my_vfprintf")==s) {
|
||||
} else if(strstr(s, "vfprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
@@ -246,9 +264,9 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "vkGetDeviceProcAddr")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_glXGetProcAddress")==s) {
|
||||
} else if(strstr(s, "glXGetProcAddress")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "my_sscanf")==s) {
|
||||
} else if(strstr(s, "sscanf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "vsscanf")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
@@ -270,14 +288,14 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(strstr(s, "udev_monitor_new_from_netlink")==s) {
|
||||
post = 5;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "my_syscall")) {
|
||||
} else if(!strcmp(s, "syscall")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %p, %p...)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s (%08X, %08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
}
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
printf_log(LOG_NONE, "%s =>", buff);
|
||||
if(!cycle_log) printf_log(LOG_NONE, "%s =>", buff);
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
w(emu, addr); // some function never come back, so unlock the mutex first!
|
||||
if(post)
|
||||
@@ -308,7 +326,10 @@ void x86Int3(x86emu_t* emu)
|
||||
else if(perr==3 && ((int)R_EAX)==-1)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
printf_log(LOG_NONE, " return 0x%08X%s%s\n", R_EAX, buff2, buff3);
|
||||
if(cycle_log)
|
||||
snprintf(buffret, 127, "0x%X%s%s", R_EAX, buff2, buff3);
|
||||
else
|
||||
printf_log(LOG_NONE, " return 0x%08X%s%s\n", R_EAX, buff2, buff3);
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
} else
|
||||
w(emu, addr);
|
||||
|
||||
@@ -165,14 +165,6 @@ Implements the INC instruction and side effects.
|
||||
static inline uint32_t inc32(x86emu_t *emu, uint32_t d)
|
||||
{
|
||||
CHECK_FLAGS(emu);
|
||||
if(emu->df == d_shr32) {
|
||||
// workaround for some wine trickery
|
||||
uint32_t cnt = emu->op2;
|
||||
if (cnt > 0) {
|
||||
uint32_t cc = emu->op1 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->df = d_inc32;
|
||||
|
||||
+7
-4
@@ -46,6 +46,9 @@ int Run(x86emu_t *emu, int step)
|
||||
int64_t ll;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx87_regs_t *opem, eam1;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
#endif
|
||||
|
||||
if(emu->quit)
|
||||
return 0;
|
||||
@@ -101,7 +104,7 @@ int Run(x86emu_t *emu, int step)
|
||||
|
||||
static const void* opcodes0f[256] = {
|
||||
&&_0f_0x00, &&_0f_0x01, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
|
||||
&&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_default, &&_default, &&_default, //0x08-0x0F
|
||||
&&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_0f_0x0D, &&_0f_0x0E, &&_default, //0x08-0x0F
|
||||
&&_0f_0x10, &&_0f_0x11, &&_0f_0x12, &&_0f_0x13, &&_0f_0x14, &&_0f_0x15, &&_0f_0x16, &&_0f_0x17, //0x10-0x17
|
||||
&&_0f_0x18, &&_default, &&_0f_0x1A, &&_0f_0x1B, &&_default ,&&_default, &&_default, &&_0f_0x1F, //0x18-0x1F
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
|
||||
@@ -138,11 +141,11 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_66_0x00_0, &&_66_0x00_1, &&_66_0x00_2, &&_66_0x00_3, &&_66_0x00_4 ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
|
||||
&&_66_0x08_0, &&_66_0x08_1, &&_66_0x08_2, &&_66_0x08_3, &&_66_0x08_4 ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
|
||||
&&_66_0x10_0, &&_66_0x10_1, &&_66_0x10_2, &&_66_0x10_3, &&_66_0x10_4 ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
|
||||
&&_66_0x18_0, &&_66_0x18_1, &&_66_0x18_2, &&_66_0x18_3, &&_66_0x18_4 ,&&_66_0x18_5, &&_default, &&_66_0x1F, //0x18-0x1F
|
||||
&&_66_0x18_0, &&_66_0x18_1, &&_66_0x18_2, &&_66_0x18_3, &&_66_0x18_4 ,&&_66_0x18_5, &&_66_0x1E, &&_66_0x1F, //0x18-0x1F
|
||||
&&_66_0x20_0, &&_66_0x20_1, &&_66_0x20_2, &&_66_0x20_3, &&_66_0x20_4 ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
|
||||
&&_66_0x28_0, &&_66_0x28_1, &&_66_0x28_2, &&_66_0x28_3, &&_66_0x28_4 ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
|
||||
&&_66_0x30_0, &&_66_0x30_1, &&_66_0x30_2, &&_66_0x30_3, &&_66_0x30_4 ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
|
||||
&&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_default, &&_default, //0x38-0x3F
|
||||
&&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_66_0x3E, &&_default, //0x38-0x3F
|
||||
&&_66_0x40, &&_66_0x41, &&_66_0x42, &&_66_0x43, &&_66_0x44, &&_66_0x45, &&_66_0x46, &&_66_0x47,
|
||||
&&_66_0x48, &&_66_0x49, &&_66_0x4A, &&_66_0x4B, &&_66_0x4C, &&_66_0x4D, &&_66_0x4E, &&_66_0x4F,
|
||||
&&_66_0x50, &&_66_0x51, &&_66_0x52, &&_66_0x53, &&_66_0x54, &&_66_0x55, &&_66_0x56, &&_66_0x57, //0x50-0x57
|
||||
@@ -165,7 +168,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_66_0xD9, &&_default, &&_default, &&_default ,&&_66_0xDD, &&_default, &&_default, //0xD8-0xDF
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE8-0xEF
|
||||
&&_66_0xF0, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_default, &&_default, &&_66_0xF7,
|
||||
&&_66_0xF0, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_66_0xF5, &&_default, &&_66_0xF7,
|
||||
&&_66_0xF8, &&_66_0xF9, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
|
||||
};
|
||||
|
||||
|
||||
+216
-49
@@ -536,63 +536,73 @@ void RunLock(x86emu_t *emu)
|
||||
#endif
|
||||
break;
|
||||
case 0xC7: /* CMPXCHG8B Gq */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
CHECK_FLAGS(emu);
|
||||
#ifdef DYNAREC
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned!!!
|
||||
uint64_t ref = R_EDX;
|
||||
ref = ref<<32 | R_EAX;
|
||||
void* p = (void*)(((uintptr_t)ED + 3)&~3);
|
||||
int d = (((uintptr_t)p - (uintptr_t)ED))*8;
|
||||
do {
|
||||
uint64_t m = *(uint64_t*)ED;
|
||||
m&=~((0xffffffffLL)<<d);
|
||||
tmp32u = arm_lock_read_d(p);
|
||||
m|=((uint64_t)tmp32u)<<d;
|
||||
if(ref == m) {
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned!!!
|
||||
uint64_t ref = R_EDX;
|
||||
ref = ref<<32 | R_EAX;
|
||||
void* p = (void*)(((uintptr_t)ED + 3)&~3);
|
||||
int d = (((uintptr_t)p - (uintptr_t)ED))*8;
|
||||
do {
|
||||
uint64_t m = *(uint64_t*)ED;
|
||||
m&=~((0xffffffffLL)<<d);
|
||||
tmp32u = arm_lock_read_d(p);
|
||||
m|=((uint64_t)tmp32u)<<d;
|
||||
if(ref == m) {
|
||||
SET_FLAG(F_ZF);
|
||||
m = ((uint64_t)R_ECX)<<32 | R_EBX;
|
||||
tmp32u2 = m>>d;
|
||||
tmp32s = arm_lock_write_d(p, tmp32u2);
|
||||
if(!tmp32s)
|
||||
*(uint64_t*)ED = m;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = m&0xffffffff;
|
||||
R_EDX = m>>32;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else
|
||||
do {
|
||||
arm_lock_read_dd(&tmp32u, &tmp32u2, ED);
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm_lock_write_dd(R_EBX, R_ECX, ED);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
m = ((uint64_t)R_ECX)<<32 | R_EBX;
|
||||
tmp32u2 = m>>d;
|
||||
tmp32s = arm_lock_write_d(p, tmp32u2);
|
||||
if(!tmp32s)
|
||||
*(uint64_t*)ED = m;
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = m&0xffffffff;
|
||||
R_EDX = m>>32;
|
||||
tmp32s = 0;
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else
|
||||
do {
|
||||
arm_lock_read_dd(&tmp32u, &tmp32u2, ED);
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm_lock_write_dd(R_EBX, R_ECX, ED);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP;
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0xC7 0x%02X 0x%02X\n", nextop, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// trigger invalid lock?
|
||||
@@ -798,6 +808,59 @@ void RunLock66(x86emu_t *emu)
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#ifdef DYNAREC
|
||||
if((uintptr_t)ED&1) {
|
||||
//meh.
|
||||
do {
|
||||
tmp16u = ED->dword[0];
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= arm_lock_read_b(ED);
|
||||
tmp16u = inc16(emu, tmp16u);
|
||||
} while(arm_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->dword[0] = tmp16u;
|
||||
} else
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
} while(arm_lock_write_h(ED, inc16(emu, tmp16u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#ifdef DYNAREC
|
||||
if((uintptr_t)ED&1) {
|
||||
//meh.
|
||||
do {
|
||||
tmp16u = ED->dword[0];
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= arm_lock_read_b(ED);
|
||||
tmp16u = dec16(emu, tmp16u);
|
||||
} while(arm_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->dword[0] = tmp16u;
|
||||
} else
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
} while(arm_lock_write_h(ED, dec16(emu, tmp16u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ip=R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip-=3; // unfetch nextop, F0 & 66
|
||||
UnimpOpcode(emu);
|
||||
@@ -889,6 +952,18 @@ void RunGS(x86emu_t *emu)
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x39: /* CMP Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x3B: /* CMP Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
@@ -1134,6 +1209,7 @@ void RunFS(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uint8_t opcode = F8;
|
||||
int8_t tmp8s;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
@@ -1263,6 +1339,93 @@ void RunFS(x86emu_t *emu)
|
||||
tmp32u = F32;
|
||||
GD.dword[0] = imul32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
|
||||
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
|
||||
case BASE+0x0: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_OF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x1: \
|
||||
PREFIX \
|
||||
if(!ACCESS_FLAG(F_OF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x2: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_CF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x3: \
|
||||
PREFIX \
|
||||
if(!ACCESS_FLAG(F_CF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x4: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_ZF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x5: \
|
||||
PREFIX \
|
||||
if(!ACCESS_FLAG(F_ZF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x6: \
|
||||
PREFIX \
|
||||
if((ACCESS_FLAG(F_ZF) || ACCESS_FLAG(F_CF))) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x7: \
|
||||
PREFIX \
|
||||
if(!(ACCESS_FLAG(F_ZF) || ACCESS_FLAG(F_CF))) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x8: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_SF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0x9: \
|
||||
PREFIX \
|
||||
if(!ACCESS_FLAG(F_SF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0xA: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_PF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0xB: \
|
||||
PREFIX \
|
||||
if(!ACCESS_FLAG(F_PF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0xC: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_SF) != ACCESS_FLAG(F_OF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0xD: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_SF) == ACCESS_FLAG(F_OF)) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0xE: \
|
||||
PREFIX \
|
||||
if(ACCESS_FLAG(F_ZF) || (ACCESS_FLAG(F_SF) != ACCESS_FLAG(F_OF))) \
|
||||
CONDITIONAL \
|
||||
break; \
|
||||
case BASE+0xF: \
|
||||
PREFIX \
|
||||
if(!ACCESS_FLAG(F_ZF) && (ACCESS_FLAG(F_SF) == ACCESS_FLAG(F_OF))) \
|
||||
CONDITIONAL \
|
||||
break;
|
||||
GOCOND(0x70
|
||||
, tmp8s = F8S; CHECK_FLAGS(emu);
|
||||
, ip += tmp8s;
|
||||
) /* Jxx Ib */
|
||||
#undef GOCOND
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
case 0x82: // 0x82 and 0x80 are the same opcodes it seems?
|
||||
nextop = F8;
|
||||
@@ -1349,6 +1512,10 @@ void RunFS(x86emu_t *emu)
|
||||
*(uint32_t*)((tlsdata) + tmp32s) = R_EAX;
|
||||
break;
|
||||
|
||||
case 0xA8: /* TEST AL, Ib */
|
||||
test8(emu, R_AL, F8);
|
||||
break;
|
||||
|
||||
case 0xC0: /* GRP2 Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
|
||||
+345
-11
@@ -38,6 +38,9 @@ void Run660F(x86emu_t *emu)
|
||||
int32_t tmp32s;
|
||||
sse_regs_t *opex, eax1, *opx2;
|
||||
mmx87_regs_t *opem;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
#endif
|
||||
|
||||
|
||||
opcode = F8;
|
||||
@@ -366,6 +369,23 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x14: /* BLENDVPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<4; ++i) {
|
||||
if(emu->xmm[0].ud[i]&0x80000000)
|
||||
GX.ud[i] = EX->ud[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x17: // PTEST GX, EX
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!((GX.q[0]&EX->q[0])|(GX.q[1]&EX->q[1])), F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!(((~GX.q[0])&EX->q[0])|((~GX.q[1])&EX->q[1])), F_CF);
|
||||
break;
|
||||
|
||||
case 0x1C: /* PABSB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -388,6 +408,104 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20: /* PMOVSXBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=7; i>=0; --i)
|
||||
GX.sw[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x21: /* PMOVSXBD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.sd[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x22: /* PMOVSXBQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x23: /* PMOVSXWD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.sd[i] = EX->sw[i];
|
||||
break;
|
||||
case 0x24: /* PMOVSXWQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = EX->sw[i];
|
||||
break;
|
||||
case 0x25: /* PMOVSXDQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x30: /* PMOVZXBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=7; i>=0; --i)
|
||||
GX.uw[i] = EX->ub[i];
|
||||
break;
|
||||
case 0x31: /* PMOVZXBD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.ud[i] = EX->ub[i];
|
||||
break;
|
||||
case 0x32: /* PMOVZXBQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.q[i] = EX->ub[i];
|
||||
break;
|
||||
case 0x33: /* PMOVZXWD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.ud[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x34: /* PMOVZXWQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.q[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x35: /* PMOVZXDQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.q[i] = EX->ud[i];
|
||||
break;
|
||||
|
||||
case 0x39: /* PMINSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX.sd[i]>EX->sd[i])
|
||||
GX.sd[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x3D: /* PMAXSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX.sd[i]<EX->sd[i])
|
||||
GX.sd[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x40: /* PMULLD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<4; ++i) {
|
||||
GX.sd[i] *= EX->sd[i];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
@@ -397,6 +515,112 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x3A: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x08: // roundps GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
switch((tmp8u & 4) ? ((emu->mxcsr >> 13) & 3) : (tmp8u & 3))
|
||||
{
|
||||
case ROUND_Nearest:
|
||||
GX.f[0] = nearbyint(EX->f[0]);
|
||||
GX.f[1] = nearbyint(EX->f[1]);
|
||||
GX.f[2] = nearbyint(EX->f[2]);
|
||||
GX.f[3] = nearbyint(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.f[0] = floor(EX->f[0]);
|
||||
GX.f[1] = floor(EX->f[1]);
|
||||
GX.f[2] = floor(EX->f[2]);
|
||||
GX.f[3] = floor(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.f[0] = ceil(EX->f[0]);
|
||||
GX.f[1] = ceil(EX->f[1]);
|
||||
GX.f[2] = ceil(EX->f[2]);
|
||||
GX.f[3] = ceil(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.f[0] = trunc(EX->f[0]);
|
||||
GX.f[1] = trunc(EX->f[1]);
|
||||
GX.f[2] = trunc(EX->f[2]);
|
||||
GX.f[3] = trunc(EX->f[3]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x09: // roundpd GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
switch((tmp8u & 4) ? ((emu->mxcsr >> 13) & 3) : (tmp8u & 3))
|
||||
{
|
||||
case ROUND_Nearest:
|
||||
GX.d[0] = nearbyint(EX->d[0]);
|
||||
GX.d[1] = nearbyint(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.d[0] = floor(EX->d[0]);
|
||||
GX.d[1] = floor(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.d[0] = ceil(EX->d[0]);
|
||||
GX.d[1] = ceil(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.d[0] = trunc(EX->d[0]);
|
||||
GX.d[1] = trunc(EX->d[1]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0A: // roundss GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
switch((tmp8u & 4) ? ((emu->mxcsr >> 13) & 3) : (tmp8u & 3))
|
||||
{
|
||||
case ROUND_Nearest:
|
||||
GX.f[0] = nearbyint(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.f[0] = floor(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.f[0] = ceil(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.f[0] = trunc(EX->f[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0B: // roundsd GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
switch((tmp8u & 4) ? ((emu->mxcsr >> 13) & 3) : (tmp8u & 3))
|
||||
{
|
||||
case ROUND_Nearest:
|
||||
GX.d[0] = nearbyint(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.d[0] = floor(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.d[0] = ceil(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.d[0] = trunc(EX->d[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0E: /* PBLENDW Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
for (int i=0; i<8; ++i) {
|
||||
if(tmp8u&(1<<i))
|
||||
GX.uw[i] = EX->uw[i];
|
||||
}
|
||||
break;
|
||||
case 0x0F: // PALIGNR GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -434,6 +658,37 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x16: // PEXTRD ED, GX, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
ED->dword[0] = GX.ud[tmp8u&3];
|
||||
break;
|
||||
|
||||
case 0x20: // PINSRB GX, Ed, Ib
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
GX.ub[tmp8u&0xF] = ED->byte[0]; // only low 8bits
|
||||
break;
|
||||
case 0x21: // INSERTPS GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)==0xC0) tmp8s = (tmp8u>>6)&3; else tmp8s = 0;
|
||||
GX.ud[(tmp8u>>4)&3] = EX->ud[tmp8s];
|
||||
for(int i=0; i<4; ++i)
|
||||
if(tmp8u&(1<<i))
|
||||
GX.ud[i] = 0;
|
||||
break;
|
||||
case 0x22: // PINSRD GX, ED, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
GX.ud[tmp8u&0x3] = ED->dword[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
@@ -450,8 +705,14 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x51: /* SQRTPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] = sqrt(EX->d[0]);
|
||||
GX.d[1] = sqrt(EX->d[1]);
|
||||
for (int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
if(EX->d[i]<0.0) // on x86, default nan are negative
|
||||
GX.d[i] = -NAN; // but input NAN are not touched (so sqrt(+nan) -> +nan)
|
||||
else
|
||||
#endif
|
||||
GX.d[i] = sqrt(EX->d[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x54: /* ANDPD Gx, Ex */
|
||||
@@ -481,14 +742,28 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x58: /* ADDPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] += EX->d[0];
|
||||
GX.d[1] += EX->d[1];
|
||||
for(int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
// add generate a -NAN only if doing inf + -inf
|
||||
if((isinf(GX.d[i]) && isinf(EX->d[i]) && (EX->q[i]&0x8000000000000000LL)!=(GX.q[i]&0x8000000000000000LL)))
|
||||
GX.d[i] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[i] += EX->d[i];
|
||||
}
|
||||
break;
|
||||
case 0x59: /* MULPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] *= EX->d[0];
|
||||
GX.d[1] *= EX->d[1];
|
||||
for(int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
// mul generate a -NAN only if doing (+/-)inf * (+/-)0
|
||||
if((isinf(GX.d[i]) && EX->d[i]==0.0) || (isinf(EX->d[i]) && GX.d[i]==0.0))
|
||||
GX.d[i] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[i] *= EX->d[i];
|
||||
}
|
||||
break;
|
||||
case 0x5A: /* CVTPD2PS Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -530,8 +805,15 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x5C: /* SUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] -= EX->d[0];
|
||||
GX.d[1] -= EX->d[1];
|
||||
for(int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
// sub generate a -NAN only if doing inf - inf
|
||||
if((isinf(GX.d[i]) && isinf(EX->d[i]) && (EX->q[i]&0x8000000000000000LL)==(GX.q[i]&0x8000000000000000LL)))
|
||||
GX.d[i] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[i] -= EX->d[i];
|
||||
}
|
||||
break;
|
||||
case 0x5D: /* MINPD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -544,8 +826,16 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x5E: /* DIVPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] /= EX->d[0];
|
||||
GX.d[1] /= EX->d[1];
|
||||
for (int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[i]) || isnan(EX->d[i]);
|
||||
#endif
|
||||
GX.d[i] /= EX->d[i];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[i]))
|
||||
GX.d[i] = -NAN;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0x5F: /* MAXPD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -834,11 +1124,50 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x7C: /* HADDPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[0]) || isnan(GX.d[1]);
|
||||
#endif
|
||||
GX.d[0] += GX.d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[0]))
|
||||
GX.d[0] = -NAN;
|
||||
#endif
|
||||
if(EX==&GX) {
|
||||
GX.d[1] = GX.d[0];
|
||||
} else {
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(EX->d[0]) || isnan(EX->d[1]);
|
||||
#endif
|
||||
GX.d[1] = EX->d[0] + EX->d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[1]))
|
||||
GX.d[1] = -NAN;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7D: /* HSUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[0]) || isnan(GX.d[1]);
|
||||
#endif
|
||||
GX.d[0] -= GX.d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[0]))
|
||||
GX.d[0] = -NAN;
|
||||
#endif
|
||||
if(EX==&GX) {
|
||||
GX.d[1] = GX.d[0];
|
||||
} else {
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(EX->d[0]) || isnan(EX->d[1]);
|
||||
#endif
|
||||
GX.d[1] = EX->d[0] - EX->d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[1]))
|
||||
GX.d[1] = -NAN;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1059,6 +1388,11 @@ void Run660F(x86emu_t *emu)
|
||||
GET_EB;
|
||||
GW.sword[0] = EB->sbyte[0];
|
||||
break;
|
||||
case 0xBF: /* MOVSX Gw,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
GW.sword[0] = EW->sword[0];
|
||||
break;
|
||||
|
||||
case 0xC1: /* XADD Gw,Ew */ // Xchange and Add
|
||||
nextop = F8;
|
||||
@@ -1467,4 +1801,4 @@ void Run660F(x86emu_t *emu)
|
||||
|
||||
R_EIP = ip;
|
||||
return;
|
||||
}
|
||||
}
|
||||
+107
-16
@@ -19,6 +19,7 @@
|
||||
#include "x86run.h"
|
||||
#include "librarian.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
#ifdef HAVE_TRACE
|
||||
#include "x86trace.h"
|
||||
#endif
|
||||
@@ -62,6 +63,7 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
return 0;
|
||||
emu->quit = 0;
|
||||
}
|
||||
MarkElfInitDone(my_context->elfs[0]);
|
||||
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main);
|
||||
// call main and finish
|
||||
PushExit(emu);
|
||||
@@ -70,7 +72,7 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
DynaRun(emu);
|
||||
|
||||
emu->quit = 1; // finished!
|
||||
return 0;
|
||||
return (int)R_EAX;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -339,6 +341,51 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_rcl8:
|
||||
cc = (emu->op1 >> (8 - emu->op2)) & 0x1;
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->op2 == 1 && XOR2(cc + ((emu->res >> 6) & 0x2)), F_OF);
|
||||
break;
|
||||
case d_rcl16:
|
||||
cc = (emu->op1 >> (16 - emu->op2)) & 0x1;
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->op2 == 1 && XOR2(cc + ((emu->res >> 14) & 0x2)), F_OF);
|
||||
break;
|
||||
case d_rcl32:
|
||||
cc = (emu->op1 >> (32 - emu->op2)) & 0x1;
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->op2 == 1 && XOR2(cc + ((emu->res >> 30) & 0x2)), F_OF);
|
||||
break;
|
||||
case d_rcr8:
|
||||
cnt = emu->op2 % 9;
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x1, F_CF);
|
||||
cc = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc + ((emu->op1 >> 6) & 0x2)), F_OF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (cnt - 1)) & 0x1, F_CF);
|
||||
}
|
||||
break;
|
||||
case d_rcr16:
|
||||
cnt = emu->op2 % 17;
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x1, F_CF);
|
||||
cc = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc + ((emu->op1 >> 14) & 0x2)), F_OF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (cnt - 1)) & 0x1, F_CF);
|
||||
}
|
||||
break;
|
||||
case d_rcr32:
|
||||
cnt = emu->op2 % 33;
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x1, F_CF);
|
||||
cc = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc + ((emu->op1 >> 30) & 0x2)), F_OF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (cnt - 1)) & 0x1, F_CF);
|
||||
}
|
||||
break;
|
||||
case d_shl8:
|
||||
if (emu->op2 < 8) {
|
||||
cnt = emu->op2 % 8;
|
||||
@@ -512,7 +559,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
bc = (emu->res & ((~emu->op1) | emu->op2)) | ((~emu->op1) & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -521,7 +568,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
bc = (emu->res & ((~emu->op1) | emu->op2)) | ((~emu->op1) & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -530,7 +577,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
bc = (emu->res & ((~emu->op1) | emu->op2)) | ((~emu->op1) & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -727,14 +774,21 @@ const char* getAddrFunctionName(uintptr_t addr)
|
||||
static char ret[1000];
|
||||
uint32_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, addr), (void*)addr, &start, &sz);
|
||||
elfheader_t* elf = FindElfAddress(my_context, addr);
|
||||
const char* symbname = FindNearestSymbolName(elf, (void*)addr, &start, &sz);
|
||||
if(symbname && addr>=start && (addr<(start+sz) || !sz)) {
|
||||
if(addr==start)
|
||||
sprintf(ret, "%s/%s", ElfName(FindElfAddress(my_context, addr)), symbname);
|
||||
if(symbname[0]=='\0')
|
||||
sprintf(ret, "%s + 0x%x", ElfName(elf), addr - (uintptr_t)GetBaseAddress(elf));
|
||||
else if(addr==start)
|
||||
sprintf(ret, "%s/%s", ElfName(elf), symbname);
|
||||
else
|
||||
sprintf(ret, "%s/%s + %d", ElfName(FindElfAddress(my_context, addr)), symbname, addr - start);
|
||||
} else
|
||||
sprintf(ret, "???");
|
||||
sprintf(ret, "%s/%s + %d", ElfName(elf), symbname, addr - start);
|
||||
} else {
|
||||
if(elf) {
|
||||
sprintf(ret, "%s + 0x%x", ElfName(elf), addr - (uintptr_t)GetBaseAddress(elf));
|
||||
} else
|
||||
sprintf(ret, "???");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -751,11 +805,46 @@ void printFunctionAddr(uintptr_t nextaddr, const char* text)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
extern uint64_t start_cnt;
|
||||
#define PK(a) (*(uint8_t*)(ip+a))
|
||||
#define PK32(a) (*(int32_t*)((uint8_t*)(ip+a)))
|
||||
|
||||
uintptr_t evalED(x86emu_t* emu, uintptr_t ip) {
|
||||
uint8_t nextop = PK(0);
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return emu->regs[(nextop&7)].dword[0];
|
||||
else {
|
||||
++ip;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = PK(0);
|
||||
++ip;
|
||||
uintptr_t base = ((sib&0x7)==5)?(PK32(0)):(emu->regs[(sib&0x7)].dword[0]);
|
||||
base += (emu->sbiidx[(sib>>3)&7]->sdword[0] << (sib>>6)); \
|
||||
return *(uintptr_t*)base;
|
||||
} else if((nextop&7)==5) {
|
||||
return *(uintptr_t*)PK32(0);
|
||||
} else {
|
||||
return *(uintptr_t*)emu->regs[nextop&7].dword[0];
|
||||
}
|
||||
} else {
|
||||
uintptr_t base;
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = PK(0);
|
||||
++ip;
|
||||
base = emu->regs[(sib&0x7)].dword[0];
|
||||
base += (emu->sbiidx[(sib>>3)&7]->sdword[0] << (sib>>6));
|
||||
} else {
|
||||
base = emu->regs[(nextop&0x7)].dword[0];
|
||||
} \
|
||||
base+=(nextop&0x80)?(*(int32_t*)ip):(*(int8_t*)ip);
|
||||
return *(uintptr_t*)base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
extern uint64_t start_cnt;
|
||||
|
||||
void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
{
|
||||
if(start_cnt) --start_cnt;
|
||||
@@ -786,7 +875,7 @@ void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_NONE, "%s", DecodeX86Trace(my_context->dec, ip));
|
||||
uint8_t peek = PK(0);
|
||||
const uint8_t peek = PK(0);
|
||||
if(peek==0xC3 || peek==0xC2) {
|
||||
printf_log(LOG_NONE, " => %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(*(uintptr_t*)(R_ESP), "=> ");
|
||||
@@ -797,9 +886,11 @@ void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
uintptr_t nextaddr = ip + 5 + PK32(1);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(peek==0xFF) {
|
||||
if(PK(1)==0x25) {
|
||||
uintptr_t nextaddr = ip + 6 + PK32(2);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
const uint8_t pk1 = PK(1);
|
||||
if(((pk1>>3)&7)==2 || ((pk1>>3)&7)==4) { // jmp/call near
|
||||
uintptr_t nextaddr = (uintptr_t)getAlternate((void*)evalED(emu, ip+1));
|
||||
printf_log(LOG_NONE, " => %p", nextaddr);
|
||||
printFunctionAddr(nextaddr, " / ");
|
||||
}
|
||||
}
|
||||
printf_log(LOG_NONE, "\n");
|
||||
|
||||
+141
-46
@@ -72,13 +72,13 @@ void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot, int fla
|
||||
void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
|
||||
int my_munmap(x86emu_t* emu, void* addr, unsigned long length);
|
||||
int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot);
|
||||
void* ElfSetBrk(void* newbrk);
|
||||
|
||||
// cannot include <fcntl.h>, it conflict with some asm includes...
|
||||
#ifndef O_NONBLOCK
|
||||
#define O_NONBLOCK 04000
|
||||
#endif
|
||||
#undef fcntl
|
||||
int fcntl(int fd, int cmd, ... /* arg */ );
|
||||
int my_fcntl(int fd, int cmd, ... /* arg */ );
|
||||
|
||||
// Syscall table for x86 can be found here: http://shell-storm.org/shellcode/files/syscalls.html
|
||||
typedef struct scwrap_s {
|
||||
@@ -112,7 +112,7 @@ scwrap_t syscallwrap[] = {
|
||||
{ 40, __NR_rmdir, 1 },
|
||||
{ 41, __NR_dup, 1 },
|
||||
{ 42, __NR_pipe, 1 },
|
||||
{ 45, __NR_brk, 1 },
|
||||
//{ 45, __NR_brk, 1 },
|
||||
{ 47, __NR_getgid, 0 },
|
||||
{ 49, __NR_geteuid, 0 },
|
||||
{ 50, __NR_getegid, 0 },
|
||||
@@ -192,6 +192,8 @@ scwrap_t syscallwrap[] = {
|
||||
{ 175, __NR_rt_sigprocmask, 4 },
|
||||
{ 179, __NR_rt_sigsuspend, 2 },
|
||||
{ 183, __NR_getcwd, 2 },
|
||||
{ 184, __NR_capget, 2},
|
||||
{ 185, __NR_capset, 2},
|
||||
{ 186, __NR_sigaltstack, 2 }, // neeed wrap or something?
|
||||
{ 191, __NR_ugetrlimit, 2 },
|
||||
// { 192, __NR_mmap2, 6},
|
||||
@@ -204,6 +206,9 @@ scwrap_t syscallwrap[] = {
|
||||
{ 201, __NR_geteuid32, 0 },
|
||||
{ 202, __NR_getegid32, 0 },
|
||||
{ 208, __NR_setresuid32, 3 },
|
||||
{ 209, __NR_getresuid32, 3 },
|
||||
{ 210, __NR_setresgid32, 3 },
|
||||
{ 211, __NR_getresgid32, 3 },
|
||||
#else
|
||||
// PowerPC uses the same syscalls for 32/64 bit processes.
|
||||
{ 199, __NR_getuid, 0 },
|
||||
@@ -211,6 +216,9 @@ scwrap_t syscallwrap[] = {
|
||||
{ 201, __NR_geteuid, 0 },
|
||||
{ 202, __NR_getegid, 0 },
|
||||
{ 208, __NR_setresuid, 3 },
|
||||
{ 209, __NR_getresuid, 3 },
|
||||
{ 210, __NR_setresgid, 3 },
|
||||
{ 211, __NR_getresgid, 3 },
|
||||
#endif
|
||||
{ 220, __NR_getdents64, 3 },
|
||||
//{ 221, __NR_fcntl64, 3 },
|
||||
@@ -246,6 +254,9 @@ scwrap_t syscallwrap[] = {
|
||||
#ifdef __NR_memfd_create
|
||||
{ 356, __NR_memfd_create, 2},
|
||||
#endif
|
||||
#ifdef __NR_futex_waitv
|
||||
{ 449, __NR_futex_waitv, 5},
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mmap_arg_struct {
|
||||
@@ -317,9 +328,42 @@ int clone_fn(void* arg)
|
||||
DynaRun(emu);
|
||||
int ret = R_EAX;
|
||||
FreeX86Emu(&emu);
|
||||
my_context->stack_clone_used = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef __NR_ipc
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
|
||||
static int my_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
|
||||
{
|
||||
#define IPC_SEMOP 1
|
||||
#define IPC_SEMGET 2
|
||||
#define IPC_SEMCTL 3
|
||||
#define IPC_SEMTIMEDOP 4
|
||||
#define IPC_MSGSND 11
|
||||
#define IPC_MSGRCV 12
|
||||
#define IPC_MSGGET 13
|
||||
#define IPC_MSGCTL 14
|
||||
#define IPC_SHMAT 21
|
||||
#define IPC_SHMDT 22
|
||||
#define IPC_SHMGET 23
|
||||
#define IPC_SHMCTL 24
|
||||
int version;
|
||||
version = call>>16;
|
||||
call &= 0xffff;
|
||||
switch (call) {
|
||||
case IPC_SHMGET:
|
||||
return semget(first, second, third);
|
||||
default:
|
||||
printf_log(LOG_INFO, "Unsuported IPC call %d (version %d)\n", call, version);
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void EXPORT x86Syscall(x86emu_t *emu)
|
||||
{
|
||||
RESET_FLAGS(emu);
|
||||
@@ -387,21 +431,14 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
R_EAX = time(NULL);
|
||||
break;
|
||||
#endif
|
||||
case 45: // sys_brk
|
||||
R_EAX = (uintptr_t)ElfSetBrk((void*)R_EBX);
|
||||
break;
|
||||
case 54: // sys_ioctl
|
||||
R_EAX = (uint32_t)ioctl((int)R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
break;
|
||||
case 55: // sys_fcntl
|
||||
if(R_ECX==4) {
|
||||
// filter out O_NONBLOCK so old stacally linked games that access X11 don't get EAGAIN error sometimes
|
||||
int tmp = of_convert((int)R_EDX)&(~O_NONBLOCK);
|
||||
if(R_EDX==0xFFFFF7FF) {
|
||||
// special case for ~O_NONBLOCK...
|
||||
int flags = fcntl(R_EBX, 3);
|
||||
tmp = flags&~O_NONBLOCK;
|
||||
}
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, tmp);
|
||||
} else
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
|
||||
R_EAX = (uint32_t)my_fcntl((int)R_EBX, (int)R_ECX, R_EDX);
|
||||
break;
|
||||
#ifndef __NR_getrlimit
|
||||
case 76: // sys_getrlimit... this is the old version, using the new one. Maybe some tranform is needed?
|
||||
@@ -476,47 +513,56 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
case 110: // iopl
|
||||
R_EAX = 0; // only on x86, so return 0...
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_ipc
|
||||
case 117: // ipc
|
||||
R_EAX = (uint32_t)my_ipc(R_EBX, (int)R_ECX, (int)R_EDX, (int)R_ESI, (void*)R_EDI, (long)R_EBP);
|
||||
break;
|
||||
#endif
|
||||
case 119: // sys_sigreturn
|
||||
emu->quit = 1; // we should be inside a DynaCall in a sigaction callback....
|
||||
break;
|
||||
case 120: // clone
|
||||
// x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
|
||||
// so flags=R_EBX, stack=R_ECX, parent_tid=R_EDX, tls=R_ESI, child_tid=R_EDI
|
||||
if(R_ECX)
|
||||
{
|
||||
// should wrap that using a thread...
|
||||
//struct x86_pt_regs *regs = (struct x86_pt_regs *)R_EDI;
|
||||
// lets duplicate the emu
|
||||
void* stack_base = (void*)R_ECX;
|
||||
int stack_size = 0;
|
||||
if(!R_ECX) {
|
||||
// allocate a new stack...
|
||||
stack_size = 1024*1024;
|
||||
//stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
|
||||
int currstack = 0;
|
||||
if((R_ESP>=(uintptr_t)emu->init_stack) && (R_ESP<=((uintptr_t)emu->init_stack+emu->size_stack)))
|
||||
currstack = 1;
|
||||
stack_size = (currstack)?emu->size_stack:(1024*1024);
|
||||
stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
|
||||
// copy value from old stack to new stack
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
if(currstack)
|
||||
memcpy(stack_base, emu->init_stack, stack_size);
|
||||
else {
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base+stack_size-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
}
|
||||
}
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (R_ECX)?0:1);
|
||||
SetupX86Emu(newemu);
|
||||
CloneEmu(newemu, emu);
|
||||
SetESP(newemu, (uintptr_t)stack_base);
|
||||
// setup registers
|
||||
/*if(regs) {
|
||||
SetEAX(newemu, regs->eax);
|
||||
SetEBX(newemu, regs->ebx);
|
||||
SetECX(newemu, regs->ecx);
|
||||
SetEDX(newemu, regs->edx);
|
||||
SetEDI(newemu, regs->edi);
|
||||
SetESI(newemu, regs->esi);
|
||||
SetEBP(newemu, regs->ebp);
|
||||
SetESP(newemu, (uintptr_t)stack_base - size_to_copy);
|
||||
Push32(newemu, 0);
|
||||
PushExit(newemu);
|
||||
void* mystack = NULL;
|
||||
if(my_context->stack_clone_used) {
|
||||
mystack = box_malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it
|
||||
} else {
|
||||
if(!my_context->stack_clone)
|
||||
my_context->stack_clone = box_malloc(1024*1024);
|
||||
mystack = my_context->stack_clone;
|
||||
my_context->stack_clone_used = 1;
|
||||
}
|
||||
SetESP(newemu, (uintptr_t)stack_base - size_to_copy);*/
|
||||
void* mystack = (R_EBX&CLONE_VM)?malloc(1024*1024):NULL; // stack for own process... memory leak, but no practical way to remove it
|
||||
int ret = clone(clone_fn, (void*)((R_EBX&CLONE_VM)?((uintptr_t)mystack+1024*1024):0), R_EBX, newemu, R_ESI, R_EDI, R_EBP);
|
||||
//int r = syscall(__NR_clone, R_EBX, (R_EBX&CLONE_VM)?((uintptr_t)mystack):0, R_EDX, R_ESI, NULL); // cannot use that syscall in C: how to setup the stack?!
|
||||
R_EAX = ret;
|
||||
long ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), R_EBX, newemu, R_EDX, R_ESI, R_EDI);
|
||||
R_EAX = (uint32_t)ret;
|
||||
}
|
||||
else
|
||||
R_EAX = (uint32_t)syscall(__NR_clone, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
break;
|
||||
case 122: // uname
|
||||
{
|
||||
@@ -585,11 +631,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
case 221: // sys_fcntl64
|
||||
if(R_ECX==4) {
|
||||
int tmp = of_convert((int)R_EDX);
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, R_ECX, tmp);
|
||||
} else
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
|
||||
R_EAX = (uint32_t)my_fcntl((int)R_EBX, (int)R_ECX, R_EDX);
|
||||
break;
|
||||
case 243: // set_thread_area
|
||||
R_EAX = my_set_thread_area((thread_area_t*)R_EBX);
|
||||
@@ -639,6 +681,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
|
||||
uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
{
|
||||
static uint32_t warned = 0;
|
||||
uint32_t s = u32(0);
|
||||
printf_log(LOG_DEBUG, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_EIP, s, s, (void*)u32(4), (void*)u32(8), (void*)u32(12), (void*)u32(16), (void*)u32(20));
|
||||
// check wrapper first
|
||||
@@ -675,14 +718,63 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
return (uint32_t)close(i32(4));
|
||||
case 11: // execve
|
||||
return (uint32_t)my_execve(emu, p(4), p(8), p(12));
|
||||
case 45: // brk
|
||||
return (uintptr_t)ElfSetBrk(p(4));
|
||||
case 91: // munmap
|
||||
return (uint32_t)my_munmap(emu, p(4), u32(8));
|
||||
#ifndef __NR_ipc
|
||||
case 117: // ipc
|
||||
return (uint32_t)my_ipc(u32(4), i32(8), i32(12), i32(16), p(20), i32(24));
|
||||
#endif
|
||||
case 120: // clone
|
||||
// x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
|
||||
// so flags=u(4), stack=p(8), parent_tid=p(12), tls=p(16), child_tid=p(20)
|
||||
if(p(8))
|
||||
{
|
||||
void* stack_base = p(8);
|
||||
int stack_size = 0;
|
||||
if(!stack_base) {
|
||||
// allocate a new stack...
|
||||
int currstack = 0;
|
||||
if((R_ESP>=(uintptr_t)emu->init_stack) && (R_ESP<=((uintptr_t)emu->init_stack+emu->size_stack)))
|
||||
currstack = 1;
|
||||
stack_size = (currstack)?emu->size_stack:(1024*1024);
|
||||
stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
|
||||
// copy value from old stack to new stack
|
||||
if(currstack)
|
||||
memcpy(stack_base, emu->init_stack, stack_size);
|
||||
else {
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base+stack_size-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
}
|
||||
}
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (p(8))?0:1);
|
||||
SetupX86Emu(newemu);
|
||||
CloneEmu(newemu, emu);
|
||||
Push32(newemu, 0);
|
||||
PushExit(newemu);
|
||||
void* mystack = NULL;
|
||||
if(my_context->stack_clone_used) {
|
||||
mystack = box_malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it
|
||||
} else {
|
||||
if(!my_context->stack_clone)
|
||||
my_context->stack_clone = box_malloc(1024*1024);
|
||||
mystack = my_context->stack_clone;
|
||||
my_context->stack_clone_used = 1;
|
||||
}
|
||||
// x86_64 raw clone is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls);
|
||||
long ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), u32(4), newemu, p(12), p(16), p(20));
|
||||
return (uint32_t)ret;
|
||||
}
|
||||
else
|
||||
return (uint32_t)syscall(__NR_clone, u32(4), p(8), p(12), p(16), p(20));
|
||||
break;
|
||||
case 123: // SYS_modify_ldt
|
||||
return my_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
|
||||
case 125: // mprotect
|
||||
return (uint32_t)my_mprotect(emu, p(4), u32(8), i32(12));
|
||||
case 174: // sys_rt_sigaction
|
||||
return (uint32_t)my_sigaction(emu, i32(4), (x86_sigaction_t*)p(8), (x86_sigaction_t*)p(12));
|
||||
return (uint32_t)my_syscall_sigaction(emu, i32(4), p(8), p(12), i32(16));
|
||||
case 192: // mmap2
|
||||
return (uint32_t)my_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
|
||||
case 243: // set_thread_area
|
||||
@@ -718,9 +810,12 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
return (uint32_t)my_memfd_create(emu, (void*)R_EBX, R_ECX);
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
if(!(warned&(1<<s))) {
|
||||
printf_log(LOG_INFO, "Warning: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
warned|=(1<<s);
|
||||
}
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+61
-23
@@ -130,32 +130,46 @@ EXPORT uint32_t my_modify_ldt(x86emu_t* emu, int op, thread_area_t* td, int size
|
||||
|
||||
#define POS_TLS 0x50
|
||||
|
||||
static int sizeDTS(box86context_t* context)
|
||||
{
|
||||
return ((context->elfsize+0xff)&~0xff)*8;
|
||||
}
|
||||
static int sizeTLSData(int s)
|
||||
{
|
||||
uint32_t mask = box86_nogtk?0xffff:0x1fff;
|
||||
return (s+mask)&~mask;
|
||||
}
|
||||
|
||||
static tlsdatasize_t* setupTLSData(box86context_t* context)
|
||||
{
|
||||
// Setup the GS segment:
|
||||
int dtsize = context->elfsize*8;
|
||||
void *ptr = (char*)malloc(context->tlssize+4+POS_TLS+dtsize);
|
||||
memcpy(ptr, context->tlsdata, context->tlssize);
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t));
|
||||
data->tlsdata = ptr;
|
||||
int dtssize = sizeDTS(context);
|
||||
int datasize = sizeTLSData(context->tlssize);
|
||||
void *ptr_oversized = (char*)box_malloc(dtssize+POS_TLS+datasize);
|
||||
void *ptr = (void*)((uintptr_t)ptr_oversized + datasize);
|
||||
memcpy((void*)((uintptr_t)ptr-context->tlssize), context->tlsdata, context->tlssize);
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)box_calloc(1, sizeof(tlsdatasize_t));
|
||||
data->data = ptr;
|
||||
data->tlssize = context->tlssize;
|
||||
data->ptr = ptr_oversized;
|
||||
data->n_elfs = context->elfsize;
|
||||
pthread_setspecific(context->tlskey, data);
|
||||
// copy canary...
|
||||
memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
|
||||
uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, 4);
|
||||
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS;
|
||||
memset((void*)((uintptr_t)ptr), 0, POS_TLS+dtssize); // set to 0 remining bytes
|
||||
memcpy((void*)((uintptr_t)ptr+0x14), context->canary, 4); // put canary in place
|
||||
uintptr_t tlsptr = (uintptr_t)ptr;
|
||||
memcpy((void*)((uintptr_t)ptr+0x0), &tlsptr, 4);
|
||||
uintptr_t dtp = (uintptr_t)ptr+POS_TLS;
|
||||
memcpy((void*)(tlsptr+0x4), &dtp, 4);
|
||||
if(dtsize) {
|
||||
if(dtssize) {
|
||||
for (int i=0; i<context->elfsize; ++i) {
|
||||
// set pointer
|
||||
dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i]));
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8), &dtp, 4);
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8+4), &i, 4); // index
|
||||
dtp = (uintptr_t)ptr + GetTLSBase(context->elfs[i]);
|
||||
memcpy((void*)((uintptr_t)ptr+POS_TLS+i*8), &dtp, 4);
|
||||
memcpy((void*)((uintptr_t)ptr+POS_TLS+i*8+4), &i, 4); // index
|
||||
}
|
||||
}
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
|
||||
memcpy((void*)((uintptr_t)ptr+0x10), &context->vsyscall, 4); // address of vsyscall
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -171,13 +185,37 @@ void* resizeTLSData(box86context_t *context, void* oldptr)
|
||||
{
|
||||
pthread_mutex_lock(&context->mutex_tls);
|
||||
tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr;
|
||||
tlsdatasize_t *data = setupTLSData(context);
|
||||
// copy the relevent old part, in case something changed
|
||||
memcpy((void*)((uintptr_t)data->tlsdata+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize);
|
||||
// all done, update new size, free old pointer and exit
|
||||
pthread_mutex_unlock(&context->mutex_tls);
|
||||
free_tlsdatasize(oldptr);
|
||||
return data;
|
||||
if(sizeTLSData(oldata->tlssize)!=sizeTLSData(context->tlssize) || (oldata->n_elfs/0xff)!=(context->elfsize/0xff)) {
|
||||
printf_log(LOG_INFO, "Warning, resizing of TLS occured! size: %d->%d / n_elfs: %d->%d\n", sizeTLSData(oldata->tlssize), sizeTLSData(context->tlssize), 1+(oldata->n_elfs/0xff), 1+(context->elfsize/0xff));
|
||||
tlsdatasize_t *data = setupTLSData(context);
|
||||
// copy the relevent old part, in case something changed
|
||||
memcpy((void*)((uintptr_t)data->data-oldata->tlssize), (void*)((uintptr_t)oldata->data-oldata->tlssize), oldata->tlssize);
|
||||
// all done, update new size, free old pointer and exit
|
||||
pthread_mutex_unlock(&context->mutex_tls);
|
||||
free_tlsdatasize(oldptr);
|
||||
return data;
|
||||
} else {
|
||||
// keep the same tlsdata, but fill in the blanks
|
||||
// adjust tlsdata
|
||||
void *ptr = oldata->data;
|
||||
if(context->tlssize!=oldata->tlssize) {
|
||||
memcpy((void*)((uintptr_t)ptr-context->tlssize), context->tlsdata, context->tlssize-oldata->tlssize);
|
||||
oldata->tlssize = context->tlssize;
|
||||
}
|
||||
// adjust DTS
|
||||
if(oldata->n_elfs!=context->elfsize) {
|
||||
uintptr_t dtp = (uintptr_t)ptr+POS_TLS;
|
||||
for (int i=oldata->n_elfs; i<context->elfsize; ++i) {
|
||||
// set pointer
|
||||
dtp = (uintptr_t)ptr + GetTLSBase(context->elfs[i]);
|
||||
*(uint64_t*)((uintptr_t)ptr+POS_TLS+i*8) = dtp;
|
||||
*(uint64_t*)((uintptr_t)ptr+POS_TLS+i*8+4) = i; // index
|
||||
}
|
||||
oldata->n_elfs = context->elfsize;
|
||||
}
|
||||
pthread_mutex_unlock(&context->mutex_tls);
|
||||
return oldata;
|
||||
}
|
||||
}
|
||||
|
||||
static void* GetSeg33Base()
|
||||
@@ -189,7 +227,7 @@ static void* GetSeg33Base()
|
||||
if(ptr->tlssize != my_context->tlssize) {
|
||||
ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr);
|
||||
}
|
||||
return ptr->tlsdata+ptr->tlssize;
|
||||
return ptr->data;
|
||||
}
|
||||
|
||||
void* GetSegmentBase(uint32_t desc)
|
||||
|
||||
Loaded 100 of 481 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user