mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 10:10:25 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e42001b2bc | ||
|
|
9818f5b6a3 | ||
|
|
46e40fbb65 | ||
|
|
c141dbbd82 | ||
|
|
9d5d08fa6c | ||
|
|
7b9aa5b91a | ||
|
|
8c75f7659f | ||
|
|
d8c40c1662 | ||
|
|
7c0180c3b9 | ||
|
|
211fee2e4e | ||
|
|
9b7b91651d | ||
|
|
6ecfe5e141 | ||
|
|
e11291538c | ||
|
|
5b90d59877 | ||
|
|
85df885b90 | ||
|
|
4dd5b67bbf | ||
|
|
88575ebc5d | ||
|
|
d8a19e9832 | ||
|
|
99a938ef37 | ||
|
|
b07ea3460e | ||
|
|
f557a86ecc | ||
|
|
a5f8dd0788 | ||
|
|
effbd82d00 | ||
|
|
9d72c9db1b | ||
|
|
486df332dd | ||
|
|
8806c8ba8b | ||
|
|
0df1e38ded | ||
|
|
7344689ba6 | ||
|
|
0ddbb80ee3 | ||
|
|
48667b7dda | ||
|
|
5708bc6b49 | ||
|
|
9481df50b1 | ||
|
|
840c454c1c | ||
|
|
77143dc8cf | ||
|
|
e3e77a8234 | ||
|
|
c3e84e6daa | ||
|
|
c3f71c43e9 | ||
|
|
df2ad6b1ca | ||
|
|
1d462b7558 | ||
|
|
0a8c3ddd71 | ||
|
|
6ab86657ff | ||
|
|
aed66d81b3 | ||
|
|
e355280232 | ||
|
|
92fff0c903 | ||
|
|
06319911d4 | ||
|
|
98959e902b | ||
|
|
1e996410f8 | ||
|
|
548a8ac87b | ||
|
|
44494df9d3 | ||
|
|
60c698d381 | ||
|
|
df3e1ace61 | ||
|
|
6def5118bb | ||
|
|
7d3224e37f | ||
|
|
28a1581bb6 | ||
|
|
66b8e697ea | ||
|
|
c15f1c917a | ||
|
|
5b72444a6d | ||
|
|
94a37bb60a | ||
|
|
935113a53d | ||
|
|
d39ed15517 | ||
|
|
1dce5ef39f | ||
|
|
2c69b57617 | ||
|
|
06961d3db5 | ||
|
|
bdf2922f5d | ||
|
|
f52d13f86a | ||
|
|
1b7b361b30 | ||
|
|
151c40441f | ||
|
|
e26363dc0f | ||
|
|
5dbc8bf383 | ||
|
|
27e6cf0e31 | ||
|
|
24f241a1cd | ||
|
|
a8febc8638 | ||
|
|
c04dfb82bb | ||
|
|
08d189683d | ||
|
|
b67975a820 | ||
|
|
fa175e7d24 | ||
|
|
c2221e5304 | ||
|
|
104b5ec6d6 | ||
|
|
59b4780afa | ||
|
|
899405456b | ||
|
|
40a81173f3 | ||
|
|
19a6608619 | ||
|
|
558a52909d | ||
|
|
76eb623de6 | ||
|
|
9e45c05383 | ||
|
|
c0a1529468 | ||
|
|
f4a7a88167 | ||
|
|
44ecb62ce7 | ||
|
|
37a976831d | ||
|
|
dd1aeb7265 | ||
|
|
777c62c056 | ||
|
|
717cddcc3d | ||
|
|
d6f7f620fc | ||
|
|
1bd928a766 | ||
|
|
e493b0775d | ||
|
|
a966fa34ae | ||
|
|
8cd27fca4d | ||
|
|
3676ca15c8 | ||
|
|
616f7d3def | ||
|
|
ec4c6ec7a1 | ||
|
|
941fa6d520 | ||
|
|
ce5e561cf3 | ||
|
|
8e5a00db76 | ||
|
|
faaeffbd38 | ||
|
|
a070066b71 | ||
|
|
4e92269ae1 | ||
|
|
994971b08f | ||
|
|
019c0fabe1 | ||
|
|
8e5346be21 | ||
|
|
5f9d1f62cf | ||
|
|
d7bdf862bf | ||
|
|
6470442e08 | ||
|
|
6157f53aae | ||
|
|
3f2d4a5274 | ||
|
|
ae83035380 | ||
|
|
4566ff6d24 | ||
|
|
cbceca3b35 | ||
|
|
436de1c4f5 | ||
|
|
737d4a5506 | ||
|
|
e5b16e9ef1 | ||
|
|
ea64f8453f | ||
|
|
507eb1c786 | ||
|
|
04f8ab3871 | ||
|
|
6b390caef5 | ||
|
|
8cee527ad0 | ||
|
|
bdf7d47742 | ||
|
|
6ad9435b4d | ||
|
|
e853892282 | ||
|
|
4969b8c252 | ||
|
|
239ef8951d | ||
|
|
494510e2a8 | ||
|
|
6dd899df22 | ||
|
|
7c4b97961f | ||
|
|
5c0a82913f | ||
|
|
d7e64d3f11 | ||
|
|
ea8d725546 | ||
|
|
cfffbcc5be | ||
|
|
ba80b40e9e | ||
|
|
b0fe7ecf8c | ||
|
|
84a6cfd558 | ||
|
|
efbf692cca | ||
|
|
f81057416b | ||
|
|
168675d380 | ||
|
|
6327477695 | ||
|
|
4c7ac85ae8 | ||
|
|
afe6fbe3b3 | ||
|
|
39568bff2f | ||
|
|
d3b44f1c84 | ||
|
|
8e74746573 | ||
|
|
bb54f234bd | ||
|
|
572a84c19b | ||
|
|
8fe46092c0 | ||
|
|
02bad8bcd1 | ||
|
|
54be0c0dec | ||
|
|
20df2789b5 | ||
|
|
a8f902885d | ||
|
|
c17e37b6e0 | ||
|
|
df25986597 | ||
|
|
dc06ca51a6 | ||
|
|
d76ea27c54 | ||
|
|
90b606584d | ||
|
|
19a24c2171 | ||
|
|
f7d75ca641 | ||
|
|
5baa083386 | ||
|
|
6f7cb088b0 | ||
|
|
8901d1c37d | ||
|
|
ec9dedd75c | ||
|
|
3edf7ee978 | ||
|
|
9e35b66510 | ||
|
|
713458ac81 | ||
|
|
90e2f04c34 | ||
|
|
9896b02bd6 | ||
|
|
d39dd45ae4 | ||
|
|
d50ae52176 | ||
|
|
784be47702 | ||
|
|
4f1fa811d0 | ||
|
|
201cd065a9 | ||
|
|
d832ec8ab2 | ||
|
|
0c6c01d86a | ||
|
|
13612d4024 | ||
|
|
9daf8d6493 | ||
|
|
e071406829 | ||
|
|
ff85b03e3f | ||
|
|
590429d104 | ||
|
|
eb0b5bd3f8 | ||
|
|
b15a902f6d | ||
|
|
4468d63145 | ||
|
|
aba5c428e9 | ||
|
|
62966c2f64 | ||
|
|
dfd2a4ef0e | ||
|
|
7fcc6e010c | ||
|
|
5d2ae4aa1e | ||
|
|
4318172edd | ||
|
|
9201559b1d | ||
|
|
40f90dd8f3 | ||
|
|
308cc81a27 | ||
|
|
7e8f8cf415 | ||
|
|
62634c6e1e | ||
|
|
70e4bd4174 | ||
|
|
7e0e618222 | ||
|
|
cf6f013909 | ||
|
|
2ed8557ea6 | ||
|
|
da3373ae42 | ||
|
|
cd0173dae4 | ||
|
|
02e7400ef0 | ||
|
|
6d6f29b6e1 | ||
|
|
0260b3177e | ||
|
|
b82d9d15d4 | ||
|
|
3bc0495eb2 | ||
|
|
50c0b60c10 | ||
|
|
c2680fd0a7 | ||
|
|
85c74c6bf8 | ||
|
|
93f665eb9c | ||
|
|
113c879d7a | ||
|
|
f13ee05c6a | ||
|
|
90fd2ff6a3 | ||
|
|
3a40b9f3a3 | ||
|
|
d8805b6af7 | ||
|
|
675336dee5 | ||
|
|
3cd4ed8e63 | ||
|
|
9c7208b1fa | ||
|
|
48af038643 | ||
|
|
ca8ad5e554 | ||
|
|
ab146f5d23 | ||
|
|
13fdd31c67 | ||
|
|
28f69afe96 | ||
|
|
2827e9e253 | ||
|
|
46ba6fc561 | ||
|
|
b3997769c0 | ||
|
|
410f58b7c7 | ||
|
|
fbecdad199 | ||
|
|
9e6e3160ff | ||
|
|
ca8abae240 | ||
|
|
6f0d095364 | ||
|
|
cc661c7549 | ||
|
|
6982846f50 | ||
|
|
eb6ec17504 | ||
|
|
8c68e1108b | ||
|
|
9077fd7b51 | ||
|
|
f8b88418ed | ||
|
|
9c12016859 | ||
|
|
e6943c8a9d | ||
|
|
c6483b5cf8 | ||
|
|
60925658bb | ||
|
|
5ef9ea35d6 | ||
|
|
901bb48877 | ||
|
|
9fc37e6418 | ||
|
|
b34cce3f75 | ||
|
|
787646b3cc | ||
|
|
f0d5e9d01e | ||
|
|
be05309e51 | ||
|
|
52811e2ec2 | ||
|
|
107738f0f2 | ||
|
|
936fa20928 | ||
|
|
362a3fde10 | ||
|
|
5c13f8f10a | ||
|
|
20cf990bf7 | ||
|
|
00744bc0e5 | ||
|
|
cb2a623faa | ||
|
|
7e80e7ba86 | ||
|
|
c50c985c85 | ||
|
|
c3ee794d40 | ||
|
|
c8502fa20c | ||
|
|
a31c037165 | ||
|
|
c71035530a | ||
|
|
acaf23fcb8 | ||
|
|
15860f3245 | ||
|
|
8a1e4cdf30 | ||
|
|
e574dca373 | ||
|
|
32fc932813 | ||
|
|
8a471d4d11 | ||
|
|
81ca3cd06e | ||
|
|
f8d65a831e | ||
|
|
a1ac21af75 | ||
|
|
d3d5e4e7bc | ||
|
|
c11cd7f4af | ||
|
|
840f2dced7 | ||
|
|
f81d6cf262 | ||
|
|
fe378c938a | ||
|
|
d9a4fed2f8 | ||
|
|
2a4fe80399 | ||
|
|
8999713301 | ||
|
|
0900cc2f59 | ||
|
|
87bf751b11 | ||
|
|
12c40a5b80 | ||
|
|
e9a2f9ff62 | ||
|
|
1fc382f74f | ||
|
|
65fc95b614 | ||
|
|
4354e8c861 | ||
|
|
f1014bbbb6 | ||
|
|
72f232e776 | ||
|
|
b7ebc35193 | ||
|
|
671328aaf6 | ||
|
|
c7bd174d7c | ||
|
|
54f8d05105 | ||
|
|
892f102e4a | ||
|
|
f9b54dab31 | ||
|
|
b3daf55ec2 | ||
|
|
391cef8549 | ||
|
|
59b51cccfc | ||
|
|
a83091bc3b | ||
|
|
7372540fce | ||
|
|
ceaa4bcac6 | ||
|
|
862f31ef1c | ||
|
|
6643bf8695 | ||
|
|
3c0297fbdf | ||
|
|
479cdb4218 | ||
|
|
6389ccee8d | ||
|
|
d478f98a4c | ||
|
|
dba0058763 | ||
|
|
10b4782efb | ||
|
|
f82d8d647a | ||
|
|
1698c822a5 | ||
|
|
c9177ec259 | ||
|
|
0481589615 | ||
|
|
6ef2b22a3c | ||
|
|
da19b2008a | ||
|
|
5493ab345a | ||
|
|
2589f7db14 | ||
|
|
2e283b9d6d | ||
|
|
3cf27bb46e | ||
|
|
f67d0709b7 | ||
|
|
2e66d603d3 | ||
|
|
d51560211c | ||
|
|
1b620b31d5 | ||
|
|
b82b730bf9 | ||
|
|
9191c993b1 | ||
|
|
1a2245043d | ||
|
|
2df7b9f302 | ||
|
|
202cbc62db | ||
|
|
9209e57bd9 | ||
|
|
1e1ad7694b | ||
|
|
b920d37f4e | ||
|
|
3cb2bc31a8 | ||
|
|
be24eec9d0 | ||
|
|
60fed04cb7 | ||
|
|
6c956013a6 | ||
|
|
59289ae8f9 | ||
|
|
8310e9762b | ||
|
|
99483d2913 | ||
|
|
b77303931e | ||
|
|
5863dc6c7c | ||
|
|
2a3923a173 | ||
|
|
3e882f3fd9 | ||
|
|
0499c38466 | ||
|
|
3e18d5ea57 | ||
|
|
ae75a502f0 | ||
|
|
6ac200f597 | ||
|
|
d7f635586d | ||
|
|
e27156be58 | ||
|
|
cafe638d5a | ||
|
|
4d996f6273 | ||
|
|
86dfd2840f | ||
|
|
dd9c3a53bf | ||
|
|
57959a1e93 | ||
|
|
6cfd7a988b | ||
|
|
ef95ff3342 | ||
|
|
773c17496e | ||
|
|
6118dafd94 | ||
|
|
8befcbfacf | ||
|
|
b9ea4983f9 | ||
|
|
d8765f86dd | ||
|
|
3d9744362f | ||
|
|
b2162ba263 | ||
|
|
aba40a9360 | ||
|
|
1a9e076685 | ||
|
|
2d9a3c643a | ||
|
|
85d2a06f6f | ||
|
|
8a5719afe1 | ||
|
|
2ec01c9b60 | ||
|
|
5fa02ef1e3 | ||
|
|
cfe8f8f6e1 | ||
|
|
9d63f0ce9a | ||
|
|
afd8d305f3 | ||
|
|
83738a606d | ||
|
|
072311b256 | ||
|
|
c904a9af1c | ||
|
|
7c042a566a | ||
|
|
57b762eb29 | ||
|
|
a4eb0cbd74 | ||
|
|
e558912a36 | ||
|
|
00ea757e77 | ||
|
|
2f04934471 | ||
|
|
1e6f492852 | ||
|
|
582c7c762a | ||
|
|
3ad64aa6a4 | ||
|
|
1c680d3aaa | ||
|
|
eed9ea35f9 | ||
|
|
a724725fdf | ||
|
|
84a5929645 | ||
|
|
cb85a8f5cb | ||
|
|
23dd80ffd8 | ||
|
|
16393c499b | ||
|
|
684160f178 | ||
|
|
e3f193b382 | ||
|
|
37d9c4b480 | ||
|
|
b6633aa306 | ||
|
|
c8651fb1f3 | ||
|
|
83a5b0d223 | ||
|
|
d95ef48d22 | ||
|
|
b59ce0b95b | ||
|
|
c00cd1d627 | ||
|
|
ab65641eae | ||
|
|
6c0781c157 | ||
|
|
bf6c6498aa | ||
|
|
4b6cec8452 | ||
|
|
b77da2635b | ||
|
|
033ddf8cc8 | ||
|
|
5b3c67c692 | ||
|
|
86aa8b8b2e | ||
|
|
0329bbc55e | ||
|
|
c9549e8ab6 | ||
|
|
5903f02086 | ||
|
|
28dcd34624 | ||
|
|
13b7398b3a | ||
|
|
50cf9c0e67 | ||
|
|
71ad38d742 | ||
|
|
c086a1ff24 | ||
|
|
75958f1f31 | ||
|
|
be34e0221d | ||
|
|
0913c94e46 | ||
|
|
910a0ef8e1 | ||
|
|
7b0e8b47a2 | ||
|
|
14e799ebe5 | ||
|
|
5e52c735a6 | ||
|
|
9eb5883f77 | ||
|
|
7a783b867b | ||
|
|
83ec0bd751 | ||
|
|
aacff4a9b6 | ||
|
|
7ab8ad8b10 | ||
|
|
cf7ac30215 | ||
|
|
547944ac88 | ||
|
|
99d7b46e48 | ||
|
|
eca872c04d | ||
|
|
8947b735f9 | ||
|
|
e245dee90b | ||
|
|
edba2a2e96 | ||
|
|
81e8ce4952 | ||
|
|
afd5d3a1e3 | ||
|
|
d1e8bcd7a5 | ||
|
|
79c71bf5c1 | ||
|
|
2c7daa388b | ||
|
|
cc351402a1 | ||
|
|
90a7602e5a | ||
|
|
1e0b8e443b | ||
|
|
96025a1977 | ||
|
|
6e1bcc03a6 | ||
|
|
728ec2e769 | ||
|
|
25a064f3a8 | ||
|
|
8a25b91ad2 | ||
|
|
cacd7dd2eb | ||
|
|
acf6825603 | ||
|
|
1b8c48ee1d | ||
|
|
6a6b75b7b4 | ||
|
|
491cbda0d3 | ||
|
|
aadd5e8786 | ||
|
|
e155d43c4b | ||
|
|
683f5d64b9 | ||
|
|
d26469c6a4 | ||
|
|
57d497c801 | ||
|
|
eac105fe9e | ||
|
|
61c2a3ed7a | ||
|
|
46031c008e | ||
|
|
d2aadd66bf | ||
|
|
646770ff68 | ||
|
|
90ad165359 | ||
|
|
30eae8f513 | ||
|
|
2d37575f3d | ||
|
|
eb1e607b93 | ||
|
|
9d16aec99a | ||
|
|
a95099696f | ||
|
|
be4791f826 | ||
|
|
41d5fa16a7 | ||
|
|
d3635126b7 | ||
|
|
7cba83231a | ||
|
|
7f4145d67f | ||
|
|
103c804c8e | ||
|
|
c7db4470e4 | ||
|
|
2e55fc8c32 | ||
|
|
5d921acd7d | ||
|
|
aa051b662e | ||
|
|
5fabd602ae | ||
|
|
0393e15843 | ||
|
|
539fb8e214 | ||
|
|
7b1fa28b85 | ||
|
|
30475f0eda | ||
|
|
19771b307c | ||
|
|
7a992837a1 | ||
|
|
33d8fa7b23 | ||
|
|
62d55296c0 | ||
|
|
cd0aad731a | ||
|
|
8e7afcc5fb | ||
|
|
a62618ee47 | ||
|
|
4e9b7f27a9 | ||
|
|
7d7ea4405c | ||
|
|
45c4117a40 | ||
|
|
4bd00b0f91 | ||
|
|
9e7225be36 | ||
|
|
154acbef72 | ||
|
|
502611702e | ||
|
|
009b9f7f3d | ||
|
|
77161c8e4d | ||
|
|
b4cd6f27ba | ||
|
|
2bb42ae9a9 | ||
|
|
54ce282b8c | ||
|
|
47057f076a | ||
|
|
7f775b7662 | ||
|
|
48317e0788 | ||
|
|
6c77c8f1aa | ||
|
|
ca759d2c8f | ||
|
|
53a59f593e | ||
|
|
d621670735 | ||
|
|
6653cce464 | ||
|
|
acfbed72de | ||
|
|
c4e322a23a | ||
|
|
6b9d617fa6 | ||
|
|
607ac40ab3 | ||
|
|
69c7ca8bdc | ||
|
|
692eb90dcd | ||
|
|
eee1c62325 | ||
|
|
442c3fdb9b | ||
|
|
e2077c46ce | ||
|
|
e8972efca1 | ||
|
|
f86c856e3b | ||
|
|
6bb674420a | ||
|
|
ee0fdc4332 | ||
|
|
4006992f8d | ||
|
|
8d04940c91 | ||
|
|
4f1d3a75c2 | ||
|
|
24c8af0363 | ||
|
|
4474af2a9a | ||
|
|
a3765ec0f8 | ||
|
|
b04712898c | ||
|
|
adaafc2a6d | ||
|
|
3308cc60e9 | ||
|
|
e4b235378b | ||
|
|
4f5f6b25e8 | ||
|
|
4b40179bc3 | ||
|
|
0f7b23148f | ||
|
|
a46923e494 | ||
|
|
1e7b4b8450 | ||
|
|
0edf24ae97 | ||
|
|
82f60fee35 | ||
|
|
1333e37b71 | ||
|
|
7f3e0b8fe0 | ||
|
|
937863f4aa | ||
|
|
ff3a639c92 | ||
|
|
3eae7156dc | ||
|
|
e12589ea8b | ||
|
|
6b5ee5ecb5 | ||
|
|
f3a9224547 | ||
|
|
8ef326fdc5 | ||
|
|
fb0e8ee9c6 | ||
|
|
6a8cc8ace3 | ||
|
|
f5fadea30e | ||
|
|
bedfb82066 | ||
|
|
8a403d9126 | ||
|
|
aca4e6585c | ||
|
|
0928f50bc6 | ||
|
|
da098cc1f7 | ||
|
|
8da631a14d | ||
|
|
dafa5014a4 | ||
|
|
879c2f365e | ||
|
|
50032affcf | ||
|
|
784cc3ba9c | ||
|
|
1d5a88a319 | ||
|
|
392575ba04 | ||
|
|
83c808c42d | ||
|
|
9a61392cf9 | ||
|
|
b2c2f7bbd2 | ||
|
|
da6ad1a43d | ||
|
|
f9e4253cb7 | ||
|
|
1675ce83b6 | ||
|
|
9b585ef706 | ||
|
|
67c9378fb8 | ||
|
|
7ab299b246 | ||
|
|
0733a87279 | ||
|
|
28dc8e6751 | ||
|
|
51cbb7e1fb | ||
|
|
3a82317dd5 | ||
|
|
1f2ef09d87 | ||
|
|
5bf0f0215d | ||
|
|
8f968e4c9c | ||
|
|
a8ce60ed4a | ||
|
|
27d8911dee | ||
|
|
4bf909393c | ||
|
|
8fc0e1d384 | ||
|
|
60ae205bd4 | ||
|
|
65045c4897 | ||
|
|
e46133c850 | ||
|
|
37ef57f78f | ||
|
|
3c50d99aba | ||
|
|
508efcf51c | ||
|
|
36d11a4443 | ||
|
|
8590b0b4f3 | ||
|
|
7817d629f1 | ||
|
|
7607a87617 | ||
|
|
b2d37d4ddb | ||
|
|
0003c72fc7 | ||
|
|
915f7cbd54 | ||
|
|
0b3097cd0b | ||
|
|
c7e0ba82b4 | ||
|
|
6168fa4275 | ||
|
|
b61a788ce7 | ||
|
|
903ecd207d | ||
|
|
d62e9652fc | ||
|
|
41e3b2b1a1 | ||
|
|
3349757d0f | ||
|
|
066d7458ca | ||
|
|
88a59b4460 | ||
|
|
aaab83356d | ||
|
|
7c1637328a | ||
|
|
0224346ed8 | ||
|
|
35366b25a6 | ||
|
|
b4c951b66b | ||
|
|
b1c09acb0c | ||
|
|
a6b231ce56 | ||
|
|
0862e4995c | ||
|
|
94832fd7d7 | ||
|
|
7cd82d16ce | ||
|
|
dabbca767f | ||
|
|
ca9bc13619 | ||
|
|
3f573711aa | ||
|
|
55306b1d3d | ||
|
|
ab2d68ef45 | ||
|
|
b7a2d59a61 | ||
|
|
25c8453353 | ||
|
|
aa39a923ed | ||
|
|
57b7729ea7 | ||
|
|
0e750a7d0d | ||
|
|
5cd583f944 | ||
|
|
c7a93758cb | ||
|
|
a450806dd2 | ||
|
|
cf6048419b | ||
|
|
cd6487ab94 | ||
|
|
157a9cc651 | ||
|
|
509157a8b0 | ||
|
|
aa8b8184b3 | ||
|
|
1f65d3add7 | ||
|
|
3b97724717 | ||
|
|
144db5f07f | ||
|
|
dc0ab611c4 | ||
|
|
5ddc93cf0d | ||
|
|
ad5328e6c7 | ||
|
|
7e514ce4bd | ||
|
|
42dc36ad5a | ||
|
|
7689d0d568 | ||
|
|
f37265235e | ||
|
|
f83b192d70 | ||
|
|
910420af07 | ||
|
|
8f719b7fed | ||
|
|
0272446f2b | ||
|
|
735d7ab1b4 | ||
|
|
3c9b556ca8 | ||
|
|
4e2ccf13cb | ||
|
|
8d0a7d322e | ||
|
|
3880b7811b | ||
|
|
2604bb078c | ||
|
|
8670d622da | ||
|
|
1ca1c37a9c | ||
|
|
7e7db57369 | ||
|
|
deb6fe8d7a | ||
|
|
1e20ed7099 | ||
|
|
40d94c84e0 | ||
|
|
bfc9af16a1 | ||
|
|
770cba7e2b | ||
|
|
8aa98d3f53 | ||
|
|
4219af78f4 | ||
|
|
0352f2e6f0 | ||
|
|
9ea02922ee | ||
|
|
816cbc74f4 | ||
|
|
e8cd8ca8c0 | ||
|
|
179015a050 | ||
|
|
d34428d249 | ||
|
|
974df6190e | ||
|
|
294a18e680 | ||
|
|
47edda2c1b | ||
|
|
ebe758f741 | ||
|
|
2f42eb02d4 | ||
|
|
08e4823917 | ||
|
|
d67615c976 | ||
|
|
2ca9b70c84 | ||
|
|
bd8e532353 | ||
|
|
4f69f090e6 | ||
|
|
0077fbe916 | ||
|
|
b263d1a049 | ||
|
|
bb3c647f49 | ||
|
|
c9b7180bb3 | ||
|
|
aca28bcb79 | ||
|
|
410447b340 | ||
|
|
6b0a1d286a | ||
|
|
e78cd0d623 | ||
|
|
6eb72b71b1 | ||
|
|
0cef7f27ea | ||
|
|
9698844cc3 | ||
|
|
9ca5e13d7f | ||
|
|
e1825e0ff2 | ||
|
|
a55fc58e24 | ||
|
|
8e2889c2b5 | ||
|
|
95d21e61e4 | ||
|
|
ed09b87953 | ||
|
|
8c3fbe26ad | ||
|
|
af2699ec21 | ||
|
|
17364dc445 | ||
|
|
59dd97cb72 | ||
|
|
a0a98419f0 | ||
|
|
1b47fd952c | ||
|
|
bf9e5b8e6e | ||
|
|
7e282c9027 | ||
|
|
e0dc494e71 | ||
|
|
4110956dda | ||
|
|
d0acd59adc | ||
|
|
8ad6ffc93d | ||
|
|
56d0926bdf | ||
|
|
8d99e12723 | ||
|
|
8ee8301bd0 | ||
|
|
1d584fead4 | ||
|
|
cc56ebbb35 | ||
|
|
56b87146e7 | ||
|
|
a5b9cdf90f | ||
|
|
6cd3d0d977 | ||
|
|
361de53d86 | ||
|
|
4021f6d8c3 | ||
|
|
2949e5cd8d | ||
|
|
c8f3921c3d | ||
|
|
5254834d43 | ||
|
|
2b0ceaf417 | ||
|
|
a688abddc1 | ||
|
|
648678ba7d | ||
|
|
f4c8c29510 | ||
|
|
87be9fd1ad | ||
|
|
7cbb2bf435 | ||
|
|
4f1cefec30 | ||
|
|
5e19c8f142 | ||
|
|
a6737720f4 | ||
|
|
e028a67f4f | ||
|
|
c5e8aaff4a | ||
|
|
2017ef192f | ||
|
|
04d3915171 | ||
|
|
2bdf3088a6 | ||
|
|
9debf2678e | ||
|
|
e03c10142d | ||
|
|
6213e7c390 | ||
|
|
9264aa5e46 | ||
|
|
4c5e1d916a | ||
|
|
d1ac3f3c24 | ||
|
|
ec9447ad5f | ||
|
|
26b01d56f5 | ||
|
|
eb687748c5 | ||
|
|
4b81cfcb47 | ||
|
|
a7074f03f7 | ||
|
|
0b67bba121 | ||
|
|
a791677534 | ||
|
|
be17a6cbf0 | ||
|
|
d2547672f3 | ||
|
|
52d1a09b8a | ||
|
|
1d98aa54d5 | ||
|
|
f56181bdab | ||
|
|
bc40c86f10 | ||
|
|
d61f3e79e2 | ||
|
|
1d58879ae5 | ||
|
|
f115fe331b | ||
|
|
92ac8fed99 | ||
|
|
877d31fefb | ||
|
|
0d77c7f9a7 | ||
|
|
0037f9eccb | ||
|
|
ba51e24fd9 | ||
|
|
7b9e6a57af | ||
|
|
7e9cab2b7d | ||
|
|
dd74ade44d | ||
|
|
9de2aa55cd | ||
|
|
6ac2376aac | ||
|
|
4fadb26cf6 | ||
|
|
61f14ffbbc | ||
|
|
377a55f60f | ||
|
|
e32cb72c62 | ||
|
|
dbd408c6d1 | ||
|
|
6e7bacb3c3 | ||
|
|
91f7078953 | ||
|
|
7787cb59f0 | ||
|
|
dac27435b8 | ||
|
|
50cd5701ce | ||
|
|
adf4fb5ae0 | ||
|
|
1f4cc1cf88 | ||
|
|
92dd53177f | ||
|
|
fe9e5bf21d | ||
|
|
1ca4f6acf5 | ||
|
|
392463b9f0 | ||
|
|
4df1f85492 | ||
|
|
ad79f878eb | ||
|
|
04a7437158 | ||
|
|
1fbeb6bd34 | ||
|
|
54cce67156 | ||
|
|
7db5b33284 | ||
|
|
6607ddb15d | ||
|
|
f18c1b3998 | ||
|
|
bd75b34f5d | ||
|
|
057de8f9be | ||
|
|
404bfdc782 | ||
|
|
b74a1b5a32 | ||
|
|
9f38e81735 | ||
|
|
47ecde75ec | ||
|
|
07948ff6a7 | ||
|
|
381bccfd6a | ||
|
|
3221038bc6 | ||
|
|
0359a65a00 | ||
|
|
eb1b77ad01 | ||
|
|
45c7bab8e4 | ||
|
|
0a558652e3 | ||
|
|
30126c9288 | ||
|
|
39562edc45 | ||
|
|
c19e513efb | ||
|
|
cf22cbcab5 | ||
|
|
e444b277f8 | ||
|
|
49dfbee211 | ||
|
|
3fc3875e82 | ||
|
|
a9099ce2c1 | ||
|
|
ad9fc59d19 | ||
|
|
0e14d42dcf | ||
|
|
987ff861fd | ||
|
|
f3f36e323b | ||
|
|
f7326b0533 | ||
|
|
dbde650339 | ||
|
|
a338e3fae8 | ||
|
|
df59bf8811 | ||
|
|
99e669bb63 | ||
|
|
66b4dcf37a | ||
|
|
1462d5c6bd | ||
|
|
60d2efc74b | ||
|
|
144b44e838 | ||
|
|
3245ff59d3 | ||
|
|
3a4d58f114 | ||
|
|
494f054ef4 | ||
|
|
0079a08cb8 | ||
|
|
d31ff6a83f | ||
|
|
58abb54da5 | ||
|
|
2fb4dccff0 | ||
|
|
45a4fc34d1 | ||
|
|
dc65627453 | ||
|
|
d24cbaf556 | ||
|
|
cbf71f678a | ||
|
|
c983418cb3 | ||
|
|
240c44b338 | ||
|
|
505ac0021d | ||
|
|
c020154a2f | ||
|
|
aac1663d75 | ||
|
|
5b9d963d31 | ||
|
|
31a6f5c4e3 | ||
|
|
98535e572d | ||
|
|
ffcfaba2fa | ||
|
|
464d868af5 | ||
|
|
34a6e81f72 | ||
|
|
57a9b520b0 | ||
|
|
6952970895 | ||
|
|
14e20e6435 | ||
|
|
93abd016b4 | ||
|
|
2ebde976db | ||
|
|
dbaee7c49c | ||
|
|
b6be4f8dde | ||
|
|
68a31c902a | ||
|
|
78e6fbcf07 | ||
|
|
0403b684c4 | ||
|
|
ccf05c6d83 | ||
|
|
a6a62007dc | ||
|
|
549c42ac19 | ||
|
|
6bfeb15655 | ||
|
|
69eb071fab | ||
|
|
277a62a897 | ||
|
|
96da85d2c1 | ||
|
|
b53b71a8ad | ||
|
|
009ffd609d | ||
|
|
50044f2f13 | ||
|
|
0a2f4eb5be | ||
|
|
0ee25621d6 | ||
|
|
e64c542c6a | ||
|
|
97ef3cccef | ||
|
|
766049afbb | ||
|
|
4fff4f679f | ||
|
|
2123f284de | ||
|
|
fb9b8fa625 | ||
|
|
d9e645b63f | ||
|
|
c2545c6762 | ||
|
|
c846d827cc | ||
|
|
f75179134d | ||
|
|
a30b22505c | ||
|
|
bbf4082b1f | ||
|
|
84a9da2f06 | ||
|
|
4f457e945a | ||
|
|
64f081009d | ||
|
|
486bbae323 | ||
|
|
b49a1904df | ||
|
|
1a70b54129 | ||
|
|
70332c4f2b | ||
|
|
8789141d0f | ||
|
|
29e7497adc | ||
|
|
8ecf28de9b | ||
|
|
66abc05259 | ||
|
|
5b04c49e74 | ||
|
|
f26e9758d5 | ||
|
|
531cb89943 | ||
|
|
24ead2f125 | ||
|
|
225e50a32a | ||
|
|
d546877e7d | ||
|
|
9657bd51d0 | ||
|
|
fd47fc3d12 | ||
|
|
c74d8bb602 | ||
|
|
ec7844072f | ||
|
|
128390d52e | ||
|
|
f7d23a4b9f | ||
|
|
2dec48f8af | ||
|
|
3f8ec8d46e | ||
|
|
a607d1178f | ||
|
|
1a3d412669 | ||
|
|
ae08d21bf1 | ||
|
|
5f69e58f37 | ||
|
|
84b0ee2284 | ||
|
|
4e9005be14 | ||
|
|
f280c64980 | ||
|
|
d0ae6a9a7d | ||
|
|
9aca360fe5 | ||
|
|
5d92a3a891 | ||
|
|
70787b0a6d | ||
|
|
206b8bc899 | ||
|
|
a0ea94b531 | ||
|
|
790a7a37d2 | ||
|
|
c0eace067a | ||
|
|
9d6835737b | ||
|
|
1b4625cedd | ||
|
|
fba75e3122 | ||
|
|
91bf99d2a5 | ||
|
|
6f29d2a5d8 | ||
|
|
008ef41261 | ||
|
|
c61d341844 | ||
|
|
49e5a48e42 | ||
|
|
9a97898ea4 | ||
|
|
cce1fa8928 | ||
|
|
cddea1e4c1 | ||
|
|
2cbf5cbf7b | ||
|
|
e360565266 | ||
|
|
dce7be2775 | ||
|
|
922e5beb3f | ||
|
|
6c6b6f7f13 | ||
|
|
798546302d | ||
|
|
65c6945fe3 | ||
|
|
e5820feedd | ||
|
|
df15bf5c59 | ||
|
|
2ccd9da8e8 | ||
|
|
18b5d6f1ed | ||
|
|
a78fe12663 | ||
|
|
87fde19623 | ||
|
|
93a4201c66 | ||
|
|
88369e0366 | ||
|
|
e50094e10a | ||
|
|
4e74819bac | ||
|
|
084b54723a | ||
|
|
60e830b64c | ||
|
|
0d52bb291c | ||
|
|
9e37c04fb2 | ||
|
|
7870940532 | ||
|
|
3adf31c85b | ||
|
|
9b2c6caf22 | ||
|
|
87b48ee3e5 | ||
|
|
9880a488ac | ||
|
|
f59675e9bf | ||
|
|
dd3ea0b5e6 | ||
|
|
4dbb1f6101 | ||
|
|
ced38e86c4 | ||
|
|
927b804684 | ||
|
|
27de834abc | ||
|
|
7de8f63b2b | ||
|
|
f042fe4713 | ||
|
|
27f3ba941f | ||
|
|
9413d5deb4 | ||
|
|
8a903f1e2c | ||
|
|
9246f4925b | ||
|
|
128fb82c1c | ||
|
|
3bf4a93a44 | ||
|
|
6460447ae9 | ||
|
|
344683927f | ||
|
|
828f088b6c | ||
|
|
d9f4730d0b | ||
|
|
aa5d320707 | ||
|
|
69c77c0a24 | ||
|
|
5ceedab213 | ||
|
|
1c4f3cbf19 | ||
|
|
90bf55e645 | ||
|
|
e066e920d0 | ||
|
|
fceaac48a6 | ||
|
|
4330b61217 | ||
|
|
97410042bd | ||
|
|
75592bec01 | ||
|
|
e96b1c8106 | ||
|
|
fdb6908474 | ||
|
|
5d63071849 | ||
|
|
8c98c7b675 | ||
|
|
5eb54321e8 | ||
|
|
9ce44af204 | ||
|
|
51e840a150 | ||
|
|
f6b4ec0fdf | ||
|
|
8439a3add9 | ||
|
|
9b3511cc88 | ||
|
|
48f80ebc93 | ||
|
|
e1108c5e17 | ||
|
|
1d6eee3262 | ||
|
|
14bcdee7e2 | ||
|
|
ec12de89c8 | ||
|
|
57e858ccc4 | ||
|
|
2c44452dc6 | ||
|
|
24f2720df4 | ||
|
|
d9c30c8942 | ||
|
|
6f3d70c69f | ||
|
|
99948b601b | ||
|
|
24a374500c | ||
|
|
b9cd6d3505 | ||
|
|
d9e907535e | ||
|
|
d1426e85b3 | ||
|
|
efdd052674 | ||
|
|
9964a0d9e5 | ||
|
|
d3e1cff733 | ||
|
|
b5096ad65e | ||
|
|
56d0e03991 | ||
|
|
c765943fdf | ||
|
|
91898d1512 | ||
|
|
c4d9262abf | ||
|
|
9b40854d27 | ||
|
|
2092da2907 | ||
|
|
9b9e489b61 | ||
|
|
9f9831ac56 | ||
|
|
afe5148211 | ||
|
|
5ab1606c47 | ||
|
|
b83ab97a8a | ||
|
|
6255932e48 | ||
|
|
9ad09a0166 | ||
|
|
728a656df4 | ||
|
|
4933a70261 | ||
|
|
02c24dffdc | ||
|
|
aa7ee8e65d | ||
|
|
64a6a28c30 | ||
|
|
f8bdb8bd16 | ||
|
|
2417faa39b | ||
|
|
5c2f62657f | ||
|
|
ae34c7e1cc | ||
|
|
07a3a0e1c8 | ||
|
|
c43f4ea080 | ||
|
|
149414f233 | ||
|
|
14695faa43 | ||
|
|
1159c0530b | ||
|
|
053ecec70b | ||
|
|
42601d8451 | ||
|
|
49392992da | ||
|
|
545c303058 | ||
|
|
086daef494 | ||
|
|
6898df1c86 | ||
|
|
307a019cb8 | ||
|
|
4ca16188c2 | ||
|
|
53687387eb | ||
|
|
eff1cea890 | ||
|
|
7867c3d906 | ||
|
|
5b5f421786 | ||
|
|
77cc2a6b8e | ||
|
|
e58ff89044 | ||
|
|
57eae464a3 | ||
|
|
8ec00e90ba | ||
|
|
a0f078718a | ||
|
|
b3a2031484 | ||
|
|
abf6e4856c | ||
|
|
518e6782d8 | ||
|
|
2a346ef0b9 | ||
|
|
83a2b2080b | ||
|
|
f21ecb32bb | ||
|
|
f810fa262d | ||
|
|
a847f46edc | ||
|
|
e710bbcec8 | ||
|
|
52f8fa1d5b | ||
|
|
5661de58a8 | ||
|
|
a1d5cb0e69 | ||
|
|
89ca436e91 | ||
|
|
d5356bee99 | ||
|
|
0384294cbf | ||
|
|
0da1f7be27 | ||
|
|
b24f2f14f0 | ||
|
|
40a1fab5e0 | ||
|
|
9464cbcf87 | ||
|
|
4334a1985b | ||
|
|
ba03124720 | ||
|
|
27b1e28f63 | ||
|
|
4431ef7736 | ||
|
|
4c86c8c264 | ||
|
|
275550a9c3 | ||
|
|
38cf61209e | ||
|
|
8670e9e5aa | ||
|
|
260eeacbeb | ||
|
|
13b2aed936 | ||
|
|
88431b9286 | ||
|
|
a12c6b7bef | ||
|
|
f81d99289f | ||
|
|
97739f8852 | ||
|
|
bdc0309296 | ||
|
|
e1a5edefc1 | ||
|
|
373c400cc3 | ||
|
|
d93e53498d | ||
|
|
e82d526414 | ||
|
|
0f11b55ba3 | ||
|
|
a665d2f62c | ||
|
|
0baa5a82ad | ||
|
|
0ea1775084 | ||
|
|
2fda0bd12b | ||
|
|
3b5c9e7a84 | ||
|
|
c0d8e7e245 | ||
|
|
d73ff21b27 | ||
|
|
4a90199f63 | ||
|
|
0dab0b5969 | ||
|
|
8e9bdf4115 | ||
|
|
613cbb8601 | ||
|
|
8cf02324ce | ||
|
|
9f75f28e7a | ||
|
|
feb4a39457 | ||
|
|
cca1fd6f19 | ||
|
|
4fb126635c | ||
|
|
9f282c2898 | ||
|
|
be3b95db6b | ||
|
|
c02b350b3d | ||
|
|
85f6d8308a | ||
|
|
06f2750eef | ||
|
|
5f078848f1 | ||
|
|
6ff68849f8 | ||
|
|
2ea036e02c | ||
|
|
f58ac3e9bf | ||
|
|
56e161d1ff | ||
|
|
85da2b7e23 | ||
|
|
da7136ab7e | ||
|
|
73264b2e80 | ||
|
|
567d48f813 | ||
|
|
0c3d350865 | ||
|
|
65211c94c3 | ||
|
|
b3b84f8357 | ||
|
|
a49d12b887 | ||
|
|
b5cb7e5649 | ||
|
|
c27c2b3487 | ||
|
|
56e9805562 | ||
|
|
f197e750b6 | ||
|
|
206bc9afb6 | ||
|
|
ffcfa5b2cb | ||
|
|
afae5d80c7 | ||
|
|
5e680e0f66 | ||
|
|
45015d6106 | ||
|
|
c3223245e5 | ||
|
|
fdf43e5874 | ||
|
|
dcc1a5db52 | ||
|
|
46ed52032d | ||
|
|
345a52b153 | ||
|
|
2accb00adc | ||
|
|
65c672fa1c | ||
|
|
f430dafb30 | ||
|
|
44524c057d | ||
|
|
a42322be99 | ||
|
|
6d8de238a0 | ||
|
|
c0d3135e54 | ||
|
|
b8b5203d08 | ||
|
|
f087afd796 | ||
|
|
91a230b38d | ||
|
|
72dc25abd1 | ||
|
|
b85b3d9bbd | ||
|
|
b6188abeeb | ||
|
|
1cd9fac9fb | ||
|
|
f1a2a7cfe9 | ||
|
|
f7fdd0a63a | ||
|
|
79ec2ee8f7 | ||
|
|
5c4f0de1d0 | ||
|
|
b9c1b1a5ea | ||
|
|
75036c43b5 | ||
|
|
3656cd66ea | ||
|
|
da88b87279 | ||
|
|
900f38779d | ||
|
|
d369ac8bf5 | ||
|
|
244eca4b38 | ||
|
|
67690748bd | ||
|
|
218ceb8a2a | ||
|
|
39ec81117d | ||
|
|
70f91204b1 | ||
|
|
f4739ae147 | ||
|
|
518125b836 | ||
|
|
7d4b353780 | ||
|
|
dbede8d6df | ||
|
|
5c48c72b56 | ||
|
|
8f52a3a3cc | ||
|
|
61a6af1de7 | ||
|
|
77f8bea615 | ||
|
|
bb49bc7844 | ||
|
|
c56ad76d18 | ||
|
|
b5dd04aa12 | ||
|
|
788724a1ca | ||
|
|
d577eb338c | ||
|
|
639ce20ecc | ||
|
|
27b6715910 | ||
|
|
b8ef8565e8 | ||
|
|
6d2f855af2 | ||
|
|
ae81bbb441 | ||
|
|
7db570af13 | ||
|
|
6a21831894 | ||
|
|
ee49851de4 | ||
|
|
e1ca614f1c | ||
|
|
01d1ea0b90 | ||
|
|
59ada379e2 | ||
|
|
52715c9220 | ||
|
|
4409fb9b21 | ||
|
|
e845d02242 | ||
|
|
35ed5b3c9b | ||
|
|
2567088192 | ||
|
|
26a083e700 | ||
|
|
8c4c87112c | ||
|
|
d052603335 | ||
|
|
01395fc579 | ||
|
|
bbe15eab7e | ||
|
|
015842ed83 | ||
|
|
d76f346648 | ||
|
|
34a5ab7498 | ||
|
|
72e537e951 | ||
|
|
670c067891 | ||
|
|
5ec4616614 | ||
|
|
bae9ef77e5 | ||
|
|
b2484afe96 | ||
|
|
e2e7479b8e | ||
|
|
cad38fe6da | ||
|
|
f5bfb537da | ||
|
|
e7f8ebaf77 | ||
|
|
29eab14f79 | ||
|
|
febcc8995d | ||
|
|
72cc87b012 | ||
|
|
5705e471b7 | ||
|
|
d8e30eb793 | ||
|
|
2c903dcb67 | ||
|
|
2d3aafefe1 | ||
|
|
5b1f16d7e9 | ||
|
|
4b74a1be58 | ||
|
|
2aeb77736f | ||
|
|
4a9d2d92d3 | ||
|
|
15c051e3ad | ||
|
|
6ee2fbf88c | ||
|
|
5665653b7d | ||
|
|
e7c0480bc3 | ||
|
|
241cec6e43 | ||
|
|
d8328b6f6e | ||
|
|
9e91f6f8d9 | ||
|
|
69b381fb66 | ||
|
|
ffa74500e6 | ||
|
|
356c135cbe | ||
|
|
9e05a02bbf | ||
|
|
b63dcabca4 | ||
|
|
cc9191382f | ||
|
|
0e86633cde | ||
|
|
9212e832e6 | ||
|
|
848763bb5c | ||
|
|
076357a2c4 | ||
|
|
daea5487ba | ||
|
|
dbd1b977fc | ||
|
|
5d14667536 | ||
|
|
ab289f8392 | ||
|
|
fa4584555d | ||
|
|
4b2a340bc7 | ||
|
|
7cb9a5064a | ||
|
|
4b6ec02517 | ||
|
|
9ea3b34e7e | ||
|
|
440c6d2d9a | ||
|
|
e579450af6 | ||
|
|
50e463917c | ||
|
|
a3ad297f92 | ||
|
|
6707640fa3 | ||
|
|
50bc5c8398 | ||
|
|
281065b5d4 | ||
|
|
f64d21e8c2 | ||
|
|
d5284a5704 | ||
|
|
9b2b603c8d | ||
|
|
6f85a204a9 | ||
|
|
b5f3d2565a | ||
|
|
2fdf52afb8 | ||
|
|
a651cf33f4 | ||
|
|
9e15d771c8 | ||
|
|
c48a2252d0 | ||
|
|
978cd2ec51 | ||
|
|
79f3afc2eb | ||
|
|
602142dc45 | ||
|
|
a4b6e99858 | ||
|
|
8730f2b073 | ||
|
|
20a6e66e11 | ||
|
|
94d397b8c5 | ||
|
|
adceb9eabb | ||
|
|
19a06a8755 | ||
|
|
87790a8d7a | ||
|
|
a6d32f4a62 | ||
|
|
a5f9bda131 | ||
|
|
327b2355c1 | ||
|
|
20308faef1 | ||
|
|
170ab57f55 | ||
|
|
874054f3bb | ||
|
|
a08f3c4c9e | ||
|
|
c0f98bb0ec | ||
|
|
42b067dc39 | ||
|
|
089e3816a8 | ||
|
|
ae15532477 | ||
|
|
b8ee806a80 | ||
|
|
9186f5eeeb | ||
|
|
216e70756c | ||
|
|
5a52922cd2 | ||
|
|
55edf30ecf | ||
|
|
d231539504 | ||
|
|
262ec3ed3c | ||
|
|
38a5e55745 | ||
|
|
8a4562c0a9 | ||
|
|
760c313f65 | ||
|
|
706ebc39eb | ||
|
|
46dfbf826d | ||
|
|
60c6858916 | ||
|
|
c5e085bc96 | ||
|
|
8dc669bc33 | ||
|
|
8aed75a338 | ||
|
|
e486e2ce8d | ||
|
|
a1705da6da | ||
|
|
0092a029c4 | ||
|
|
176ef90258 | ||
|
|
f82a6b7b41 | ||
|
|
c79c42b62d | ||
|
|
91dd7adbfa | ||
|
|
de82f07277 | ||
|
|
0c8e0b6708 | ||
|
|
c71a840e74 | ||
|
|
2b5c25ef17 | ||
|
|
da34156267 | ||
|
|
113ef45c6c | ||
|
|
67dd40dc08 | ||
|
|
1e0fee739e | ||
|
|
d59a98ffe6 | ||
|
|
5e9429afe8 | ||
|
|
31fd0451d0 | ||
|
|
b56be08f95 | ||
|
|
b1923cadb5 | ||
|
|
0a955c1020 | ||
|
|
791efc9e79 | ||
|
|
f9bc94bfb8 | ||
|
|
72119ddfa4 | ||
|
|
d4afca9b5a | ||
|
|
219ac40a7d | ||
|
|
b9378fe4c1 | ||
|
|
3c05822011 | ||
|
|
02cad7b5fe | ||
|
|
1a85ec5fdb | ||
|
|
3e19cfe58e | ||
|
|
3d3c7437be | ||
|
|
c4b57774f0 | ||
|
|
f7acded7a1 | ||
|
|
cabcca2e31 | ||
|
|
cc3237a77d | ||
|
|
b65e02420f | ||
|
|
5a7761c294 | ||
|
|
ad332494d0 | ||
|
|
eb212cd27e | ||
|
|
b604dd0bcc | ||
|
|
c0b879c998 | ||
|
|
e473af1635 | ||
|
|
8d9c6b2d01 | ||
|
|
7cdcb6c4ef | ||
|
|
ca44d84e55 | ||
|
|
e73a3c3376 | ||
|
|
1f9973e623 | ||
|
|
9077f3d675 | ||
|
|
ce61d27d8d | ||
|
|
5c1dbc0104 | ||
|
|
aa55f67ee3 | ||
|
|
9516694c35 | ||
|
|
c6a9f239c4 | ||
|
|
a922acc4dd | ||
|
|
bfef8c9bbe | ||
|
|
3fe2843bb3 | ||
|
|
42b8378988 | ||
|
|
c6bd721d2e | ||
|
|
83eedef999 | ||
|
|
1411e7f9f6 | ||
|
|
5d42d9212f | ||
|
|
4a1e05524a | ||
|
|
fb5ac9c4cd | ||
|
|
ed4e33d888 | ||
|
|
c6dd73065d | ||
|
|
9ef48de1a8 | ||
|
|
692ad43285 | ||
|
|
d06ff478d1 | ||
|
|
83db04cdce | ||
|
|
d0a724bb08 | ||
|
|
8e9ac1b9ac | ||
|
|
272d4efd4b | ||
|
|
4610f451e9 | ||
|
|
0810859c21 | ||
|
|
93c447051c | ||
|
|
60b3f042a8 | ||
|
|
c5632360d6 | ||
|
|
a379b4aab8 | ||
|
|
3b8d6ef208 | ||
|
|
9705d5e38b | ||
|
|
2e59b56f16 | ||
|
|
d9f9e8e57a | ||
|
|
33a8befbcf | ||
|
|
4f66a419e3 | ||
|
|
65992746d3 | ||
|
|
cbd4c64084 | ||
|
|
081be61f88 | ||
|
|
b89ca87280 | ||
|
|
ca84f10921 | ||
|
|
2200c4af6b | ||
|
|
838dfa453c | ||
|
|
6f3d636226 | ||
|
|
f03792619a | ||
|
|
21b3292fff | ||
|
|
39ebeb2401 | ||
|
|
8f4e8ed1e7 | ||
|
|
0e10ead81a | ||
|
|
476612d8f8 | ||
|
|
bd769c9261 | ||
|
|
831f78a389 | ||
|
|
920edce73e | ||
|
|
7dc7b002c5 | ||
|
|
c74c9bd693 | ||
|
|
1daf15c525 | ||
|
|
108949345f | ||
|
|
69eb309031 | ||
|
|
e7f0c8cbe1 | ||
|
|
9c8b663d5b | ||
|
|
8309b63fb1 | ||
|
|
6d6de880eb | ||
|
|
a65bf79ad9 | ||
|
|
c192188b42 | ||
|
|
a3516ce655 | ||
|
|
8481db4735 | ||
|
|
b6390c3dbd | ||
|
|
0f914cf747 | ||
|
|
5fab7d2993 | ||
|
|
faee142876 | ||
|
|
215c63233a | ||
|
|
e5afcd14a9 | ||
|
|
96a7d1e7ec | ||
|
|
2d2a65b616 | ||
|
|
b5d32fe271 | ||
|
|
8a5a69818e | ||
|
|
56701220e9 | ||
|
|
6bf434a7ab | ||
|
|
d1e767d30c | ||
|
|
4874df25a2 | ||
|
|
f43868e4dc | ||
|
|
bc8227d2bd | ||
|
|
09e748d6c9 | ||
|
|
4038ad5ce5 | ||
|
|
973864e045 | ||
|
|
af694b57a2 | ||
|
|
07be0c6ef4 | ||
|
|
78a336c092 | ||
|
|
649c0f8055 | ||
|
|
87b66b8db8 | ||
|
|
a4ffa3de7a | ||
|
|
dd111f55f6 | ||
|
|
5db6264d8f | ||
|
|
4ce63c8caf | ||
|
|
727f8b1d9b | ||
|
|
35f2bcf296 | ||
|
|
7ebfe84489 | ||
|
|
4e645debaa | ||
|
|
821ab99bf7 | ||
|
|
282e242f5e | ||
|
|
13deb8d8d7 | ||
|
|
389992c330 | ||
|
|
0753c52bed | ||
|
|
24ce9b0f8d | ||
|
|
6e6f8412a5 | ||
|
|
853cdcdd31 | ||
|
|
f24ec20623 | ||
|
|
cdc7d695e9 | ||
|
|
d1cf754c6e | ||
|
|
d1f63fe260 | ||
|
|
53eee70c03 | ||
|
|
7b73ba551e | ||
|
|
af1176274a | ||
|
|
4c2ef9947a | ||
|
|
db7c9e96ea | ||
|
|
ee5398b3be | ||
|
|
3d3ab0fedc | ||
|
|
d21efb51ce | ||
|
|
bd4c742212 | ||
|
|
c821fd938c | ||
|
|
977caba4ca | ||
|
|
8b167a70b8 | ||
|
|
ecca96c03e | ||
|
|
49231a593a | ||
|
|
0338899804 | ||
|
|
810c2250c4 | ||
|
|
5ed210f0f3 | ||
|
|
7508390747 | ||
|
|
67620b7948 | ||
|
|
6c0500d1b6 | ||
|
|
7144efff4e | ||
|
|
3ae31c34f6 | ||
|
|
bc5072ed54 | ||
|
|
2aa7c45ca2 | ||
|
|
73467dc523 | ||
|
|
4ff744ef89 | ||
|
|
b8722b3537 | ||
|
|
caed2ae757 | ||
|
|
5ffdb8eeb4 | ||
|
|
90445f7f1d | ||
|
|
5a298c165e | ||
|
|
63ba377f6f | ||
|
|
a15cdb4c1d | ||
|
|
dff14a868f | ||
|
|
4304301701 | ||
|
|
2dd31b0a44 | ||
|
|
23e01808a2 | ||
|
|
b8300add62 | ||
|
|
97cb1e2080 | ||
|
|
e9d6735e52 | ||
|
|
9d8381041d | ||
|
|
5cf4226c13 | ||
|
|
5bb3d8a24d | ||
|
|
1de683efa4 | ||
|
|
3e705be6c8 | ||
|
|
6548ec1b43 | ||
|
|
e739a74705 | ||
|
|
c0d401fbfc | ||
|
|
7b813d03b9 | ||
|
|
93d06e8680 | ||
|
|
7f22b33f5a | ||
|
|
ceaacba1c2 | ||
|
|
6bee1dcecd | ||
|
|
3c28048038 | ||
|
|
fb02ae0e9a | ||
|
|
ffb293fe0a | ||
|
|
f46522572e | ||
|
|
2ecb87ddc3 | ||
|
|
a34530ebb7 | ||
|
|
0973e7009e | ||
|
|
d0d18441cf | ||
|
|
3f1c37aa76 | ||
|
|
8165342670 | ||
|
|
686c68a90d | ||
|
|
86dbf089cc | ||
|
|
9f3ea84b57 | ||
|
|
3f007d2dbb | ||
|
|
cde68af79a | ||
|
|
574e70642b | ||
|
|
ae156d9326 | ||
|
|
c08268d0ae | ||
|
|
0e4d031054 | ||
|
|
de15ee057a | ||
|
|
1d873cc701 | ||
|
|
bcde60b9e8 | ||
|
|
d6d2b2e756 | ||
|
|
4276573f67 | ||
|
|
fa3481ea8e | ||
|
|
ac54eceea5 | ||
|
|
e1c29bf2af | ||
|
|
0fe560ed7f | ||
|
|
23269040a6 | ||
|
|
b03649748a | ||
|
|
06851f8b98 | ||
|
|
893fc7c940 | ||
|
|
3819aecf07 | ||
|
|
a186b22d6e | ||
|
|
a43186d137 | ||
|
|
554f4889bc | ||
|
|
b584832e75 | ||
|
|
299c911330 | ||
|
|
6318b592a3 | ||
|
|
2b7e7fe6f6 | ||
|
|
bb8983b48a | ||
|
|
666861419d | ||
|
|
52d6c5ac88 | ||
|
|
5b89a2375a | ||
|
|
c0d19de08d | ||
|
|
27d85a737c | ||
|
|
277f542304 | ||
|
|
517a5b6844 | ||
|
|
d4f98902a0 | ||
|
|
eb289e8542 | ||
|
|
06754daf87 | ||
|
|
ee509f6350 | ||
|
|
6a7c6cba12 | ||
|
|
129f5e93fa | ||
|
|
629312b382 | ||
|
|
d31524691b | ||
|
|
ff6ec86f1c | ||
|
|
0c55facdd9 | ||
|
|
d9e1f91735 | ||
|
|
9f037fef60 | ||
|
|
0bc7100ea8 | ||
|
|
8698a58a60 | ||
|
|
a8151de2cb | ||
|
|
7a9005dae6 | ||
|
|
a77f8bf203 | ||
|
|
efc7877ffd | ||
|
|
3cb7632dc8 | ||
|
|
cde8e54b51 | ||
|
|
8ce1a2d605 | ||
|
|
d09379990b | ||
|
|
136318f98a | ||
|
|
1775844f45 | ||
|
|
987a663094 | ||
|
|
107dbd5645 | ||
|
|
bebd8f3c1a | ||
|
|
3be1e33339 | ||
|
|
91348f22be | ||
|
|
c9279061fa | ||
|
|
5bfe397c63 | ||
|
|
a202640da4 | ||
|
|
08fcdfa0fb | ||
|
|
51fb706781 | ||
|
|
92ed70f029 | ||
|
|
067b28be41 | ||
|
|
81b7fc519c | ||
|
|
24cc0c8422 | ||
|
|
8459ea0d31 | ||
|
|
494c245b59 | ||
|
|
d87f0ea728 | ||
|
|
dbdfc13a23 | ||
|
|
c19730f5e2 | ||
|
|
446e735825 | ||
|
|
0e47d1269c | ||
|
|
7dc5359c2b | ||
|
|
e394903ccf | ||
|
|
98bb78ae3a | ||
|
|
defe5ce594 | ||
|
|
713e3fa89d | ||
|
|
73f813279a | ||
|
|
0063cad60d | ||
|
|
3bb3f618b9 | ||
|
|
53195e3a25 | ||
|
|
09103aa52e | ||
|
|
ee63a9f368 | ||
|
|
9a73c15b84 | ||
|
|
b50dec9d92 | ||
|
|
9f8feb622e | ||
|
|
db156b41fb | ||
|
|
374583bb48 | ||
|
|
5d3c218b1b | ||
|
|
f34427e772 | ||
|
|
a1666986c6 | ||
|
|
b669177c83 | ||
|
|
1678d2b97a | ||
|
|
3564f41c48 | ||
|
|
72314a33ab | ||
|
|
9289b29504 | ||
|
|
de115b87df | ||
|
|
cfeb0626cc | ||
|
|
3f2c4ed794 | ||
|
|
978256179b | ||
|
|
742af765ba | ||
|
|
035d0aebc1 | ||
|
|
a5dbd58200 | ||
|
|
9073e1d47e | ||
|
|
ed1078dadf | ||
|
|
83dbd728ef | ||
|
|
31a6149b0f | ||
|
|
3d274fdfd9 | ||
|
|
8f3ec680c7 | ||
|
|
612e94be9d | ||
|
|
7a95c78ba0 | ||
|
|
5a2a546090 | ||
|
|
baf6fc8987 | ||
|
|
bf75d6496f | ||
|
|
fb7f134c06 | ||
|
|
067dcbc0f7 | ||
|
|
280bc969ce | ||
|
|
010b8a79cb | ||
|
|
4ec39ae323 | ||
|
|
ec7c654451 | ||
|
|
6022a61b3c | ||
|
|
975b489007 | ||
|
|
f8f1859a05 | ||
|
|
92f2a44b28 | ||
|
|
7585a984b2 | ||
|
|
789bf9c220 | ||
|
|
2e9bc93e1f | ||
|
|
e2a993a425 | ||
|
|
d0b5c79b81 | ||
|
|
95622ca964 | ||
|
|
76b63de754 | ||
|
|
58cdb1bda2 | ||
|
|
a530f56511 | ||
|
|
bf6e74ad8e | ||
|
|
c2253dafc0 | ||
|
|
389d159c7a | ||
|
|
21161ae38e | ||
|
|
aa074d7121 | ||
|
|
99d04e93a2 | ||
|
|
d6b9df6ca2 | ||
|
|
4fbeca0aa3 | ||
|
|
f19b89b263 | ||
|
|
0a908d78ca | ||
|
|
f2b8b06280 | ||
|
|
0cc04e5253 | ||
|
|
5e9a9b9867 | ||
|
|
68826baf3b | ||
|
|
cc26096c28 | ||
|
|
1c110080a8 | ||
|
|
7b67bbe698 | ||
|
|
7692371ccb | ||
|
|
534eb4ce88 | ||
|
|
c88b936233 | ||
|
|
32c229215a | ||
|
|
9c5cc38c9a | ||
|
|
12795ea491 | ||
|
|
c0b143043f | ||
|
|
40b849da23 | ||
|
|
4f18bd6293 | ||
|
|
702e92d4f4 | ||
|
|
40fa336829 | ||
|
|
fa93803b45 | ||
|
|
7201dbd477 | ||
|
|
40248c3e13 | ||
|
|
f2a0a1b62d | ||
|
|
dcb4bbb3e6 | ||
|
|
21c56e7898 | ||
|
|
7c74e7be35 | ||
|
|
bf5ec1eb57 | ||
|
|
342241a24d | ||
|
|
d047dcb983 | ||
|
|
0fc310f1c4 | ||
|
|
c6e14a562b | ||
|
|
a3f6a7ddbc | ||
|
|
c8c09d7e09 | ||
|
|
411163c73f | ||
|
|
b25aa07e11 | ||
|
|
bc72a506c1 | ||
|
|
8451c62b44 | ||
|
|
1f3729822a | ||
|
|
a27283aa9b | ||
|
|
1eb1bd6800 | ||
|
|
cda4af3403 | ||
|
|
93ea5bacb7 | ||
|
|
841c5c22e0 | ||
|
|
511446846f | ||
|
|
a79bf97b48 | ||
|
|
a78d5e2636 | ||
|
|
b6d2e3fb55 | ||
|
|
43850ac856 | ||
|
|
532b1697a6 | ||
|
|
a3f63a12f9 | ||
|
|
b2dfe64cea | ||
|
|
ff7dc072d1 | ||
|
|
b185afa29f | ||
|
|
742742fd48 | ||
|
|
5f6104a9d3 | ||
|
|
787198b30e | ||
|
|
3490c63259 | ||
|
|
8077d7bb0b | ||
|
|
b2c8c227ec | ||
|
|
ca8ff5fda9 | ||
|
|
a6f2d96557 | ||
|
|
948205e6f9 | ||
|
|
d90b6b7e51 | ||
|
|
e3e1ee313b | ||
|
|
dc5c049ed9 | ||
|
|
642260bdb6 | ||
|
|
bafa85e772 | ||
|
|
4f102a43fa | ||
|
|
2ac265d529 | ||
|
|
e261270eb8 | ||
|
|
d08bd0c619 | ||
|
|
cc833341e4 | ||
|
|
add0081b50 | ||
|
|
46fb9d6df1 | ||
|
|
e324942a07 | ||
|
|
b853012cb6 | ||
|
|
d64d7db5f5 | ||
|
|
d19a076f1e | ||
|
|
5ad314ba5a | ||
|
|
c7473dd7c9 | ||
|
|
abb9ab1bb6 | ||
|
|
8bc9baefd6 | ||
|
|
0fe835e087 | ||
|
|
e8ed41c763 | ||
|
|
d9cd0604cc | ||
|
|
afb2cc4a99 | ||
|
|
a72751914d | ||
|
|
9e3c5b1bf2 | ||
|
|
bf77789076 | ||
|
|
1b0d063cff | ||
|
|
24f8f47f76 | ||
|
|
7745457f9b | ||
|
|
660bbae9a8 | ||
|
|
c071e9b051 | ||
|
|
1c1bab8d6b | ||
|
|
8beb818100 | ||
|
|
1ff0a7c4e7 | ||
|
|
49991a3341 | ||
|
|
88af5ea07c | ||
|
|
63fbd64eb8 | ||
|
|
8337fd306a | ||
|
|
7df6dbeafb | ||
|
|
bf2d6b8999 | ||
|
|
5528cb9f16 | ||
|
|
d8bc6dcc1b | ||
|
|
c0ebc4cbb0 | ||
|
|
e3b6d6e6b2 | ||
|
|
a50b10b869 | ||
|
|
183704ab95 | ||
|
|
e654ed980a | ||
|
|
a4eb35371f | ||
|
|
0931f95e65 | ||
|
|
83997e1125 | ||
|
|
555a1184e4 | ||
|
|
f6b31f65ac | ||
|
|
fc67b208ad | ||
|
|
b6f83007eb | ||
|
|
6e82268704 | ||
|
|
4142cc296b | ||
|
|
e98b1e6716 | ||
|
|
fda8b96063 | ||
|
|
bb8e11e08d | ||
|
|
aee1fe1004 | ||
|
|
fbcd77a1a7 | ||
|
|
90f58dbcbe | ||
|
|
729d19ab24 | ||
|
|
ca9a1b6666 | ||
|
|
08aa003335 | ||
|
|
b0a56e2790 | ||
|
|
01f589885f | ||
|
|
038c940e8e | ||
|
|
20067c02bc | ||
|
|
efa3fa3aed | ||
|
|
e0908ced14 | ||
|
|
3068ca8908 | ||
|
|
88406332d2 | ||
|
|
6cb9561d96 | ||
|
|
3135ba57cd | ||
|
|
96420b959a | ||
|
|
15bda0af27 | ||
|
|
a076e9b0a8 | ||
|
|
0cb4fa67f1 | ||
|
|
bf79be222c | ||
|
|
1bb27f2b80 | ||
|
|
96dae29f4d | ||
|
|
4e0df627df | ||
|
|
15411c7c9e | ||
|
|
b4c389c374 | ||
|
|
44aeead296 | ||
|
|
5e0d4800d9 | ||
|
|
e1a8e8d82d | ||
|
|
4ae714089d | ||
|
|
3894da6242 | ||
|
|
2f74e6ebf8 | ||
|
|
c1aeb2244c | ||
|
|
d231851734 | ||
|
|
c4a68bcd43 | ||
|
|
1add5dac3e | ||
|
|
ec3786f862 | ||
|
|
0e761801de | ||
|
|
39f70c0956 | ||
|
|
0674636243 | ||
|
|
ea89d85845 | ||
|
|
0f3884afde | ||
|
|
7b3d4c6359 | ||
|
|
f9a8fa3854 | ||
|
|
575c86551e | ||
|
|
57bbac4923 | ||
|
|
7f8167e4e2 | ||
|
|
ebce5998de | ||
|
|
672a41a79c | ||
|
|
48b881f491 | ||
|
|
a6f0525a4c | ||
|
|
d9707926fa | ||
|
|
e38c663dea | ||
|
|
b1873b21b6 | ||
|
|
4c4d3dc9e7 | ||
|
|
c7e6777cc1 | ||
|
|
5336524129 | ||
|
|
de30d37ba9 | ||
|
|
e2b6e32fe9 | ||
|
|
f2573a5c02 | ||
|
|
96f8873f2c | ||
|
|
b3919fe819 | ||
|
|
9eeaaf0a03 | ||
|
|
9328ba79d1 | ||
|
|
0c7168648f | ||
|
|
26f8a756cb | ||
|
|
4174442558 | ||
|
|
452a390325 | ||
|
|
9fcb6e1f38 | ||
|
|
826f9cf2f3 | ||
|
|
c18fbfa106 | ||
|
|
cd695f735b | ||
|
|
0e3cd11a55 | ||
|
|
1236c16c83 | ||
|
|
66a47329db | ||
|
|
322f18926e | ||
|
|
5bbc241168 | ||
|
|
83925633e0 | ||
|
|
42943eab95 | ||
|
|
66bf32bafa | ||
|
|
aa42913ece | ||
|
|
e4e8a46424 | ||
|
|
dfe894a39b | ||
|
|
c80feac629 | ||
|
|
71c1ca3eb6 | ||
|
|
ffc99aa52e | ||
|
|
4b10506691 | ||
|
|
57f1f82d76 | ||
|
|
53f84817ba | ||
|
|
221527e0e1 | ||
|
|
501ab2bbe8 | ||
|
|
f78c5a2b18 | ||
|
|
962c3c25b6 | ||
|
|
ae6d6d753a | ||
|
|
3e764fdc45 | ||
|
|
f52ee794db | ||
|
|
34ece330f3 | ||
|
|
7adaf39f1a | ||
|
|
6392550208 | ||
|
|
98d705ed9b | ||
|
|
a356eb7abf | ||
|
|
e950872ec9 | ||
|
|
ab1fdbfead | ||
|
|
7ac8d7de22 | ||
|
|
f012e02b35 | ||
|
|
1ffbb7bf6b | ||
|
|
72927195fd | ||
|
|
e29326d8d0 | ||
|
|
b7bf1955b7 | ||
|
|
1057b88ba7 | ||
|
|
de21088bc4 | ||
|
|
d8698cdc84 | ||
|
|
1ae1906637 | ||
|
|
5a0fc820d4 | ||
|
|
a1f51ad7dc | ||
|
|
fbb89dcf10 | ||
|
|
736552a559 | ||
|
|
162abb0a32 | ||
|
|
a2cd8b72dc | ||
|
|
11aca3f0aa | ||
|
|
c312ca45bd | ||
|
|
f1dc84afef | ||
|
|
7cafe8311e | ||
|
|
9513053f74 | ||
|
|
bfea73d5d8 | ||
|
|
2ae1713ac1 | ||
|
|
fb2047853c | ||
|
|
3dec81b9eb | ||
|
|
b0fa2f5ec0 | ||
|
|
6c367f4a29 | ||
|
|
c8d4d3b69e | ||
|
|
a0234eed48 | ||
|
|
8cc3b54bcd | ||
|
|
d8630d5bdc | ||
|
|
82118c854c | ||
|
|
b1b558d244 | ||
|
|
6ef734960a | ||
|
|
244e3eafdf | ||
|
|
59e367a88e | ||
|
|
681f0ef111 | ||
|
|
098317ed29 | ||
|
|
30cc36abca | ||
|
|
58090c2c32 | ||
|
|
008f5913e9 | ||
|
|
349736b0a5 | ||
|
|
42e926e27c | ||
|
|
80be548b64 | ||
|
|
bb22be4f4f | ||
|
|
fab4c72285 | ||
|
|
9bb42fc5bf | ||
|
|
5d93fc58b3 | ||
|
|
ab633484cd | ||
|
|
5e69a69b8d | ||
|
|
50a9aef179 | ||
|
|
13bc7d17bf | ||
|
|
d8c328ec09 | ||
|
|
2a4c1d0aac | ||
|
|
6c4b88123a | ||
|
|
b78f3a8216 | ||
|
|
8f93b18469 | ||
|
|
a66725adc4 | ||
|
|
8d9d5f3fc3 | ||
|
|
9699198bcc | ||
|
|
aa163b5010 | ||
|
|
aacc392049 | ||
|
|
74b99b52ee | ||
|
|
c7b573dcff | ||
|
|
5b03a1e218 | ||
|
|
77db70f9b5 | ||
|
|
0379d02d8c |
No files matched your search
@@ -0,0 +1,14 @@
|
||||
---
|
||||
BasedOnStyle: WebKit
|
||||
AlignTrailingComments: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
ColumnLimit: 0
|
||||
IndentWidth: 4
|
||||
SortIncludes: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
IndentCaseLabels: true
|
||||
AlignConsecutiveMacros: true
|
||||
---
|
||||
@@ -13,12 +13,16 @@ on:
|
||||
- X64
|
||||
- GENERIC_ARM
|
||||
- PHYTIUM
|
||||
- RK3288
|
||||
- RK3326
|
||||
- RK3399
|
||||
- RK3588
|
||||
- RPI4ARM64
|
||||
- RPI5ARM64
|
||||
- SD845
|
||||
- SD888
|
||||
- ADLINK
|
||||
- TEGRAX1
|
||||
- ARM64
|
||||
build_type:
|
||||
description: 'Build type'
|
||||
required: true
|
||||
|
||||
@@ -27,21 +27,37 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RK3326, RK3399, RK3288, TEGRAX1, PHYTIUM, SD845]
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RPI5ARM64, RK3326, RK3399, RK3588, PHYTIUM, SD845, SD888, ADLINK, ARM64, ANDROID]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-20.04
|
||||
- platform: TEGRAX1
|
||||
type: Trace
|
||||
os: ubuntu-20.04
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu 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 "BOX64_COMPILER=$PWD/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DNOLOADADDR=1" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'X64' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
@@ -80,17 +96,37 @@ jobs:
|
||||
${{ env.BOX64_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON\
|
||||
-DCI=${{ matrix.platform != 'ANDROID' }}
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Test Box64"
|
||||
if: ${{ matrix.platform == 'X64' }}
|
||||
if: ${{ matrix.platform != 'TEGRAX1' }}
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'ANDROID' ]]; then
|
||||
mkdir qemu8.1.0
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-8.1.0-2-x86_64.pkg.tar.zst | tar -I zstd -C qemu8.1.0 -xf -
|
||||
sudo cp qemu8.1.0/usr/bin/* /usr/bin/
|
||||
fi
|
||||
|
||||
cd build
|
||||
ctest -j$(nproc)
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'ANDROID' ]]; then # AArch64
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
true
|
||||
else
|
||||
BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
fi
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
@@ -55,6 +55,7 @@ dkms.conf
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
.cache
|
||||
.gdb_history
|
||||
src/git_head.h
|
||||
backup/
|
||||
@@ -64,3 +65,6 @@ backup/
|
||||
!/LLVMprivateGenerator/Makefile
|
||||
!/LLVMprivateGenerator/main.cpp
|
||||
!/LLVMprivateGenerator/registered_structs.cpp
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
Executable → Regular
File mode changed.
Executable → Regular
+487
-96
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,123 @@
|
||||

|
||||
|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
[View changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64-bit little-endian).
|
||||
|
||||
You can find many Box64 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.
|
||||
|
||||
Since Box64 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/).
|
||||
|
||||
Box64 integrates with DynaRec (dynamic recompiler) for the ARM64 and RV64 platform, providing a speed boost between 5 to 10 times faster than using only the interpreter. Some high level information on how DynaRec works can be found [here](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Some x64 internal opcodes use parts of "Realmode X86 Emulator Library", see [x64primop.c](src/emu/x64primop.c) for copyright details
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box64.
|
||||
|
||||
See [here](docs/USAGE.md) for all the environment variables and what they do.
|
||||
|
||||
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md) \
|
||||
> Instructions for installing Wine for Box64 can be found [here](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
|
||||
----
|
||||
|
||||
Version history/Change log
|
||||
----
|
||||
|
||||
The change log is available [here](docs/CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Notes about 32-bit platforms
|
||||
----
|
||||
|
||||
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bit libraries. Box64 doesn't include any 64-bit <-> 32-bit translation.
|
||||
|
||||
So understand that box64 will only run 64-bit linux binaries. For 32-bit binaries, you need box86 (with all the multiarch or proot trickery it implies on a 64-bit OS).
|
||||
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when the argument is "-m"
|
||||
|
||||
----
|
||||
|
||||
Notes about Box64 configuration
|
||||
----
|
||||
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box4.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reason, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.box64rc` > `/etc/box64.box64rc` > command line
|
||||
So, your settings in `~/.box64rc` may override the setting from your command line...
|
||||
|
||||
----
|
||||
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games should just work, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers). Also many newer Unity3D (like KSP) games use the BC7 compressed textures, which is not supported on many ARM integrated GPU.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
|
||||
Notes about GTK programs
|
||||
----
|
||||
|
||||
GTK libraries are now wrapped on box64, both gtk2 and gtk3.
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Note that Steam is a hybrid 32-bit / 64-bit. You NEED box86 to run Steam, as the client app is a 32-bit binary. It also uses a 64-bit local server binaries, and that steamwebhelper process is now mandatory, even on the "small mode". And that process will eat lots of memory. So machine with less the 6Gb of RAM will need a swapfile to use Steam.
|
||||
|
||||
----
|
||||
|
||||
Notes about Wine
|
||||
----
|
||||
|
||||
Wine64 is supported on box64. Proton too. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively).
|
||||
Note that the new 32-bit PE in 64-bit processes that the Wine team is currently implementing in Wine 7.+ is now supported, but the support is quite young so there might be some residual issues.
|
||||
|
||||
----
|
||||
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box64 wraps Vulkan libraries, but note that it as mostly been tested with an AMD RX550 card and on the Freedreno driver, so some extensions may be missing depending on your graphics card.
|
||||
|
||||
----
|
||||
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box64 development.
|
||||
There are many ways to contribute: code contribution, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, mogery
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* For their major code contribution on the RV64 Dynarec: ksco, xctan
|
||||
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/)
|
||||
* For their continuous advertisements for the box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
And I also thank the many other people who participated even once in this project.
|
||||
|
||||
(If you use Box64 in your project, please don't forget to mention it!)
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# box64
|
||||
|
||||

|
||||
Linux 上用户空间的 x86_64 应用模拟器(支持运行原生库)
|
||||
|
||||
----
|
||||

|
||||
|
||||
[English](docs/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md)
|
||||
|
||||
Box64 可以在非 x86_64 Linux 系统(比如 ARM64)上运行 x86_64 Linux 程序(比如游戏),注意主机系统需要是 64 位小端。
|
||||
|
||||
您可以在 [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)、[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) 和 [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube 频道上找到许多 Box64 视频。
|
||||
|
||||
由于 Box64 使用一些“系统”库的原生版本,如 libc、libm、SDL 和 OpenGL 等,因此很容易与大多数应用程序集成和使用,并且在许多情况下性能会相当不错。可以在[这里](https://box86.org/index.php/2021/06/game-performances/)查看一些性能测试的样例。
|
||||
|
||||
Box64 集成了适用于 ARM64 和 RV64 平台的 DynaRec(动态重编译器),速度可以比纯解释模式快 5 到 10 倍。可以在[这里](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/)找到有关 DynaRec 工作原理的一些信息。
|
||||
|
||||
一些 x64 内部操作码使用 “Realmode X86 Emulator Library” 的部分内容,有关版权详细信息,请参见 [x64primop.c](../src/emu/x64primop.c)。
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
LOGO 由 @grayduck 制作,感谢!
|
||||
|
||||
----
|
||||
|
||||
使用方法
|
||||
----
|
||||
|
||||
有若干环境变量可以控制 Box64 的行为。
|
||||
|
||||
可在[这里](docs/USAGE.md)查看所有环境变量及其作用。
|
||||
|
||||
注意:Box64 的 Dynarec 使用具有内存保护和段错误信号处理的机制来执行 JIT 代码。所以,如果想使用 GDB 调试使用 JIT 代码的程序(如 Mono/Unity3D),这会触发许多“正常”的段错误。建议在 GDB 中使用类似 `handle SIGSEGV nostop` 来防止它每个段错误处停止。如果你想捕获段错误,可以在 `signals.c` 的 `my_memprotectionhandler` 中设置断点。
|
||||
|
||||
----
|
||||
|
||||
编译/安装
|
||||
----
|
||||
|
||||
编译说明可以在[这里](docs/COMPILE.md)查看。
|
||||
|
||||
----
|
||||
|
||||
版本历史
|
||||
----
|
||||
|
||||
版本日志在[这里](docs/CHANGELOG.md)。
|
||||
|
||||
----
|
||||
|
||||
32位平台的注意事项
|
||||
----
|
||||
|
||||
因为 Box64 的工作原理是直接将函数调用从 x86_64 转换为主机系统,所以主机系统(运行 Box64 的系统)需要有 64 位库。Box64 不包含任何 64 位 <-> 32 位的转换。
|
||||
|
||||
所以 box64 只能运行 64 位的 Linux 二进制。对于 32 位二进制则需要使用 box86 来运行(它在 64 位操作系统上使用了 multiarch 和 proot 等技巧来实现运行)。请注意,许多(基于 mojo 的)安装程序在检测到 ARM64 操作系统时将回退到 “x86”,因此即使存在 x86_64 版本,也会尝试使用 box86。这时你可以使用一个假的 `uname` ,并使它在运行参数为 `-m` 时返回 `x86_64`。
|
||||
|
||||
----
|
||||
|
||||
关于 Unity 游戏模拟的注意事项
|
||||
----
|
||||
|
||||
运行 Unity 游戏应该没什么问题,但还应该注意,许多 Unity3D 游戏需要 OpenGL 3+,这在 ARM SBC 上可能会比较棘手。同时许多较新的 Unity3D游戏(如 KSP)也使用 BC7 压缩纹理,很多 ARM 的集成显卡并不支持。
|
||||
|
||||
> 提示:如果游戏开始后没有显示任何东西就退出了,在 Pi4 上可以使用 `MESA_GL_VERSION_OVERRIDE=3.2`,在 Panfrost 上则可以使用 `PAN_MESA_DEBUG=gl3` 来使用更高的配置。
|
||||
|
||||
----
|
||||
|
||||
关于GTK程序的注意事项
|
||||
----
|
||||
|
||||
box64 封装了 GTK,包括 gtk2 和 gtk3。
|
||||
|
||||
----
|
||||
|
||||
关于 Steam 的注意事项
|
||||
----
|
||||
|
||||
请注意,Steam 是 32/64 位混合的应用,所以你需要 box86 才能运行,因为客户端应用程序是 32 位的。它还使用 64 位本地服务器,它的 steamwebhelper 无法被关闭(即使是在最小模式)而且会吃掉大量的内存。对于内存小于 6 GB 的机型,你将会需要创建 swapfile 来运行 Steam。
|
||||
|
||||
----
|
||||
|
||||
关于 Wine 的注意事项
|
||||
----
|
||||
|
||||
box64 支持 Wine64,Proton 应该也能运行。请注意,64 位 Wine 包含有 32 位组件,以便能够运行 32 位 Windows 程序。32 位应用程序需要 box86,否则无法运行。在 box64 和 box86 都存在并工作的系统上,64 位的 Wine 可以同时运行 32 位和 64 位 Windows 程序(分别使用 `wine` 和 `wine64`)。请注意,目前在 Wine 7.+ 中实现的 Wine 时间在 64 位进程中的新 32bit PE 尚不支持。我测试了 Wine 7.5 64 位可以正常工作,但是更新的版本可能还不行。
|
||||
|
||||
----
|
||||
|
||||
关于 Vulkan 注意事项
|
||||
----
|
||||
|
||||
Box64 封装了 Vulkan 库,但请注意,它仅在 RX550 显卡上进行过测试,因此根据您的显卡,某些扩展可能会丢失。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
----
|
||||
|
||||
我要感谢所有为 box64 开发做出贡献的人。
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
|
||||
* 代码贡献:rajdakin, mogery
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠和 LoongArch 迁移:[xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* 硬件捐赠:[ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
(如果你的项目中使用了Box64,请不要忘记提及!)
|
||||
+119
@@ -0,0 +1,119 @@
|
||||

|
||||
|
||||
Емулятор простіра користувача x86_64 із родзинкою
|
||||
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Повідомити про помилку](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Box64 дозволяє запускати x86_64 Linux програми (наприклад, ігри) на системах Linux відмінних від x86_64, наприклад ARM (хост-система має мати 64-розрядний порядок редагування).
|
||||
|
||||
Ви можете знайти багато відео про Box64 в YouTube каналах [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) або [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
|
||||
Оскільки Box64 використовує рідні версії деяких «системних» бібліотек, таких як libc, libm, SDL і OpenGL, його легко інтегрувати та використовувати з більшістю програм, а продуктивність у багатьох випадках може бути напрочуд високою. Подивіться на цей стендовий аналіз для прикладу [тут](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
Box64 інтегрується з DynaRec (динамічний рекомпілятор) для платформ ARM64 і RV64 забезпечуючи підвищення швидкості в 5-10 разів, ніж використання лише інтерпретатора. Деякі високорівневі відомості про те, як працює DynaRec, можна знайти [тут](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Деякі внутрішні коди операцій x64 використовують частини «Бібліотеки емулятора Realmode X86», дивіться [x64primop.c](src/emu/x64primop.c) для детальної інформації про авторські права.
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Логотип і піктограма зроблені @grayduck, дякую!
|
||||
|
||||
----
|
||||
|
||||
Використання
|
||||
----
|
||||
|
||||
Є кілька змінних середовища для керування поведінкою Box64.
|
||||
|
||||
Дивіться [тут](docs/USAGE.md) для перегляду всіх змінних середовища та того, що вони роблять.
|
||||
|
||||
Примітка: Dynarec від Box64 використовує механізм із захистом пам’яті та обробником сигналу помилки сегментів для обробки JIT коду. Простіше кажучи, якщо ви хочете використовувати GDB для налагодження запущеної програми, яка використовує JIT-код (наприклад, mono/Unity3D), ви все одно матимете багато «звичайних» помилок сегментів. Пропонується використовувати щось на зразок `handle SIGSEGV nostop` в GDB, щоб не зупинятися на кожній помилці сегмента, і, можливо, поставити точку зупину всередині `my_memprotectionhandler` в `signals.c`, якщо ви хочете перехопити помилки сегментів.
|
||||
|
||||
----
|
||||
Компіляція/Встановлення
|
||||
----
|
||||
> Інструкцію зі складання Box64 можна знайти [тут](docs/COMPILE.md).\
|
||||
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/X64WINE.md).
|
||||
|
||||
----
|
||||
|
||||
Історія версій/Журнал змін
|
||||
----
|
||||
|
||||
Історія версій доступна [тут](docs/CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо 32 бітних платформ
|
||||
----
|
||||
Оскільки Box64 працює шляхом прямого перекладу викликів функцій з x86_64 на хост-систему, хост-система (та, на якій працює Box64) повинна мати 64-розрядні бібліотеки. Box64 не містить 64-біт <-> 32-біт перекладу.
|
||||
|
||||
Також розумійте що Box64 запускатиме лише 64-розрядні двійкові Linux файли. Для 32-розрядних двійкових файлів вам потрібен Box86 (з усіма хитрощами з мультиархітектурною системою або корінними правами). Зауважте, що багато інсталяторів (на основі mojo) повертаються до "x86" при виявленні ОС ARM64, і тому намагатимуться використовувати Box86 для налаштування, навіть якщо існує версія x86_64. Ви можете зламати свій шлях за допомогою фальшивого "uname", який повертає "x86_64", коли аргумент "-m"
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо конфігурації Box64
|
||||
----
|
||||
|
||||
Обидва файли мають однаковий синтаксис і в основному є файлами ini. Розділ у квадратних дужках визначає назву процесу, а решта — встановлють змінну середовища. Подивіться [використання](USAGE.md), щоб дізнатися, які параметри можна завдати. Box64 поставляється з файлом за замовчуванням, який слід встановити для кращої стабільності. Файл знаходиться в `system/box64.box64rc` і має бути встановлен в `/etc/box64.box64rc`. Якщо з певних причин ви не хочете встановлювати цей файл у `/etc`, принаймні скопіюйте його в `~/.box64rc` або гра може не працювати належним чином. Зауважте, що пріоритетом є: `~/.bashrc` > `/etc/box64.box64rc` > командний рядок
|
||||
Таким чином, ваші налаштування в `~/.bashrc` можуть замінити налаштування з вашого командного рядка...
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо емуляції ігор Unity
|
||||
----
|
||||
|
||||
Запуск ігор Unity має працювати, але ви також повинні зауважити, що для багатьох ігор Unity3D потрібен OpenGL 3+, який може бути складно забезпечити на ARM SBC (одноплатних комп’ютерах). Крім того, багато нових ігор Unity3D (наприклад, KSP) використовують стиснуті текстури BC7, які не підтримуються багатьма інтегрованими GPU ARM.
|
||||
Підказка: в Pi4 використовуйте `MESA_GL_VERSION_OVERRIDE=3.2`, а в Panfrost — `PAN_MESA_DEBUG=gl3`, щоб використовувати вищий профіль, якщо гра запускається, а потім завершується, перш ніж щось показує.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо програм GTK
|
||||
----
|
||||
|
||||
Бібліотеки GTK2 і GTK3 тепер використовуються в Box64.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Steam
|
||||
----
|
||||
|
||||
Зауважте, що Steam є гібридом 32-біт / 64-біт. Вам ПОТРІБЕН box86, щоб запустити Steam, оскільки клієнта є 32-розрядною двійковою програмою. Він також використовує 64-розрядні двійкові файли локального сервера, і цей процес steamwebhelper тепер є обов’язковим навіть у «малому режимі». І цей процес з’їсть багато оперативної пам’яті, таким чином машині з 6 Гб оперативної пам’яті знадобиться файл підкачки для використання Steam.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Wine
|
||||
----
|
||||
|
||||
Wine64 підтримується Box64, Proton теж. Майте на увазі, що 64-розрядний Wine також містить 32-розрядні компоненти щоб мати можливість запускати 32-розрядні програми Windows. Для 32-розрядних програм потрібен Box86, і вони не працюватимуть без нього. У системі, де присутні і працюють Box64, і Box86, 64-розрядне встановлення Wine може запускати як 32-розрядні, так і 64-розрядні програми Windows (просто використовуйте `wine` і `wine64` відповідно).
|
||||
Зауважте, що новий 32-бітний PE в 64-бітному процесі, який Wine зараз реалізує у Wine 7+ тепер підтримується, але підтримка є досить молодою тому можуть виникнути деякі проблеми.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Vulkan
|
||||
----
|
||||
|
||||
Box64 використовує бібліотеки Vulkan, але зауважте що він тестувався з картою AMD Radeon RX550 і драйвером Freedreno, тому деякі розширення можуть бути відсутні залежно від вашої відеокарти.
|
||||
|
||||
----
|
||||
|
||||
Останнє слово
|
||||
----
|
||||
|
||||
Я хочу подякувати всім, хто зробив внесок у розвиток box64.
|
||||
Є багато способів зробити внесок: внесок коду, фінансовий внесок, апаратне забезпечення та реклама!
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, mogery
|
||||
* За великий фінансовий внесок: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
|
||||
* За основний внесок у код RV64 Dynarec: ksco, xctan
|
||||
* За внесок у апаратне забезпечення: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* За безперервну рекламу Box64: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/Команда [TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
|
||||
|
||||
(Якщо ви використовуєте Box64 у своєму проекті, будь ласка, не забудьте згадати про це!)
|
||||
Vendored
+128
-2
@@ -1,3 +1,129 @@
|
||||
box64 (0.2.6) unstable; urgency=low
|
||||
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: More opcodes on ARM64 & RV64
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
|
||||
* Dynarec: RV64: Many fixes, making Wow64 apps running
|
||||
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
|
||||
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
|
||||
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* CPU: Added full support for SHA extension
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Added some more syscalls
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* OS: New option to use mold for a high speed link
|
||||
* => More hadware support, more functions wrapped for an improve compatibity
|
||||
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
|
||||
* => Some work also to reduce the memory footprint
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
|
||||
box64 (0.2.4) unstable; urgency=low
|
||||
|
||||
* Added Dynarec for RISC-V
|
||||
* Added partial 32 bits support (WoW64 works)
|
||||
* Changed cpuid to display box64
|
||||
* Fixed steam, again
|
||||
* Improved hacked version for overridden malloc/free functions
|
||||
* More wrapped libs
|
||||
* More wrapped functions and syscalls
|
||||
* Reduced memory footprint
|
||||
* Added support for the BIND_NOW flags in ELF files
|
||||
* Added RTLD_NOLOAD support
|
||||
* Fixed some typos and general cleanup, again
|
||||
* Added a cosimulation mode (to compare the behaviour of the dynarec with the interpreter)
|
||||
* Added FASTNAN/FASTROUND handling for more opcodes
|
||||
* Better float/double/long double handling
|
||||
* Better dlopen/dlclose handling
|
||||
* More games in the rc file
|
||||
* Added BOX64_DYNAREC_MISSING to show only missing opcode, independantly of the log level
|
||||
* Added BOX64_RESERVE_HIGH to reserve addresses above 47bits
|
||||
* Improved multitreading support
|
||||
* Ukrainian translation of the README
|
||||
* => Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
|
||||
* => Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.2) unstable; urgency=low
|
||||
|
||||
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadaptor9 wrapping
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.0) unstable; urgency=low
|
||||
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved execv family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
|
||||
* Fix typos and arch type string by @archanox in #321
|
||||
* Fix grammar by @Jai-JAP in #326
|
||||
* Enable 64k page size by @martinmanyhats in #334
|
||||
* Align address when call mprotect by @wannacu in #336
|
||||
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
|
||||
* add 18.04 tegra X1 github actions by @theofficialgman in #345
|
||||
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
|
||||
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
|
||||
* Add SW64 base support by @wannacu in #382
|
||||
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
|
||||
* Create X64WINE.md by @WheezyE in #423
|
||||
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
|
||||
* Malloc override by @ptitSeb in #437
|
||||
* Remove dynablocklist by @ptitSeb in #438
|
||||
* Fix Pkgbuilds by @Jai-JAP in #452
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
|
||||
|
||||
box64 (0.1.8) unstable; urgency=low
|
||||
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
@@ -23,7 +149,7 @@ box64 (0.1.8) unstable; urgency=low
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* Added some more Syscall
|
||||
* Wrapped Vulkan library. Vulkan and dxvk now supported!
|
||||
* Support building on PPC64LE (interpretor only)
|
||||
* Added support for Risc-V (interpretor only)
|
||||
* Support building on PPC64LE (interpreter only)
|
||||
* Added support for Risc-V (interpreter only)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
|
||||
Vendored
+3
-2
@@ -6,7 +6,8 @@
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1
|
||||
-DARM_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.6
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.5 --exclude=libstdc++.so.6
|
||||
+115
-5
@@ -1,3 +1,113 @@
|
||||
v0.2.6
|
||||
======
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: More opcodes on ARM64 & RV64
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
|
||||
* Dynarec: RV64: Many fixes, making Wow64 apps running
|
||||
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
|
||||
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
|
||||
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* CPU: Added full support for SHA extension
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Added some more syscalls
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* OS: New option to use mold for a high speed link
|
||||
=> More hadware support, more functions wrapped for an improve compatibity
|
||||
=> More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
|
||||
=> Some work also to reduce the memory footprint
|
||||
|
||||
v0.2.4
|
||||
======
|
||||
* Added Dynarec for RISC-V
|
||||
* Added partial 32 bits support (WoW64 works)
|
||||
* Changed cpuid to display box64
|
||||
* Fixed steam, again
|
||||
* Improved hacked version for overridden malloc/free functions
|
||||
* More wrapped libs
|
||||
* More wrapped functions and syscalls
|
||||
* Reduced memory footprint
|
||||
* Added support for the BIND_NOW flags in ELF files
|
||||
* Added RTLD_NOLOAD support
|
||||
* Fixed some typos and general cleanup, again
|
||||
* Added a cosimulation mode (to compare the behaviour of the dynarec with the interpreter)
|
||||
* Added FASTNAN/FASTROUND handling for more opcodes
|
||||
* Better float/double/long double handling
|
||||
* Better dlopen/dlclose handling
|
||||
* More games in the rc file
|
||||
* Added BOX64_DYNAREC_MISSING to show only missing opcode, independantly of the log level
|
||||
* Added BOX64_RESERVE_HIGH to reserve addresses above 47bits
|
||||
* Improved multitreading support
|
||||
* Ukrainian translation of the README
|
||||
=> Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
|
||||
=> Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
|
||||
|
||||
v0.2.2
|
||||
======
|
||||
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
=> Steam Large mode and new BigPicture are working
|
||||
=> Heroic Launcher is working
|
||||
* Added rcfile handling: box64 now read `/etc/box64.box64rc` and `~/.box64rc` and apply per process parameters
|
||||
=> Every program can be finetuned, for speed or just to make them work
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Box64 now return a custom name for the CPU instal of P4, build with Box64 and the cpu name it's running on
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadapter9 wrapping
|
||||
=> gallium nine is now supported on box64 too
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
|
||||
v0.2.0
|
||||
======
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved `execv` family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
=> Lot's of new games stat working, to name a few: Surviving Mars, Piczle Cross Adventure (using Proton experimental), UT2004, Obduction, Machinarium, Silicon Zero, Hacknet, Absolute Drift, Art of Rally, Dota2
|
||||
=> Some apps also runs now, like TeamSpeak 3 Client and Server or Discord
|
||||
=> The bash integration is usefull for device with no binfmt integration or for script that check the machine it's running on
|
||||
|
||||
v0.1.8
|
||||
======
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
@@ -23,8 +133,8 @@ v0.1.8
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* Added some more Syscall
|
||||
* Wrapped Vulkan library. Vulkan and dxvk now supported!
|
||||
* Support building on PPC64LE (interpretor only)
|
||||
* Added support for Risc-V (interpretor only)
|
||||
* Support building on PPC64LE (interpreter only)
|
||||
* Added support for Risc-V (interpreter only)
|
||||
|
||||
v0.1.6
|
||||
======
|
||||
@@ -40,7 +150,7 @@ v0.1.6
|
||||
* Some residual fixes on thread attribute handling
|
||||
* Better handling of app that want 32bits jumps, like unity3d/mono (thanks mogery)
|
||||
* More ARM hardware option in CMake (Phytium, NX...)
|
||||
* Added loongarch64 support (interpretor only)
|
||||
* Added loongarch64 support (interpreter only)
|
||||
* Some fixes to elfloader
|
||||
* Added a mecanism to cancel a Dynarec block construction if it triggers a segfault (instead of a crash)
|
||||
|
||||
@@ -63,7 +173,7 @@ v0.1.4
|
||||
v0.1.2
|
||||
======
|
||||
* OpenSource!
|
||||
* A few more opcode added to the Interpretor and the Dynarec
|
||||
* A few more opcode added to the Interpreter and the Dynarec
|
||||
* Improved Native Function calling
|
||||
* Added some function to limit allocated memory to 47bits space (for Wine)
|
||||
* Improved and Fixed the functions to limit allocated memory to 32bits space
|
||||
@@ -77,7 +187,7 @@ v0.1.0
|
||||
* Some fixes to a few function signature
|
||||
* Improvement to Signal handling, and internal mutex handling
|
||||
* A few fixes to some dynarec opcodes
|
||||
* A few fixes to some interpretor opcodes
|
||||
* A few fixes to some interpreter opcodes
|
||||
|
||||
v0.0.8
|
||||
======
|
||||
|
||||
Executable → Regular
+137
-101
@@ -1,34 +1,88 @@
|
||||
Compiling
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
### Debian-based Linux
|
||||
You can use [@ryanfortner](https://github.com/ryanfortner)'s apt repository to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
sudo wget https://ryanfortner.github.io/box64-debs/box64.list -O /etc/apt/sources.list.d/box64.list
|
||||
wget -qO- https://ryanfortner.github.io/box64-debs/KEY.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/box64-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box64-arm64 -y
|
||||
```
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
----
|
||||
|
||||
### The general approach is:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. ${OPTIONS}
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
- You can use `make -j1`, `make -j2` to prevent running out of memory
|
||||
- You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588.
|
||||
|
||||
#### For Instance, if you want to build box64 for Generic ARM64 Linux platforms, it would look like this:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -D ARM_DYNAREC=ON -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
----
|
||||
|
||||
#### for RK3399
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D RK3399=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for PI4
|
||||
#### for RK3588 / RK3588S
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
-D RK3588=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 3
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
|
||||
If building on the Pi, you will also need a large swap (3 GB+)
|
||||
[optionally reduce GPU memory to a minimum (e.g. 16 MB) using `raspi-config`
|
||||
(and reboot) before starting the build]:
|
||||
|
||||
You can use e.g. '`make -j4`' to speed up the build, but on a Pi 3 with 1GB memory you will likely
|
||||
run out of memory at some point and need to run the build again.
|
||||
Still, this can be faster if your build is attended.
|
||||
|
||||
```
|
||||
-D RPI3ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 4
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
-D RPI4ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
|
||||
#### for Raspberry Pi 5
|
||||
|
||||
If your Raspberry Pi OS use 16K pages use `RPI5ARM64PS16K` instead of `RPI5ARM64`:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D RPI5ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for TEGRA X1
|
||||
@@ -36,48 +90,46 @@ sudo systemctl restart systemd-binfmt
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D TEGRAX1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Snapdragon 845
|
||||
|
||||
#### for ODROID N2/N2+
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DSD845=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D ODROIDN2=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Snapdragon
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
-D SD845=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
-D SD888=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
Depending how recent your Snapdragon is
|
||||
|
||||
----
|
||||
#### for Phytium
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
-D PHYTIUM=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
|
||||
#### for ADLink machines
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D ADLINK=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for M1
|
||||
@@ -85,52 +137,23 @@ sudo systemctl restart systemd-binfmt
|
||||
Only test on Asahi for now, using the default "16K page" kernel
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DM1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
-D M1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
|
||||
#### for Other ARM64 Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### for LoongArch
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DLARCH64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D LARCH64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for RISCV
|
||||
#### for RISC-V
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRV64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D RV64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for PowerPC 64 LE
|
||||
@@ -138,15 +161,7 @@ sudo systemctl restart systemd-binfmt
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DPPC64LE=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D PPC64LE=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for LX2160A
|
||||
@@ -154,24 +169,38 @@ sudo systemctl restart systemd-binfmt
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j$(nproc)
|
||||
sudo make install
|
||||
-D LX2160A=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
|
||||
#### for Termux
|
||||
|
||||
You must have ARM64 Device for build box64.
|
||||
|
||||
##### in CHRoot/PRoot
|
||||
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D ARM64=1 -DCMAKE_C_COMPILER=gcc -DBAD_SIGNAL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
##### in Termux (Native)
|
||||
|
||||
NOTE: BUILDING BOX64 IN TERMUX NATIVE IS EXPERIMENTAL AND DOESN'T GONNA RUN LINUX BINARIES IN NATIVE TERMUX BOX64!!!
|
||||
|
||||
You also needed have `libandroid-sysv-semaphore` and `libandroid-spawn` libraries:
|
||||
|
||||
```
|
||||
-D TERMUX=1 -D -DCMAKE_C_COMPILER=clang CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for x86_64 Linux
|
||||
```
|
||||
-D LD80BITS=1 -D NOALIGN=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
If you encounter some linking errors, try using `NOLOADADDR=ON` (`cmake -D NOLOADADDR=ON; make -j$(nproc)`).
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
----
|
||||
|
||||
If you encounter some linking errors, try using `NOLOADADDR=ON` (`cmake -DNOLOADADDR=ON; make -j$(nproc)`).
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -187,17 +216,24 @@ The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both opti
|
||||
|
||||
#### To have a Trace Enabled build
|
||||
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need to have the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime.
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need to have the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime. Use version v3.2.1, as later version changed the API and will no longer work with box64
|
||||
|
||||
#### To have ARM Dynarec
|
||||
|
||||
Dynarec is only available on ARM (for the meantime), Activate it by using `-DARM_DYNAREC=1`.
|
||||
###### *Note: VFPv3 and NEON are required for Dynarec.*
|
||||
|
||||
#### To have a build using less memory
|
||||
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. It's, for now, only increasing the jumptable from 4 level to 5 levels. The added granularity avoid wasting space, but the 1 level more to the jumptable means there is on read from memory more when jumping between blocks.
|
||||
|
||||
#### 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 (box64 uses git SHA1 to show last commit in version number).
|
||||
|
||||
#### Use faster linker
|
||||
|
||||
You need to add `-DWITH_MOLD=1` if GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
@@ -212,4 +248,4 @@ The tests are very basic and only tests some functionality for now.
|
||||
|
||||
Debian Packaging
|
||||
----
|
||||
Box64 can also be packaged into a .deb file with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`.
|
||||
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you might want in `debian/rules`.
|
||||
-114
@@ -1,114 +0,0 @@
|
||||

|
||||
|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
[View changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/docs/README_CN.md) | [Report an error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64-bit little-endian).
|
||||
|
||||
You can find many Box64 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.
|
||||
|
||||
Since Box64 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/).
|
||||
|
||||
Box64 integrates with DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than using only the interpreter. Some high level information on how DynaRec works can be found [here](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Some x64 internal opcodes use parts of "Realmode X86 Emulator Library", see [x64primop.c](../src/emu/x64primop.c) for copyright details
|
||||
|
||||
<img src="img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box64.
|
||||
|
||||
See [here](USAGE.md) for all the environment variables and what they do.
|
||||
|
||||
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md).
|
||||
|
||||
----
|
||||
|
||||
Version history/Change log
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Notes about 32-bit platforms
|
||||
----
|
||||
|
||||
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bit libraries. Box64 doesn't include any 64-bit <-> 32-bit translation.
|
||||
|
||||
So understand that box64 will only runs 64-bit linux binaries. For 32-bit binaries, you need box86 (with all the multiarch or proot trickery it imply on 64-bit OS).
|
||||
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when the argument is "-m"
|
||||
|
||||
----
|
||||
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not always emulated in a 100% accurate way).
|
||||
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers).
|
||||
So, not all Unity games work and can require a high OpenGL profile, but many actualy work now.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
|
||||
Notes about GTK programs
|
||||
----
|
||||
|
||||
GTK libraries are now wrapped on box64, bu only gtk2, not gtk3 (contrary to box86).
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Note that Steam is a hybrid 32-bit / 64-bit. You NEED box86 to run Steam, as the client app is a 32-bit binary. It also uses a 64-bit local server binaries, but like most stuff using libcef/chromium, it's not working correctly on box64 for now.
|
||||
So, no Steam for now on box64.
|
||||
|
||||
----
|
||||
|
||||
Notes about Wine
|
||||
----
|
||||
|
||||
Wine64 is supported on box64. Proton should also work. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively)
|
||||
|
||||
----
|
||||
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box64 wraps Vulkan libraries, but note that it as only been tested with a RX550 card, some extensions may be missing depending on your graphics card.
|
||||
|
||||
----
|
||||
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box64 development.
|
||||
There are many ways to contribute: code contribution, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, mogery
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000
|
||||
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* For their continous advertisement of box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
And I also thank the many other people who participated even once in this project.
|
||||
|
||||
(If you use Box64 in your project, please don't forget to mention it!)
|
||||
@@ -1,119 +0,0 @@
|
||||
# box64
|
||||
|
||||

|
||||
Linux上用户空间的x86_64应用模拟器
|
||||
|
||||
----
|
||||

|
||||
|
||||
[English](README.md)
|
||||
|
||||
在ARM或其他非X86_64架构的Linux操作系统上,使用Box64可以运行x86_64 Linux程序(例如游戏),请注意,主机系统需要**64位小端**。
|
||||
|
||||
您可以在Youtube的[MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)、[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)或[The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)频道找到更多Box64视频。
|
||||
|
||||
Box64使用了一些“系统”库的原生版本,例如libc、libm、SDL和OpenGL,所以它很容易与大多数应用程序集成和使用,并且在很多情况下性能会出奇的高。点击[此处](https://box86.org/index.php/2021/06/game-performances/)查看示例的基准测试分析。
|
||||
|
||||
Box64为ARM64平台集成了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/)找到。
|
||||
|
||||
注:DynaRec需要针对不同平台编写一部分汇编代码,目前仅支持ARM64。
|
||||
|
||||
一些x64内部操作码使用“Realmode X86 Emulator Library”的部分内容,请参阅[x64primop.c](../src/emu/x64primop.c)了解版权详情
|
||||
|
||||
<img src="img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo和图标由grayduck制作,感谢!
|
||||
|
||||
----
|
||||
|
||||
使用方法
|
||||
----
|
||||
|
||||
若干环境变量可以设置Box64的行为。
|
||||
|
||||
点击[这里](USAGE.md)了解所有的环境变量和它们的作用。
|
||||
|
||||
请注意:Box64的Dynarec提供了一种机制来处理JIT代码,包含内存保护和段错误信号处理程序。简单地说,如果您想用GDB来调试一个使用JIT代码的运行程序(比如mono/Unity3D),您仍然会触发很多“正常”的段错误。建议在GDB中使用类似于`handle SIGSEGV nostop`的东西,不要在每个段错误时都停止,如果您想捕获段错误,可以在`signals.c`中的`my_memprotectionhandler`中放置一个断点。
|
||||
|
||||
----
|
||||
|
||||
编译/安装
|
||||
----
|
||||
> 编译说明可以在[这里](COMPILE.md)查看。
|
||||
|
||||
----
|
||||
|
||||
版本历史
|
||||
----
|
||||
|
||||
版本日志在[这里](CHANGELOG.md)。
|
||||
|
||||
----
|
||||
|
||||
32位平台的注意事项
|
||||
----
|
||||
|
||||
Box64的工作原理是直接将函数调用从x86_64转换到主机系统,主机系统(Box64运行的系统)需要有64位的库。Box64并不包括任何64位<->32位的转换。
|
||||
|
||||
所以请理解,Box64只能运行64位的Linux二进制文件。对于32位的二进制文件,需要Box86(在64位的操作系统上需要所有的multiarch库或一些proot技巧)。
|
||||
|
||||
请注意,许多(基于mojo的)安装程序,即使存在x86_64版本,但在检测到架构为ARM64时会退回到"x86",这时会尝试使用(如果有)box86进行安装。这时你可以使用一个假的"uname",当它的参数为"-m"时返回"x86_64"。
|
||||
|
||||
----
|
||||
|
||||
关于Unity游戏模拟的注意事项
|
||||
----
|
||||
|
||||
当前Unity游戏模拟是一件碰运气的事情。Unity使用Mono(它的信号表示,并不总能100%成功模拟)。
|
||||
|
||||
您还应该注意,一些Unity3D游戏需要OpenGL 3+,目前在ARM SBC(单板计算机)上提供OpenGL 3+是很棘手的。
|
||||
|
||||
所以,并不是所有的Unity游戏都能工作,而且可能需要很高的OpenGL配置,但现在很多游戏都能工作。
|
||||
|
||||
提示:如果游戏开始后在显示任何东西之前退出,在Pi4上使用`MESA_GL_VERSION_OVERRIDE=3.2`,在Panfrost上使用`PAN_MESA_DEBUG=gl3`来使用更高的配置文件。
|
||||
|
||||
----
|
||||
|
||||
关于GTK程序的注意事项
|
||||
----
|
||||
|
||||
GTK 庫現在包裝在 box64 上,但只有 gtk2,而不是 gtk3(與 box86 相反)。
|
||||
|
||||
----
|
||||
|
||||
关于Steam的注意事项
|
||||
----
|
||||
|
||||
Steam并不是32位/64位混合的,而是32位的,因此您需要Box86才能运行Steam。Steam也使用64位的本地服务器程序,但像大多数使用libcef/chromium的程序一样,在box64上暂时无法正常工作。
|
||||
所以:目前在box64上无法运行Steam。
|
||||
----
|
||||
|
||||
关于Wine的注意事项
|
||||
----
|
||||
|
||||
box64支持64位Wine,但请注意,64位的Wine还包含32位的组件,以便能够运行32位的Windws程序。32位程序需要Box86,没有它就不能运行。在Box64和Box86共存的系统上,设置64位Wine可以同时运行32位和64位windows程序(只需分别使用 `wine` 和 `wine64`)。
|
||||
|
||||
----
|
||||
|
||||
关于Vulkan注意事项
|
||||
----
|
||||
|
||||
Box64 包裝 Vulkan 庫。但請注意,它僅使用 RX550 卡進行了測試,根據您的圖形卡,可能會缺少某些擴展。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
----
|
||||
|
||||
我要感谢所有为 box64 开发做出贡献的人。
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, mogery
|
||||
* 财务帮助:FlyingFathead, stormchaser3000
|
||||
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* 硬件捐赠和LoongArch迁移:[xiaoji](https://www.linuxgame.cn)
|
||||
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
(如果你的项目中使用了Box64,请不要忘记提及!)
|
||||
Executable → Regular
+202
-43
@@ -3,145 +3,250 @@ Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64 behaviour.
|
||||
Env. var with * can also be put inside box64rc files.
|
||||
Box64 look for 2 places for rcfile: `/etc/box64.box64rc` and `~/.box64rc`
|
||||
The second takes precedence to the first, on an APP level
|
||||
(that means if an [MYAPP] my appears in both file, only the settings in `~/.box64rc` will be applied)
|
||||
|
||||
#### BOX64_LOG
|
||||
#### BOX64_LOG *
|
||||
Controls the Verbosity level of the logs
|
||||
* 0: NONE : No message (except some fatal error). (Default.)
|
||||
* 1: INFO : Show some minimum log (Example: librairies not found)
|
||||
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
|
||||
* 3: DUMP : All DEBUG plus DUMP of all ELF Info.
|
||||
|
||||
#### BOX64_ROLLING_LOG *
|
||||
Show last few wrapped function call when a Signal is caught
|
||||
* 0: No last function call printed (Default.)
|
||||
* 1: Last 16 wrapped functions calls printed when a signal is printed. Incompatible with BOX64_LOG>1 (may need BOX64_SHOWSEGV=1 also)
|
||||
* N: Last N wrapped functions calls printed when a signal is printed. Incompatible with BOX64_LOG>1 (may need BOX64_SHOWSEGV=1 also)
|
||||
|
||||
#### BOX64_NOBANNER
|
||||
Disables Box64 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX64_LD_LIBRARY_PATH
|
||||
#### BOX64_LD_LIBRARY_PATH *
|
||||
Path to look for x86_64 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/x86_64-linux-gnu` and `/lib/x86_64-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX64_PATH
|
||||
#### BOX64_PATH *
|
||||
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX64_DLSYM_ERROR
|
||||
#### BOX64_DLSYM_ERROR *
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX64_TRACE_FILE
|
||||
#### BOX64_TRACE_FILE *
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box64 instance
|
||||
End the filename with `+` to have thetrace appended instead of overwritten
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX64_TRACE
|
||||
#### BOX64_TRACE *
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
#### BOX64_TRACE_INIT
|
||||
Use BOX64_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
|
||||
#### BOX64_TRACE_INIT *
|
||||
Use BOX64_TRACE_INIT instead of BOX64_TRACE to start trace before the initialisation of libraries and the running program
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
#### BOX64_TRACE_START
|
||||
#### BOX64_TRACE_START *
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX64_TRACE_XMM
|
||||
#### BOX64_TRACE_XMM *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
#### BOX64_TRACE_EMM
|
||||
#### BOX64_TRACE_EMM *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The EMM (i.e. XMM/x87) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 0 : The EMM (i.e. MMX) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the EMM registers.
|
||||
|
||||
#### BOX64_TRACE_COLOR
|
||||
#### BOX64_TRACE_COLOR *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The general registers will always be the default white color. (Default.)
|
||||
* 1 : The general registers will change color in the dumps when they changed value.
|
||||
|
||||
#### BOX64_LOAD_ADDR
|
||||
#### BOX64_LOAD_ADDR *
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX64_NOSIGSEGV
|
||||
#### BOX64_NOSIGSEGV *
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
#### BOX64_NOSIGILL
|
||||
#### BOX64_NOSIGILL *
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX64_SHOWSEGV
|
||||
#### BOX64_SHOWSEGV *
|
||||
Show Segfault signal even if a signal handler is present
|
||||
* 0 : Don"t force show the SIGSEGV analysis (Default.)
|
||||
* 1 : Show SIGSEGV detail, even if a signal handler is present
|
||||
|
||||
#### BOX64_X11THREADS
|
||||
#### BOX64_SHOWBT *
|
||||
Show some Backtrace (Nativ e and Emulated) whgen a signal (SEGV, ILL or BUS) is caught
|
||||
* 0 : Don"t show backtraces (Default.)
|
||||
* 1 : Show Backtrace detail (for native, box64 is rename as the x86_64 binary run)
|
||||
|
||||
#### BOX64_X11THREADS *
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX64_X11GLX
|
||||
#### BOX64_X11GLX *
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_DUMP
|
||||
#### BOX64_DYNAREC_DUMP *
|
||||
Enables/disables Box64's Dynarec's dump.
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
#### BOX64_DYNAREC_LOG
|
||||
#### BOX64_DYNAREC_LOG *
|
||||
Set the level of DynaRec's logs.
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
#### BOX64_DYNAREC
|
||||
#### BOX64_DYNAREC *
|
||||
Enables/Disables Box64's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_TRACE
|
||||
#### BOX64_DYNAREC_TRACE *
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX64_NODYNAREC
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
|
||||
#### BOX64_NODYNAREC *
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpreter)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX64_DYNAREC_BIGBLOCK
|
||||
#### BOX64_DYNAREC_TEST *
|
||||
Dynarec will compare it's execution with the interpreter (super slow, only for testing)
|
||||
* 0 : No comparison
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different
|
||||
|
||||
#### BOX64_DYNAREC_BIGBLOCK *
|
||||
Enables/Disables Box64'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, but only for blocks in elf memory)
|
||||
* 3 : Build Dynarec block bigger (don't stop when block overlaps, for all type of memory)
|
||||
|
||||
#### BOX64_DYNAREC_STRONGMEM
|
||||
#### BOX64_DYNAREC_FORWARD *
|
||||
Define Box64's Dynarec max allowed forward value when building Block.
|
||||
* 0 : No forward value. When current block end, don't try to go further even if there are previous forward jumps
|
||||
* XXX : Allow up to XXXX bytes of gap when building a Block after the block end to next forward jump (Default: 128)
|
||||
|
||||
#### BOX64_DYNAREC_STRONGMEM *
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
* 1 : Enable some Memory Barrier when writting to memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : All 1. plus a memory barrier on every write to memory using MOV
|
||||
* 3 : All 2. plus Memory Barrier when reading from memory and on some SSE/SSE2 opcodes too
|
||||
|
||||
#### BOX64_DYNAREC_X87DOUBLE
|
||||
#### BOX64_DYNAREC_X87DOUBLE *
|
||||
Force the use of Double for x87 emulation
|
||||
* 0 : Try to use float when possible for x87 emulation (faster)
|
||||
* 0 : Try to use float when possible for x87 emulation (default, faster)
|
||||
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis)
|
||||
|
||||
#### BOX64_DYNAREC_FASTNAN
|
||||
#### BOX64_DYNAREC_FASTNAN *
|
||||
Enable/Disable generation of -NAN
|
||||
* 0 : Generate -NAN like on x86 (Default.)
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (was default before this option exsted)
|
||||
* 0 : Generate -NAN like on x86
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (default, faster)
|
||||
|
||||
#### BOX64_LIBGL
|
||||
#### BOX64_DYNAREC_FASTROUND *
|
||||
Enable/Disable generation of precise x86 rounding
|
||||
* 0 : Generate float/double -> int rounding like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion) (default, faster)
|
||||
|
||||
#### BOX64_DYNAREC_SAFEFLAGS *
|
||||
Handling of flags on CALL/RET opcodes
|
||||
* 0 : Treat CALL/RET as if it never needs any flags (faster but not advised)
|
||||
* 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)
|
||||
|
||||
#### BOX64_DYNAREC_CALLRET *
|
||||
Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
* 0 : Don't optimize CALL/RET, use Jump Table for boths
|
||||
* 1 : Try to optimized CALL/RET, skipping the use of the JumpTable when possible (Default)
|
||||
|
||||
#### BOX64_DYNAREC_HOTPAGE *
|
||||
Handling of HotPage (Page being both executed and written)
|
||||
* 0 : Don't track hotpage (Default)
|
||||
* 1-255 : Track HotPage, and disable execution of a page being written for N attempts
|
||||
|
||||
#### BOX64_DYNAREC_FASTPAGE *
|
||||
Will use a faster handling of HotPage (Page being both executed and written)
|
||||
* 0 : use regular hotpage (Default)
|
||||
* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash)
|
||||
|
||||
#### BOX64_DYNAREC_ALIGNED_ATOMICS *
|
||||
Generated code for aligned atomics only
|
||||
* 0 : The code generated can handle unaligned atomics (Default)
|
||||
* 1 : Generated code only for aligned atomics (faster and less code generated, but will SEGBUS if LOCK prefix is unsed on unaligned data)
|
||||
|
||||
#### BOX64_DYNAREC_BLEEDING_EDGE *
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
* 0 : Don't detect MonoBleedingEdge
|
||||
* 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX64_DYNAREC_JVM *
|
||||
Detect libjvm and apply conservative settings
|
||||
* 0 : Don't detect libjvm
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX64_DYNAREC_WAIT *
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
#### BOX64_DYNAREC_MISSING *
|
||||
Dynarec print the missing opcodes
|
||||
* 0 : not print the missing opcode (Default, unless DYNAREC_LOG>=1 or DYNAREC_DUMP>=1 is used)
|
||||
* 1 : Will print the missing opcodes
|
||||
|
||||
#### BOX64_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
* 0 : Just track the flag (Default)
|
||||
* 1 : Direct apply of SSE Flush to 0 flag
|
||||
|
||||
#### BOX64_X87_NO80BITS *
|
||||
Handling of x87 80bits long double
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
#### BOX64_SYNC_ROUNDING *
|
||||
Box64 will sync rounding mode with fesetround/fegetround.
|
||||
* 0 : Disable rounding mode syncing. (Default.)
|
||||
* 1 : Enable rounding mode syncing.
|
||||
|
||||
#### BOX64_LIBCEF *
|
||||
Detect libcef and apply malloc_hack settings
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
#### BOX64_SDL2_JGUID *
|
||||
Need a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2
|
||||
* 0 : Don't use any workaround
|
||||
* 1 : Use a workaround for program that use the private SDL_GetJoystickGUIDInfo function with 1 missing argument
|
||||
|
||||
#### BOX64_LIBGL *
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
@@ -150,42 +255,75 @@ Enable/Disable generation of -NAN
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX64_EMULATED_LIBS
|
||||
#### BOX64_EMULATED_LIBS *
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX64_ALLOWMISSINGLIBS
|
||||
#### BOX64_ALLOWMISSINGLIBS *
|
||||
Allow Box64 to continue even if a library is missing.
|
||||
* 0 : Box64 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.
|
||||
|
||||
#### BOX64_PREFER_WRAPPED
|
||||
#### BOX64_PREFER_WRAPPED *
|
||||
Box64 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
|
||||
|
||||
#### BOX64_PREFER_EMULATED
|
||||
#### BOX64_PREFER_EMULATED *
|
||||
Box64 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)
|
||||
|
||||
#### BOX64_NOPULSE
|
||||
#### BOX64_CRASHHANDLER *
|
||||
Box64 will use a dummy crashhandler.so library
|
||||
* 0 : Use Emulated crashhandler.so library if needed
|
||||
* 1 : Use an internal dummy (completly empty) crashhandler.so library (defaut)
|
||||
|
||||
#### BOX64_MALLOC_HACK *
|
||||
How Box64 will handle hooking of malloc operators
|
||||
* 0 : Don't allow malloc operator to be redirected, rewriting code to use regular function (Default)
|
||||
* 1 : Allow malloc operator to be redirected (not advised)
|
||||
* 2 : Like 0, but track special mmap / free (some redirected functions were inlined and cannot be redirected)
|
||||
|
||||
#### BOX64_NOPULSE *
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
|
||||
|
||||
#### BOX64_NOGTK
|
||||
#### BOX64_NOGTK *
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
#### BOX64_NOVULKAN
|
||||
#### BOX64_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.)
|
||||
|
||||
#### BOX64_JITGDB
|
||||
#### BOX64_FUTEX_WAITV *
|
||||
Use of the new fuext_waitc syscall
|
||||
* 0 : Do not try to use it, return unsupported (Default for BAD_SIGNAL build)
|
||||
* 1 : let program use the syscall if the host system support it (Default for other build)
|
||||
|
||||
#### BOX64_BASH *
|
||||
Define x86_64 bash to launch script
|
||||
* yyyy
|
||||
Will use yyyy as x86_64 bash to launch script. yyyy needs to be a full path to a valid x86_64 version of bash
|
||||
|
||||
#### BOX64_ENV *
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var.
|
||||
|
||||
#### BOX64_ENV1
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
#### BOX64_RESERVE_HIGH
|
||||
* 0 : Don't try to pe-reserve high memory (beyond 47bits) (Default)
|
||||
* 1 : Try to reserve (without allocating it) memory beyond 47bits (seems unstable)
|
||||
|
||||
#### BOX64_JITGDB *
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack)
|
||||
@@ -195,3 +333,24 @@ Disables the load of vulkan libraries.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
* 3 : Launch `lldb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
|
||||
#### BOX64_NORCFILES
|
||||
If the env var exist, no rc files (like /etc/box64.box64rc and ~/.box64rc) will be loaded
|
||||
|
||||
----
|
||||
|
||||
Those variables are only valid inside a rcfile:
|
||||
----
|
||||
|
||||
#### BOX64_NOSANDBOX
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "--no-sandbox" to command line arguments (usefull for chrome based programs)
|
||||
|
||||
#### BOX64_INPROCESSGPU
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "--in-process-gpu" to command line arguments (usefull for chrome based programs)
|
||||
|
||||
#### BOX64_EXIT
|
||||
* 0 : Nothing special
|
||||
* 1 : Just exit, don't try to run the program
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
# Installing Wine64
|
||||
Running Wine64/Wine with Box64/Box86 allows x64/x86 Windows programs to run on 64-bit ARM Linux devices.
|
||||
- Box64 needs `wine-amd64` to be installed **manually** on ARM64 (aarch64) devices. This will run 64-bit Windows programs (aka x86_64).
|
||||
- Box86 needs `wine-i386` to be installed **manually** on ARM32 (armhf) devices (or on ARM64 with multiarch or chroot). This will run 32-bit Windows programs (aka x86).
|
||||
- _Note that `wine:arm64` and `wine:armhf` will not work with Box64/Box86. Your device's package manager might try to install those if you ask it to install wine._
|
||||
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
## Overview
|
||||
The general procedure for installing Wine64 & Wine for Box64 & Box86 is to...
|
||||
- Download all the install 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 (often `~/wine/` by default)
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries.
|
||||
- Boot wine to create a new wineprefix.
|
||||
- Download winetricks (which is just a complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
|
||||
## Examples
|
||||
### Installing Wine64 & Wine for Box64 & Box86 on Raspberry Pi OS from WineHQ .deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/)_
|
||||
|
||||
This install method allows you to install different versions of Wine64/Wine. You may install any version/branch of Wine that you wish.
|
||||
```
|
||||
# NOTE: Can only run on aarch64 (since box64 can only run on aarch64)
|
||||
# box64 runs wine-amd64, box86 runs wine-i386.
|
||||
|
||||
### User-defined Wine version variables ################
|
||||
# - Replace the variables below with your system's info.
|
||||
# - Note that we need the amd64 version for Box64 even though we're installing it on our ARM processor.
|
||||
# - 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/
|
||||
|
||||
local branch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386)
|
||||
local version="7.1" #example: "7.1"
|
||||
local id="debian" #example: debian, ubuntu
|
||||
local dist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, ${VERSION_CODENAME}, etc
|
||||
local tag="-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 any old wine-mono/wine-gecko install files
|
||||
rm -rf ~/.local/share/applications/wine # remove any old program shortcuts
|
||||
|
||||
# Backup any old wine installs
|
||||
rm -rf ~/wine-old 2>/dev/null; mv ~/wine ~/wine-old 2>/dev/null
|
||||
rm -rf ~/.wine-old 2>/dev/null; mv ~/.wine ~/.wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wine64 /usr/local/bin/wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old 2>/dev/null
|
||||
|
||||
# Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
LNKA="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-amd64/" #amd64-wine links
|
||||
DEB_A1="wine-${branch}-amd64_${version}~${dist}${tag}_amd64.deb" #wine64 main bin
|
||||
DEB_A2="wine-${branch}_${version}~${dist}${tag}_amd64.deb" #wine64 support files (required for wine64 / can work alongside wine_i386 main bin)
|
||||
#DEB_A3="winehq-${branch}_${version}~${dist}${tag}_amd64.deb" #shortcuts & docs
|
||||
LNKB="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-i386/" #i386-wine links
|
||||
DEB_B1="wine-${branch}-i386_${version}~${dist}${tag}_i386.deb" #wine_i386 main bin
|
||||
DEB_B2="wine-${branch}_${version}~${dist}${tag}_i386.deb" #wine_i386 support files (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
|
||||
#DEB_B3="winehq-${branch}_${version}~${dist}${tag}_i386.deb" #shortcuts & docs
|
||||
|
||||
# Install amd64-wine (64-bit) alongside i386-wine (32-bit)
|
||||
echo -e "Downloading wine . . ."
|
||||
wget -q ${LNKA}${DEB_A1}
|
||||
wget -q ${LNKA}${DEB_A2}
|
||||
wget -q ${LNKB}${DEB_B1}
|
||||
echo -e "Extracting wine . . ."
|
||||
dpkg-deb -x ${DEB_A1} wine-installer
|
||||
dpkg-deb -x ${DEB_A2} wine-installer
|
||||
dpkg-deb -x ${DEB_B1} wine-installer
|
||||
echo -e "Installing wine . . ."
|
||||
mv wine-installer/opt/wine* ~/wine
|
||||
|
||||
# Download wine dependencies
|
||||
# - these packages are needed for running box86/wine-i386 on a 64-bit RPiOS via multiarch
|
||||
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.
|
||||
|
||||
# - these packages are needed for running box64/wine-amd64 on RPiOS (box64 only runs on 64-bit OS's)
|
||||
sudo apt-get install -y libasound2:arm64 libc6:arm64 libglib2.0-0:arm64 libgphoto2-6:arm64 libgphoto2-port12:arm64 \
|
||||
libgstreamer-plugins-base1.0-0:arm64 libgstreamer1.0-0:arm64 libldap-2.4-2:arm64 libopenal1:arm64 libpcap0.8:arm64 \
|
||||
libpulse0:arm64 libsane1:arm64 libudev1:arm64 libunwind8:arm64 libusb-1.0-0:arm64 libvkd3d1:arm64 libx11-6:arm64 libxext6:arm64 \
|
||||
ocl-icd-libopencl1:arm64 libasound2-plugins:arm64 libncurses6:arm64 libncurses5:arm64 libcups2:arm64 \
|
||||
libdbus-1-3:arm64 libfontconfig1:arm64 libfreetype6:arm64 libglu1-mesa:arm64 libgnutls30:arm64 \
|
||||
libgssapi-krb5-2:arm64 libjpeg62-turbo:arm64 libkrb5-3:arm64 libodbc1:arm64 libosmesa6:arm64 libsdl2-2.0-0:arm64 libv4l-0:arm64 \
|
||||
libxcomposite1:arm64 libxcursor1:arm64 libxfixes3:arm64 libxi6:arm64 libxinerama1:arm64 libxrandr2:arm64 \
|
||||
libxrender1:arm64 libxxf86vm1:arm64 libc6:arm64 libcap2-bin:arm64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel_7.1~bullseye-1_amd64.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel-amd64_7.1~bullseye-1_amd64.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:arm64` to packages in dep list, then try installing them on Pi aarch64.
|
||||
|
||||
# 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
|
||||
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
|
||||
sudo cp -TRv libfaudio/usr/ /usr/
|
||||
rm libfaudio0_*~bpo10+1_i386.deb # clean up
|
||||
rm -rf libfaudio # clean up
|
||||
|
||||
# Install symlinks
|
||||
sudo ln -s ~/wine/bin/wine /usr/local/bin/wine
|
||||
sudo ln -s ~/wine/bin/wine64 /usr/local/bin/wine64
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wine64 /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
```
|
||||
|
||||
## Installing winetricks
|
||||
Winetricks is a bash script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs. You can either install it with `apt`, or manually using the steps below.
|
||||
|
||||
```
|
||||
sudo apt-get install cabextract -y # winetricks needs this installed
|
||||
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old # Backup old winetricks
|
||||
cd ~/Downloads && wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks # Download
|
||||
sudo chmod +x winetricks && sudo mv winetricks /usr/local/bin/ # Install
|
||||
```
|
||||
|
||||
Whenever we run winetricks, we must tell Box86 to supress its info banner, otherwise winetricks will crash. Box86's info banner can be suppressed using the `BOX86_NOBANNER=1` environment variable before invoking winetricks (example: `BOX86_NOBANNER=1 winetricks`).
|
||||
|
||||
If `apt` installed a desktop menu shortcut for winetricks (or if you make your own desktop shortcut for winetricks) then you may need to edit that shortcut to include Box86's BOX86_NOBANNER=1 env var. With your favorite text editor, edit `/usr/share/applications/winetricks.desktop` and change `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`.
|
||||
|
||||
## Example commands
|
||||
Creating a 64-bit wineprefix:
|
||||
`wine64 wineboot` or `wine wineboot` (wineprefix is created in `~/.wine/`)
|
||||
`WINEPREFIX="$HOME/prefix64" wine wineboot` (wineprefix is created in `~/prefix64/`) _Note: You will need to invoke `WINEPREFIX="$HOME/prefix64"` before every command to use this wineprefix._
|
||||
|
||||
Creating a 32-bit wineprefix:
|
||||
`WINEARCH=win32 wine wineboot` (wineprefix is created in `~/.wine/`)
|
||||
|
||||
Fore-quitting wine:
|
||||
`wineserver -k`
|
||||
|
||||
Running Wine Configuration:
|
||||
`winecfg`
|
||||
|
||||
Using winetricks:
|
||||
`winetricks -q corefonts vcrun2010 dotnet20sp1`
|
||||
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
|
||||
|
||||
Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will cause winetricks to crash.
|
||||
|
||||
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
|
||||
|
||||
## Other notes
|
||||
|
||||
### Wineprefixes (and Wine initialization)
|
||||
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable. For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
|
||||
|
||||
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
|
||||
|
||||
### Transplanting wineprefixes
|
||||
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
|
||||
|
||||
### Swapping out different versions of Wine
|
||||
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
|
||||
|
||||
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
|
||||
|
||||
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will migrate a wineprefix from an older version of Wine to be usable by the newer version of Wine you just installed. You can check which version of Wine you're running with the `wine --version` command.
|
||||
+484
@@ -0,0 +1,484 @@
|
||||
=head1 NAME
|
||||
|
||||
box64 - Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<box64> [B<--help>] [B<--version>] I<executable>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<Box64> lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux
|
||||
systems, like ARM (host system needs to be 64-bit little-endian). Since B<Box64>
|
||||
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. B<Box64> integrates with DynaRec (dynamic
|
||||
recompiler) for the ARM64 platform, providing a speed boost between 5 to 10
|
||||
times faster than using only the interpreter.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<-h,--help>
|
||||
|
||||
Print box64 help and quit.
|
||||
|
||||
=item B<-v,--version>
|
||||
|
||||
Print box64 version and quit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 CONFIGURATION FILE
|
||||
|
||||
B<Box64> now have configurations files. There are 2 files loaded.
|
||||
F</etc/box4.box64rc> and F<~/.box64rc>. Both files have the same syntax, and is
|
||||
basically an ini files. Section in square brackets define the process name, and
|
||||
the rest is the environment variable. B<Box64> comes with a default file that
|
||||
should be installed for better stability. Note that the priority is:
|
||||
F<~/.bashrc> > F</etc/box64.box64rc> > command line So, your settings in
|
||||
F<~/.bashrc> may override the setting from your command line. Example:
|
||||
|
||||
[factorio]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
BOX64_DYNAREC_BIGBLOCK=2
|
||||
BOX64_DYNAREC_FORWARD=1024
|
||||
BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
=head1 VARIABLES FOR RCFILE ONLY
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<BOX64_NOSANDBOX=0|1>
|
||||
|
||||
When set to 1, add C<--no-sandbox> to command line arguments (useful for chrome
|
||||
based programs).
|
||||
|
||||
=item B<BOX64_INPROCESSGPU=0|1>
|
||||
|
||||
When set to 1, add C<--in-process-gpu> to command line arguments (useful for chrome
|
||||
based programs).
|
||||
|
||||
=item B<BOX64_EXIT>=I<0|1>
|
||||
|
||||
When set to 1, just exit, don't try to run the program.
|
||||
|
||||
=back
|
||||
|
||||
=head1 VARIABLES ONLY FOR ENVIRONMENT AND NOT RCFILE
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<BOX64_NOBANNER>=I<0|1>
|
||||
|
||||
When set to 1, don't prints the banner including version and build.
|
||||
|
||||
=item B<BOX64_LD_PRELOAD>=I<lib1>[:I<lib2>:...]
|
||||
|
||||
Force loading libraries with the binary. PreLoaded libs can be emulated or
|
||||
native, and are treated the same way as if they were comming from the binary.
|
||||
|
||||
=item B<BOX64_ENV>=I<env=val>
|
||||
|
||||
Add an variable with value to the environment.
|
||||
|
||||
=item B<BOX64_ENV1>=I<env=val> B<BOX64_ENV2>=I<env=val> ...
|
||||
|
||||
Add arbitrary many variables using B<BOX64_ENV1>, B<BOX64_ENV2>, ...
|
||||
|
||||
=item B<BOX64_NORCFILES>
|
||||
|
||||
No rc files (like F</etc/box64.box64rc> and F<~/.box64rc>) will be loaded.
|
||||
|
||||
=back
|
||||
|
||||
=head1 VARIABLES FOR BOTH ENVIRONMENT AND RCFILE
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<BOX64_LOG>=I<0|NONE|1|INFO|2|DEBUG|3|DUMP>
|
||||
|
||||
Controls the Verbosity level of the logs
|
||||
|
||||
* 0 or NONE : No message (except some fatal error). (Default.)
|
||||
* 1 or INFO : Show some minimum log (Example: libraries not found)
|
||||
* 2 or DEBUG : Details a lot of stuff (Example: relocations or functions called).
|
||||
* 3 or DUMP : All DEBUG plus DUMP of all ELF Info.
|
||||
|
||||
=item B<BOX64_ROLLING_LOG>=I<0|1|N>
|
||||
|
||||
Show last few wrapped function call when a Signal is caught. Incompatible with
|
||||
B<BOX64_LOG> > 1 (may need B<BOX64_SHOWSEGV=1> also)
|
||||
|
||||
* 0: No last function call printed (Default.)
|
||||
* 1: Last 16 wrapped functions calls printed when a signal is printed.
|
||||
* N: Last N wrapped functions calls printed when a signal is printed.
|
||||
|
||||
=item B<BOX64_LD_LIBRARY_PATH>=I</path/to/libs>
|
||||
|
||||
Path to look for x86_64 libraries. Default is current folder and C<lib> in
|
||||
current folder. Also, F</usr/lib/x86_64-linux-gnu> and
|
||||
F</lib/x86_64-linux-gnu> are added if they exist.
|
||||
|
||||
=item B<BOX64_PATH>=I</path/to/bins>
|
||||
|
||||
Path to look for x86_64 executable. Default is current folder and C<bin> in
|
||||
current folder.
|
||||
|
||||
=item B<BOX64_DLSYM_ERROR>=I<0|1>
|
||||
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
=item B<BOX64_TRACE_FILE>=I</path/to/file>
|
||||
|
||||
Send all log and trace to a file instead of C<stdout>. Also, if name contains
|
||||
C<%pid> then this is replaced by the actual C<PID> of B<box64> instance. End
|
||||
the filename with `+` to have thetrace appended instead of overwritten Use
|
||||
C<stderr> to use this instead of default C<stdout>.
|
||||
|
||||
=item B<BOX64_TRACE>=I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
|
||||
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
=item B<BOX64_TRACE_INIT>=I<0|1>
|
||||
|
||||
Use B<BOX64_TRACE_INIT> instead of B<BOX64_TRACE> to start trace before the
|
||||
initialization of libraries and the running program
|
||||
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
=item B<BOX64_TRACE_START>=I<NNNNNNN>
|
||||
|
||||
Only on builds with trace enabled. Start trace only after I<NNNNNNNN> opcode
|
||||
execute (number is an `uint64_t`).
|
||||
|
||||
=item B<BOX64_TRACE_XMM>=I<0|1>
|
||||
|
||||
Only on builds with trace enabled.
|
||||
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
=item B<BOX64_TRACE_EMM>=I<0|1>
|
||||
|
||||
Only on builds with trace enabled.
|
||||
|
||||
* 0 : The EMM (i.e. MMX) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the EMM registers.
|
||||
|
||||
=item B<BOX64_TRACE_COLOR>=I<0|1>
|
||||
|
||||
Only on builds with trace enabled.
|
||||
|
||||
* 0 : The general registers will always be the default white color. (Default.)
|
||||
* 1 : The general registers will change color in the dumps when they changed value.
|
||||
|
||||
=item B<BOX64_LOAD_ADDR>=I<0xXXXXXXXX>
|
||||
|
||||
Try to load at C<0xXXXXXX> main binary (if binary is a PIE).
|
||||
|
||||
=item B<BOX64_NOSIGSEGV>=I<0|1>
|
||||
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
=item B<BOX64_NOSIGILL>=I<0|1>
|
||||
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
=item B<BOX64_SHOWSEGV>=I<0|1>
|
||||
|
||||
Show Segfault signal even if a signal handler is present
|
||||
|
||||
* 0 : Don"t force show the SIGSEGV analysis (Default.)
|
||||
* 1 : Show SIGSEGV detail, even if a signal handler is present
|
||||
|
||||
=item B<BOX64_SHOWBT>=I<0|1>
|
||||
|
||||
Show some Backtrace (Nativ e and Emulated) whgen a signal (SEGV, ILL or BUS) is caught
|
||||
|
||||
* 0 : Don"t show backtraces (Default.)
|
||||
* 1 : Show Backtrace detail (for native, box64 is rename as the x86_64 binary run)
|
||||
|
||||
=item B<BOX64_X11THREADS>=I<0|1>
|
||||
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
=item B<BOX64_X11GLX>=I<0|1>
|
||||
|
||||
Force libX11's GLX extension to be present.
|
||||
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP>=I<0|1|2>
|
||||
|
||||
Enables/disables Box64's Dynarec's dump.
|
||||
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
=item B<BOX64_DYNAREC_LOG>=I<0|1|2|3>
|
||||
|
||||
Set the level of DynaRec's logs.
|
||||
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
=item B<BOX64_DYNAREC>=I<0|1>
|
||||
|
||||
Enables/Disables Box64's Dynarec.
|
||||
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
=item B<BOX64_DYNAREC_TRACE>=I<0|1>
|
||||
|
||||
Enables/Disables trace for generated code. Like regular Trace, this will slow
|
||||
down the program a lot and generate huge logs.
|
||||
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code
|
||||
|
||||
=item B<BOX64_NODYNAREC>=I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging
|
||||
behaviour difference between Dynarec and Interpretor)
|
||||
|
||||
=item B<BOX64_DYNAREC_TEST>=I<0|1>
|
||||
|
||||
Enables/Disables test for generated code. This will run interpreter along the Dynacrec, so this will slow
|
||||
down the program a lot.
|
||||
|
||||
* 0 : No test for generated code. (Default.)
|
||||
* 1 : Enable Tests for generated code
|
||||
|
||||
=item B<BOX64_DYNAREC_BIGBLOCK>=I<0|1|2|3>
|
||||
|
||||
Enables/Disables Box64'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, but only for blocks in elf memory)
|
||||
* 3 : Build Dynarec block bigger (don't stop when block overlaps, for all type of memory)
|
||||
|
||||
=item B<BOX64_DYNAREC_FORWARD>=I<0|XXX>
|
||||
|
||||
Define Box64's Dynarec max allowed forward value when building Block.
|
||||
|
||||
* 0 : No forward value. When current block end, don't try to go further even if there are previous forward jumps
|
||||
* XXX : Allow up to XXXX bytes of gap when building a Block after the block end to next forward jump (Default: 128)
|
||||
|
||||
=item B<BOX64_DYNAREC_STRONGMEM>=I<0|1|2>
|
||||
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
|
||||
=item B<BOX64_DYNAREC_X87DOUBLE>=I<0|1>
|
||||
|
||||
Force the use of Double for x87 emulation
|
||||
|
||||
* 0 : Try to use float when possible for x87 emulation (default, faster)
|
||||
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis)
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTNAN>=I<0|1>
|
||||
|
||||
Enable/Disable generation of -NAN
|
||||
|
||||
* 0 : Generate -NAN like on x86
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (default, faster)
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTROUND>=I<0|1>
|
||||
|
||||
Enable/Disable generation of precise x86 rounding
|
||||
|
||||
* 0 : Generate float/double -> int rounding like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion) (default, faster)
|
||||
|
||||
=item B<BOX64_DYNAREC_SAFEFLAGS>=I<0|1|2>
|
||||
|
||||
Handling of flags on CALL/RET opcodes
|
||||
|
||||
* 0 : Treat CALL/RET as if it never needs any flags (faster but not advised)
|
||||
* 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)
|
||||
|
||||
=item B<BOX64_DYNAREC_CALLRET>=I<0|1>
|
||||
|
||||
Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
|
||||
* 0 : Don't optimize CALL/RET, use Jump Table for boths (Default)
|
||||
* 1 : Try to optimized CALL/RET, skipping the use of the JumpTable when possible (will crash if blacks are invalidate, so probably incompatible with JIT/Dynarec)
|
||||
|
||||
=item B<BOX64_DYNAREC_HOTPAGE>=I<0|1-255>
|
||||
|
||||
Handling of HotPage (Page beeing both executed and writen)
|
||||
|
||||
* 0 : Don't track hotpage
|
||||
* 1-255 : Track HotPage, and disable execution of a page beeing writen for N attempts (default is 4)
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTPAGE>=I<0|1>
|
||||
|
||||
Will use a faster handling of HotPage (Page beeing both executed and writen)
|
||||
|
||||
* 0 : use regular hotpage (Default)
|
||||
* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash)
|
||||
|
||||
=item B<BOX64_DYNAREC_BLEEDING_EDGE>=I<0|1>
|
||||
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
|
||||
* 0 : Don't detect MonoBleedingEdge
|
||||
* 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
=item B<BOX64_DYNAREC_WAIT>=I<0|1>
|
||||
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
=item B<BOX64_SSE_FLUSHTO0>=I<0|1>
|
||||
|
||||
Handling of SSE Flush to 0 flags
|
||||
|
||||
* 0 : Just track the flag (Default)
|
||||
* 1 : Direct apply of SSE Flush to 0 flag
|
||||
|
||||
=item B<BOX64_X87_NO80BITS>=I<0|1>
|
||||
|
||||
Handling of x87 80bits long double
|
||||
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
=item B<BOX64_SYNC_ROUNDING>=I<0|1>
|
||||
|
||||
Box64 will sync rounding mode with fesetround/fegetround.
|
||||
|
||||
* 0 : Disable rounding mode syncing. (Default.)
|
||||
* 1 : Enable rounding mode syncing.
|
||||
|
||||
=item B<BOX64_LIBCEF>=I<0|1>
|
||||
|
||||
Detect libcef and apply malloc_hack settings
|
||||
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
=item B<BOX64_LIBGL>=I<libXXXX|/PATH/TO/libGLXXX>
|
||||
|
||||
You can also use B<SDL_VIDEO_GL_DRIVER>
|
||||
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
|
||||
=item B<BOX64_EMULATED_LIBS>=I<XXXX[:YYYY:...]>
|
||||
|
||||
Force lib XXXX (and YYYY...) to be emulated (and not wrapped) Some games uses
|
||||
an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is
|
||||
automatical added to emulated libs, and same for Don't Starve (and Together /
|
||||
Server variant) that use an old SDL2 too
|
||||
|
||||
=item B<BOX64_ALLOWMISSINGLIBS>=I<0|1>
|
||||
|
||||
Allow Box64 to continue even if a library is missing.
|
||||
|
||||
* 0 : Box64 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.
|
||||
|
||||
=item B<BOX64_PREFER_WRAPPED>=I<0|1>
|
||||
|
||||
Box64 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
|
||||
|
||||
=item B<BOX64_PREFER_EMULATED>=I<0|1>
|
||||
|
||||
Box64 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)
|
||||
|
||||
=item B<BOX64_CRASHHANDLER>=I<0|1>
|
||||
|
||||
Box64 will use a dummy crashhandler.so library
|
||||
|
||||
* 0 : Use Emulated crashhandler.so library if needed
|
||||
* 1 : Use an internal dummy (completly empty) crashhandler.so library (defaut)
|
||||
|
||||
=item B<BOX64_MALLOC_HACK>=I<0|1|2>
|
||||
|
||||
How Box64 will handle hooking of malloc operators
|
||||
|
||||
* 0 : Don't allow malloc operator to be redirected, rewriting code to use regular function (Default)
|
||||
* 1 : Allow malloc operator to be redirected (not advised)
|
||||
* 2 : Like 0, but track special mmap / free (some redirected functions were inlined and cannot be redirected)
|
||||
|
||||
=item B<BOX64_NOPULSE>=I<0|1>
|
||||
|
||||
Disables the load of pulseaudio libraries.
|
||||
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
|
||||
|
||||
=item B<BOX64_NOGTK>=I<0|1>
|
||||
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
=item B<BOX64_NOVULKAN>=I<0|1>
|
||||
|
||||
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.)
|
||||
|
||||
=item B<BOX64_FUTEX_WAITV>=I<0|1>
|
||||
|
||||
Use of the new fuext_waitc syscall
|
||||
|
||||
* 0 : Do not try to use it, return unsupported (default for BAD_SIGNAL build)
|
||||
* 1 : let program use the syscall if the host system support it (Default for other build)
|
||||
|
||||
=item B<BOX64_BASH>=I<yyyy>
|
||||
|
||||
Define x86_64 bash to launch script. Will use yyyy as x86_64 bash to launch
|
||||
script. yyyy needs to be a full path to a valid x86_64 version of bash
|
||||
|
||||
=item B<BOX64_JITGDB>=I<0|1|2>
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting. When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack) then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then simply `set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`. This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
|
||||
=cut
|
||||
Executable → Regular
File mode changed.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Executable → Regular
File mode changed.
|
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 180 KiB |
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-arm64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}"
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
cd "${srcdir}/${pkgname%-arm64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
cd "${srcdir}/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-arm64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-asahi-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-asahi-git}-git" "${pkgname%-asahi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-asahi-git}-git" "${pkgname%-asahi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-asahi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-asahi-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DM1=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-asahi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-asahi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-lx2160a-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}"
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-lx2160a-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2160a-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-odroid-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DODROIDN2=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-phytium-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-phytium-git}-git" "${pkgname%-phytium-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-phytium-git}-git" "${pkgname%-phytium-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPHYTIUM=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
# Check for Pi version number
|
||||
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
|
||||
_piversion=4
|
||||
elif [[ ${_pimodel} =~ "Raspberry Pi 3" ]]; then
|
||||
_piversion=3
|
||||
else
|
||||
# This RPI is not supported or this device is not a pi.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3 (2/1/0 isn't supported).\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRPI${_piversion}ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3xxx-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
_rkmodel=`tr -d '\0' < /proc/device-tree/compatible`
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}"
|
||||
# Check for RockChip version number
|
||||
if [[ ${_rkmodel} =~ "rk3326" ]]; then
|
||||
_rksuffix=3326
|
||||
elif [[ ${_rkmodel} =~ "rk3399" ]]; then
|
||||
_rksuffix=3399
|
||||
elif [[ ${_rkmodel} =~ "rk3588" ]]; then
|
||||
_rksuffix=3588
|
||||
else
|
||||
# This RKxxxx is not supported or this device is not RockChip based.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RockChip model 3326/3399/3588.\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected RockChip verion number is: \033[01;31m${_rksuffix}\033[01m.\033[00m"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRK${_rksuffix}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rv64-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('riscv64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rv64-git}-git" "${pkgname%-rv64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rv64-git}-git" "${pkgname%-rv64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-rv64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rv64-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRV64=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-rv64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-rv64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-sd845-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DSD845=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-tegra-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}"
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
cd "${srcdir}/${pkgname%-tegra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
cd "${srcdir}/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-tegra-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-x64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
arch=('x86_64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
@@ -14,30 +14,22 @@ source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x64-git}"
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
cd "${srcdir}/${pkgname%-x64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
cd "${srcdir}/${pkgname%-x64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-x64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box64"
|
||||
license=('MIT')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box64')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x64-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=Debug
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-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
|
||||
}
|
||||
+3
-1
@@ -4,6 +4,8 @@
|
||||
Just download the `PKGBUILD-<your-platform>` (no need to download the whole repository), go to directory where you downloaded and type:
|
||||
```sh
|
||||
mv ./PKGBUILD-<your-platform> ./PKGBUILD
|
||||
# use the below line if you need a DEBUG build
|
||||
# sed -i 's/RelWithDebInfo/Debug/g' ./PKGBUILD
|
||||
cd ..
|
||||
makepkg -si
|
||||
```
|
||||
@@ -12,7 +14,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](../docs/COMPILE.md).
|
||||
All specified in [COMPILE.md](../docs/COMPILE.md) except for LARCH64, PPC64LE and SW64.
|
||||
|
||||
### 3. Any advantages with this solution?
|
||||
This might give you some advantages like:
|
||||
|
||||
+283
-121
@@ -145,10 +145,20 @@ wrappedtestundefs.h:
|
||||
|
||||
# TODO: Add /.F.*A/ automatic generation (and suppression)
|
||||
|
||||
class FunctionConvention(object):
|
||||
def __init__(self, ident: str, convname: str, valid_chars: List[str]) -> None:
|
||||
self.ident = ident
|
||||
self.name = convname
|
||||
self.values = valid_chars
|
||||
# Free letters: B FG J QR T XYZab e gh jk mno qrst xyz
|
||||
conventions = {
|
||||
'F': FunctionConvention('F', "System V", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', 'x', 'X']),
|
||||
'W': FunctionConvention('W', "Windows", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'P', 'A'])
|
||||
}
|
||||
sortedvalues = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', 'x', 'X', '0', '1']
|
||||
assert(all(all(c not in conv.values[:i] and c in sortedvalues for i, c in enumerate(conv.values)) for conv in conventions.values()))
|
||||
|
||||
class FunctionType(str):
|
||||
values: List[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A']
|
||||
|
||||
@staticmethod
|
||||
def validate(s: str, post: str) -> bool:
|
||||
if len(s) < 3:
|
||||
@@ -163,10 +173,13 @@ class FunctionType(str):
|
||||
# TODO: change *FEv into true functions (right now they are redirected to *FE)
|
||||
#chk_type = s[0] + s[3:]
|
||||
|
||||
if s[1] not in ["F"]:
|
||||
if s[1] not in conventions:
|
||||
raise NotImplementedError("Bad middle letter {0}{1}".format(s[1], post))
|
||||
|
||||
return all(c in FunctionType.values for c in chk_type) and (('v' not in chk_type[1:]) or (len(chk_type) == 2))
|
||||
return all(c in conventions[s[1]].values for c in chk_type) and (('v' not in chk_type[1:]) or (len(chk_type) == 2))
|
||||
|
||||
def get_convention(self) -> FunctionConvention:
|
||||
return conventions[self[1]]
|
||||
|
||||
def splitchar(self) -> List[int]:
|
||||
"""
|
||||
@@ -177,9 +190,9 @@ class FunctionType(str):
|
||||
of `values.index`.
|
||||
"""
|
||||
try:
|
||||
ret = [len(self), FunctionType.values.index(self[0])]
|
||||
ret = [len(self), ord(self.get_convention().ident), self.get_convention().values.index(self[0])]
|
||||
for c in self[2:]:
|
||||
ret.append(FunctionType.values.index(c))
|
||||
ret.append(self.get_convention().values.index(c))
|
||||
return ret
|
||||
except ValueError as e:
|
||||
raise ValueError("Value is " + self) from e
|
||||
@@ -187,8 +200,6 @@ class FunctionType(str):
|
||||
def __getitem__(self, i: Union[int, slice]) -> 'FunctionType':
|
||||
return FunctionType(super().__getitem__(i))
|
||||
|
||||
assert(all(c not in FunctionType.values[:i] for i, c in enumerate(FunctionType.values)))
|
||||
|
||||
RedirectType = NewType('RedirectType', FunctionType)
|
||||
DefineType = NewType('DefineType', str)
|
||||
|
||||
@@ -373,7 +384,7 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
# If you find no problem, comment the error below, add a "pass" line (so python is happy)
|
||||
# and open a ticket so I can fix this.
|
||||
raise NotImplementedError("Some functions are only implemented under one condition (probably) ({0}:{1})"
|
||||
.format(k, filename) + " [extra note in the script]")
|
||||
.format(k, filename) + " [extra note in the script]\nProblematic function{}: {}".format(("" if len(funsname[k]) == 1 else "s"), funsname[k]))
|
||||
for f in funsname[k]:
|
||||
if f in ['_fini', '_init', '__bss_start', '__data_start', '_edata', '_end']:
|
||||
continue # Always allow those symbols [TODO: check if OK]
|
||||
@@ -388,7 +399,11 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("sdl1mixer", "sdl2mixer") \
|
||||
or match("sdl1net", "sdl2net") \
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("libc", "tcmallocminimal"):
|
||||
or match("libGL", "libEGL") \
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("libc", "androidshmem") \
|
||||
or match("tcmallocminimal", "tbbmallocproxy"):
|
||||
continue
|
||||
|
||||
# Note: this test is very (too) simple. If it ever raises, comment
|
||||
@@ -459,7 +474,8 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
gotype = ln.split("(")[0].strip()
|
||||
funname = ln.split(",")[0].split("(")[1].strip()
|
||||
ln = ln.split(",")[1].split(")")[0].strip()
|
||||
add_symbol_name(funname)
|
||||
if not filename.endswith("_genvate.h"):
|
||||
add_symbol_name(funname)
|
||||
except IndexError:
|
||||
raise NotImplementedError("Invalid GO command: {0}:{1}".format(
|
||||
filename, line[:-1]
|
||||
@@ -468,26 +484,40 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
hasFlatStructure = False
|
||||
origLine = ln
|
||||
if not FunctionType.validate(ln, " ({0}:{1})".format(filename, line[:-1])):
|
||||
if (ln[0] in FunctionType.values) \
|
||||
# This needs more work
|
||||
old = RedirectType(FunctionType(ln))
|
||||
if (ln[0] in old.get_convention().values) \
|
||||
and ('v' not in ln[2:]) \
|
||||
and all((c in FunctionType.values) or (c in mystructs) for c in ln[2:]):
|
||||
and all((c in old.get_convention().values) or (c in mystructs) for c in ln[2:]):
|
||||
hasFlatStructure = True
|
||||
|
||||
for sn in mystructs:
|
||||
ln = ln.replace(sn, mystructs[sn][1])
|
||||
ln = ln[0] + 'F' + ln[2:] # In case a structure named 'F' is used
|
||||
mystructuses[RedirectType(FunctionType(origLine))] = FunctionType(ln)
|
||||
else:
|
||||
# This needs more work
|
||||
old = RedirectType(FunctionType(ln))
|
||||
acceptables = ['0', '1'] + FunctionType.values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("0", "i") # 0 -> integer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
assert(len(ln) >= 3)
|
||||
if old.get_convention().name == "System V":
|
||||
acceptables = ['0', '1'] + old.get_convention().values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("0", "i") # 0 -> integer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
assert(len(ln) >= 3)
|
||||
else:
|
||||
acceptables = ['0', '1', 'D', 'H'] + old.get_convention().values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = ln[:2] + (ln[2:]
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("D", "p") # long double -> pointer
|
||||
.replace("H", "p") # unsigned __int128 -> pointer
|
||||
.replace("0", "i") # 0 -> integer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
assert(len(ln) >= 3)
|
||||
redirects.setdefault(str(dependants), {})
|
||||
redirects[str(dependants)][old] = FunctionType(ln)
|
||||
|
||||
@@ -522,6 +552,7 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
typedefs.setdefault(RedirectType(FunctionType(origLine)), [])
|
||||
|
||||
# If the line is a structure metadata information...
|
||||
# FIXME: what happens with e.g. a Windows function?
|
||||
elif ln.startswith("//%S"):
|
||||
metadata = [e for e in ln.split() if e]
|
||||
if len(metadata) != 4:
|
||||
@@ -535,12 +566,12 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
if metadata[3] == "":
|
||||
# If you need this, please open an issue (this is never actually called, empty strings are removed)
|
||||
raise NotImplementedError("Invalid structure metadata supply (empty replacement) ({0}:{1})".format(filename, line[:-1]))
|
||||
if any(c not in FunctionType.values for c in metadata[3]):
|
||||
if any(c not in conventions['F'].values for c in metadata[3]):
|
||||
# Note that replacement cannot be another structure type
|
||||
raise NotImplementedError("Invalid structure metadata supply (invalid replacement) ({0}:{1})".format(filename, line[:-1]))
|
||||
if metadata[1] in mystructs:
|
||||
raise NotImplementedError("Invalid structure nickname {0} (duplicate) ({1}/{2})".format(metadata[1], filename, line[:-1]))
|
||||
if (metadata[1] in FunctionType.values) or (metadata[1] in ['0', '1']):
|
||||
if (metadata[1] in conventions['F'].values) or (metadata[1] in ['0', '1']):
|
||||
raise NotImplementedError("Invalid structure nickname {0} (reserved) ({1}/{2})".format(metadata[1], filename, line[:-1]))
|
||||
|
||||
# OK, add into the database
|
||||
@@ -675,17 +706,21 @@ def sortArrays(gbl_tmp : JumbledGlobals, red_tmp : JumbledRedirects, filespec: J
|
||||
for k3 in gbl:
|
||||
gbl[k3].sort(key=FunctionType.splitchar)
|
||||
|
||||
FunctionType.values = FunctionType.values + ['0', '1']
|
||||
oldvals = { k: conventions[k].values for k in conventions }
|
||||
for k in conventions:
|
||||
conventions[k].values = sortedvalues
|
||||
for k3 in redirects:
|
||||
redirects[k3].sort(key=lambda v: v[0].splitchar() + v[1].splitchar())
|
||||
FunctionType.values = FunctionType.values[:-2]
|
||||
for k in conventions:
|
||||
conventions[k].values = oldvals[k]
|
||||
|
||||
sortedfilespec: SortedFilesSpecific = {}
|
||||
for fn in filespec:
|
||||
# Maybe do better?
|
||||
mystructs_vals: List[str] = sorted(filespec[fn][1].keys())
|
||||
if mystructs_vals != []:
|
||||
FunctionType.values = FunctionType.values + list(mystructs_vals)
|
||||
for k in conventions:
|
||||
conventions[k].values = conventions[k].values + list(mystructs_vals)
|
||||
|
||||
mytypedefs_vals: List[RedirectType] = sorted(filespec[fn][0].keys(), key=FunctionType.splitchar)
|
||||
sortedfilespec[fn] = (
|
||||
@@ -694,7 +729,8 @@ def sortArrays(gbl_tmp : JumbledGlobals, red_tmp : JumbledRedirects, filespec: J
|
||||
)
|
||||
|
||||
if mystructs_vals != []:
|
||||
FunctionType.values = FunctionType.values[:-len(mystructs_vals)]
|
||||
for k in conventions:
|
||||
conventions[k].values = conventions[k].values[:-len(mystructs_vals)]
|
||||
|
||||
return CustOrderedDict(gbl, gbl_idxs), CustOrderedDict(redirects, redirects_idxs), sortedfilespec
|
||||
|
||||
@@ -781,24 +817,33 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Detect simple wrappings
|
||||
simple_wraps: Dict[ClausesStr, List[Tuple[FunctionType, int]]] = {}
|
||||
allowed_conv_ident = "F"
|
||||
allowed_conv = conventions[allowed_conv_ident]
|
||||
|
||||
# H could be allowed maybe?
|
||||
allowed_simply: str = "v"
|
||||
allowed_regs : str = "cCwWiuIUlLp"
|
||||
allowed_fpr : str = "fd"
|
||||
|
||||
# Detect functions which return in an x87 register
|
||||
retx87_wraps: Dict[ClausesStr, List[FunctionType]] = {}
|
||||
return_x87: str = "DK"
|
||||
|
||||
# Sanity checks
|
||||
forbidden_simple: str = "EDKVOSNMHPA"
|
||||
assert(len(allowed_simply) + len(allowed_regs) + len(allowed_fpr) + len(forbidden_simple) == len(FunctionType.values))
|
||||
forbidden_simple: str = "EDKVOSNMHPAxX"
|
||||
assert(len(allowed_simply) + len(allowed_regs) + len(allowed_fpr) + len(forbidden_simple) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs for c in allowed_simply))
|
||||
assert(all(c not in allowed_simply + allowed_regs for c in allowed_fpr))
|
||||
assert(all(c not in allowed_simply + allowed_regs + allowed_fpr for c in forbidden_simple))
|
||||
assert(all(c in allowed_simply + allowed_regs + allowed_fpr + forbidden_simple for c in FunctionType.values))
|
||||
assert(all(c in allowed_simply + allowed_regs + allowed_fpr + forbidden_simple for c in allowed_conv.values))
|
||||
assert(all(c in allowed_conv.values for c in return_x87))
|
||||
|
||||
def check_simple(v: FunctionType):
|
||||
def check_simple(v: FunctionType) -> Optional[int]:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
return None
|
||||
if v[0] in forbidden_simple:
|
||||
return None
|
||||
for c in v[2:]:
|
||||
@@ -828,6 +873,15 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
simple_wraps[k] = tmp
|
||||
simple_idxs = sorted(simple_wraps.keys(), key=lambda x: Clauses(x).splitdef())
|
||||
|
||||
def check_return_x87(v: FunctionType) -> bool:
|
||||
return v[0] in return_x87
|
||||
|
||||
for k in gbls:
|
||||
tmp = [v for v in gbls[k] if check_return_x87(v)]
|
||||
if tmp:
|
||||
retx87_wraps[k] = tmp
|
||||
retx87_idxs = sorted(retx87_wraps.keys(), key=lambda x: Clauses(x).splitdef())
|
||||
|
||||
# Now the files rebuilding part
|
||||
# File headers and guards
|
||||
files_header = {
|
||||
@@ -841,6 +895,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "regs.h"
|
||||
#include "x64emu.h"
|
||||
#define COMPLEX_IMPL
|
||||
#include "complext.h"
|
||||
|
||||
extern void* my__IO_2_1_stdin_ ;
|
||||
extern void* my__IO_2_1_stdout_;
|
||||
@@ -869,12 +925,14 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
#define __WRAPPER_H_
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "complext.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
// the generic wrapper pointer functions
|
||||
typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc);
|
||||
|
||||
|
||||
|
||||
// list of defined wrapper
|
||||
// E = current x86emu struct
|
||||
// v = void
|
||||
@@ -894,6 +952,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
// M = ... automatically sending 2 args
|
||||
// A = va_list
|
||||
// 0 = constant 0, 1 = constant 1
|
||||
// x = float complex
|
||||
// X = double complex
|
||||
|
||||
""",
|
||||
"fntypes.h": """
|
||||
@@ -954,15 +1014,21 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Rewrite the wrapper.c file:
|
||||
# i and u should only be 32 bits
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
td_types = ["x64emu_t*", "void", "int8_t", "int16_t", "int64_t", "int64_t", "uint8_t", "uint16_t", "uint64_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "unsigned __int128", "void*", "void*"]
|
||||
if len(FunctionType.values) != len(td_types):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(td_types) = {lentypes}".format(lenval=len(FunctionType.values), lentypes=len(td_types)))
|
||||
td_types = {
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
'F': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "unsigned __int128", "void*", "void*", "complexf_t", "complex_t"],
|
||||
# E v c w i I C W u U f d K l L p V O S N M P A
|
||||
'W': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "void*", "void*"]
|
||||
}
|
||||
assert(all(k in conventions for k in td_types))
|
||||
for k in conventions:
|
||||
if len(conventions[k].values) != len(td_types[k]):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(td_types) = {lentypes}".format(lenval=len(conventions[k].values), lentypes=len(td_types[k])))
|
||||
|
||||
def generate_typedefs(arr: Iterable[FunctionType], file) -> None:
|
||||
for v in arr:
|
||||
file.write("typedef " + td_types[FunctionType.values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(td_types[FunctionType.values.index(t)] for t in v[2:]) + ");\n")
|
||||
file.write("typedef " + td_types[v.get_convention().ident][v.get_convention().values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(td_types[v.get_convention().ident][v.get_convention().values.index(t)] for t in v[2:]) + ");\n")
|
||||
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
|
||||
file.write(files_header["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
@@ -981,59 +1047,85 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Helper variables
|
||||
# Return type template
|
||||
vals = [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int64_t)fn({0});", # i should be int32_t
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint64_t)fn({0});", # u should be uint32_t
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0val = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"unsigned __int128 u128 = fn({0}); R_RAX=(u128&0xFFFFFFFFFFFFFFFFL); R_RDX=(u128>>64)&0xFFFFFFFFFFFFFFFFL;", # H
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
]
|
||||
vals = {
|
||||
conventions['F']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int32_t)fn({0});", # i
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint32_t)fn({0});", # u
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0val = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"unsigned __int128 u128 = fn({0}); R_RAX=(u128&0xFFFFFFFFFFFFFFFFL); R_RDX=(u128>>64)&0xFFFFFFFFFFFFFFFFL;", # H
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
'from_complexf(emu, fn({0})));', # x
|
||||
'from_complex(emu, fn({0})));' # X
|
||||
],
|
||||
conventions['W']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int32_t)fn({0});", # i
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint32_t)fn({0});", # u
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
]
|
||||
}
|
||||
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
assert(len(reg_arg) == 6)
|
||||
# vreg: value is in a general register
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
vreg = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 2, 2, 0, 1]
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vreg = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 2, 2, 0, 1, 0, 0]
|
||||
# vxmm: value is in a XMM register
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
vxmm = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vxmm = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2]
|
||||
# vother: value is elsewere
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
vother = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vother = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
# vstack: value is on the stack (or out of register)
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A
|
||||
vstack = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 1, 1, 1, 2, 2, 1, 1]
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vstack = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 1, 1, 1, 2, 2, 1, 1, 1, 2]
|
||||
arg_r = [
|
||||
"", # E
|
||||
"", # v
|
||||
"(int8_t){p}, ", # c
|
||||
"(int16_t){p}, ", # w
|
||||
"(int64_t){p}, ", # i should int32_t
|
||||
"(int32_t){p}, ", # i
|
||||
"(int64_t){p}, ", # I
|
||||
"(uint8_t){p}, ", # C
|
||||
"(uint16_t){p}, ", # W
|
||||
"(uint64_t){p}, ", # u should uint32_t
|
||||
"(uint32_t){p}, ", # u
|
||||
"(uint64_t){p}, ", # U
|
||||
"", # f
|
||||
"", # d
|
||||
@@ -1050,6 +1142,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"\n#error Use pp instead\n", # H
|
||||
"", # P
|
||||
"(void*){p}, ", # A
|
||||
"", # x
|
||||
"", # X
|
||||
]
|
||||
arg_x = [
|
||||
"", # E
|
||||
@@ -1077,6 +1171,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"to_complexf(emu, {p}),",# x
|
||||
"to_complex(emu, {p})," # X
|
||||
]
|
||||
arg_o = [
|
||||
"emu, ", # E
|
||||
@@ -1104,17 +1200,19 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"", # x
|
||||
"", # X
|
||||
]
|
||||
arg_s = [
|
||||
"", # E
|
||||
"", # v
|
||||
"*(int8_t*)(R_RSP + {p}), ", # c
|
||||
"*(int16_t*)(R_RSP + {p}), ", # w
|
||||
"*(int64_t*)(R_RSP + {p}), ", # i should be int32_t
|
||||
"*(int32_t*)(R_RSP + {p}), ", # i
|
||||
"*(int64_t*)(R_RSP + {p}), ", # I
|
||||
"*(uint8_t*)(R_RSP + {p}), ", # C
|
||||
"*(uint16_t*)(R_RSP + {p}), ", # W
|
||||
"*(uint64_t*)(R_RSP + {p}), ", # u should be uint32_t
|
||||
"*(uint32_t*)(R_RSP + {p}), ", # u
|
||||
"*(uint64_t*)(R_RSP + {p}), ", # U
|
||||
"*(float*)(R_RSP + {p}), ", # f
|
||||
"*(double*)(R_RSP + {p}), ", # d
|
||||
@@ -1131,27 +1229,38 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"*(unsigned __int128)(R_RSP + {p}), ", # H
|
||||
"*(void**)(R_RSP + {p}), ", # P
|
||||
"*(void**)(R_RSP + {p}), ", # A
|
||||
"*(complexf_t*)(R_RSP + {p}), ", # x
|
||||
"*(complex_t*)(R_RSP + {p}), ", # X
|
||||
]
|
||||
|
||||
|
||||
# Asserts
|
||||
if len(FunctionType.values) != len(vstack):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vstack) = {lenvstack}".format(lenval=len(FunctionType.values), lenvstack=len(vstack)))
|
||||
if len(FunctionType.values) != len(vreg):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vreg) = {lenvreg}".format(lenval=len(FunctionType.values), lenvreg=len(vreg)))
|
||||
if len(FunctionType.values) != len(vxmm):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vxmm) = {lenvxmm}".format(lenval=len(FunctionType.values), lenvxmm=len(vxmm)))
|
||||
if len(FunctionType.values) != len(vother):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vother) = {lenvother}".format(lenval=len(FunctionType.values), lenvother=len(vother)))
|
||||
if len(FunctionType.values) != len(arg_s):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_s) = {lenargs}".format(lenval=len(FunctionType.values), lenargs=len(arg_s)))
|
||||
if len(FunctionType.values) != len(arg_r):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_r) = {lenargr}".format(lenval=len(FunctionType.values), lenargr=len(arg_r)))
|
||||
if len(FunctionType.values) != len(arg_x):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_x) = {lenargx}".format(lenval=len(FunctionType.values), lenargx=len(arg_x)))
|
||||
if len(FunctionType.values) != len(arg_o):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_o) = {lenargo}".format(lenval=len(FunctionType.values), lenargo=len(arg_o)))
|
||||
if len(FunctionType.values) != len(vals):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vals) = {lenvals}".format(lenval=len(FunctionType.values), lenvals=len(vals)))
|
||||
for k in conventions:
|
||||
assert all(v in conventions['F'].values for v in conventions[k].values), "a convention is not a subset of System V"
|
||||
assert all(vr == vs for (vr, vs) in zip(vreg, vstack) if vr != 0), "vreg and vstack are inconsistent"
|
||||
assert all(vx == vs for (vx, vs) in zip(vxmm, vstack) if vx != 0), "vxmm and vstack are inconsistent"
|
||||
assert all((vo == 0) == (vs != 0) for (vo, vs) in zip(vother, vstack)), "vother and vstack are inconsistent"
|
||||
if len(conventions['F'].values) != len(vstack):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vstack) = {lenvstack}".format(lenval=len(conventions['F'].values), lenvstack=len(vstack)))
|
||||
if len(conventions['F'].values) != len(vreg):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vreg) = {lenvreg}".format(lenval=len(conventions['F'].values), lenvreg=len(vreg)))
|
||||
if len(conventions['F'].values) != len(vxmm):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vxmm) = {lenvxmm}".format(lenval=len(conventions['F'].values), lenvxmm=len(vxmm)))
|
||||
if len(conventions['F'].values) != len(vother):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vother) = {lenvother}".format(lenval=len(conventions['F'].values), lenvother=len(vother)))
|
||||
if len(conventions['F'].values) != len(arg_s):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_s) = {lenargs}".format(lenval=len(conventions['F'].values), lenargs=len(arg_s)))
|
||||
if len(conventions['F'].values) != len(arg_r):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_r) = {lenargr}".format(lenval=len(conventions['F'].values), lenargr=len(arg_r)))
|
||||
if len(conventions['F'].values) != len(arg_x):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_x) = {lenargx}".format(lenval=len(conventions['F'].values), lenargx=len(arg_x)))
|
||||
if len(conventions['F'].values) != len(arg_o):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg_o) = {lenargo}".format(lenval=len(conventions['F'].values), lenargo=len(arg_o)))
|
||||
for k in conventions:
|
||||
c = conventions[k]
|
||||
if c not in vals:
|
||||
raise NotImplementedError("[{k}]values not in vals".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
if len(c.values) != len(vals[c]):
|
||||
raise NotImplementedError("len([{k}]values) = {lenval} != len(vals[...]) = {lenvals}".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
# When arg_* is not empty, v* should not be 0
|
||||
if any(map(lambda v, a: (a != "") and (v == 0), vstack, arg_s)):
|
||||
raise NotImplementedError("Something in the stack has a null offset and a non-empty arg string")
|
||||
@@ -1172,7 +1281,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
raise NotImplementedError("Something can be in an XMM register but not in the stack")
|
||||
|
||||
# Helper functions to write the function definitions
|
||||
def function_args(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> str:
|
||||
systemVconv = conventions['F']
|
||||
def function_args_systemV(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> str:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
# r: general register no
|
||||
@@ -1182,16 +1292,18 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Redirections
|
||||
if args[0] == "0":
|
||||
return "0, " + function_args(args[1:], d, r, x)
|
||||
return "0, " + function_args_systemV(args[1:], d, r, x)
|
||||
elif args[0] == "1":
|
||||
return "1, " + function_args(args[1:], d, r, x)
|
||||
return "1, " + function_args_systemV(args[1:], d, r, x)
|
||||
|
||||
idx = FunctionType.values.index(args[0])
|
||||
if (r < 6) and (vreg[idx] > 0):
|
||||
idx = systemVconv.values.index(args[0])
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
if (r < len(reg_arg)) and (vreg[idx] > 0):
|
||||
ret = ""
|
||||
for _ in range(vreg[idx]):
|
||||
# There may be values in multiple registers
|
||||
if r < 6:
|
||||
if r < len(reg_arg):
|
||||
# Value is in a general register
|
||||
ret = ret + arg_r[idx].format(p=reg_arg[r])
|
||||
r = r + 1
|
||||
@@ -1199,23 +1311,59 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
# Remaining is in the stack
|
||||
ret = ret + arg_s[idx].format(p=d)
|
||||
d = d + 8
|
||||
return ret + function_args(args[1:], d, r, x)
|
||||
return ret + function_args_systemV(args[1:], d, r, x)
|
||||
elif (x < 8) and (vxmm[idx] > 0):
|
||||
# Value is in an XMM register
|
||||
return arg_x[idx].format(p=x) + function_args(args[1:], d, r, x+1)
|
||||
return arg_x[idx].format(p=x) + function_args_systemV(args[1:], d, r, x+1)
|
||||
elif vstack[idx] > 0:
|
||||
# Value is in the stack
|
||||
return arg_s[idx].format(p=d) + function_args(args[1:], d+8*vstack[idx], r, x)
|
||||
return arg_s[idx].format(p=d) + function_args_systemV(args[1:], d+8*vstack[idx], r, x)
|
||||
else:
|
||||
# Value is somewhere else
|
||||
return arg_o[idx].format(p=d) + function_args(args[1:], d, r, x)
|
||||
return arg_o[idx].format(p=d) + function_args_systemV(args[1:], d, r, x)
|
||||
# windowsconv = conventions['W']
|
||||
def function_args_windows(args: FunctionType, d: int = 40, r: int = 0) -> str:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
# r: general register no
|
||||
# We can re-use vstack to know if we need to put a pointer or the value
|
||||
if len(args) == 0:
|
||||
return ""
|
||||
|
||||
# Redirections
|
||||
if args[0] == "0":
|
||||
return "0, " + function_args_windows(args[1:], d, r)
|
||||
elif args[0] == "1":
|
||||
return "1, " + function_args_windows(args[1:], d, r)
|
||||
|
||||
idx = systemVconv.values.index(args[0]) # Little hack to be able to re-use
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RCX", "R_RDX", "R_R8", "R_R9"]
|
||||
if (r < len(reg_arg)) and (vstack[idx] == 1):
|
||||
# We use a register
|
||||
if vreg[idx] == 1:
|
||||
# Value is in a general register
|
||||
return arg_r[idx].format(p=reg_arg[r]) + function_args_windows(args[1:], d, r+1)
|
||||
else:
|
||||
# Remaining is in an XMM register
|
||||
return arg_x[idx].format(p=r) + function_args_windows(args[1:], d, r+1)
|
||||
elif vstack[idx] > 0:
|
||||
# Value is in the stack
|
||||
return arg_s[idx].format(p=d) + function_args_windows(args[1:], d+8*vstack[idx], r)
|
||||
else:
|
||||
# Value is somewhere else
|
||||
return arg_o[idx].format(p=d) + function_args_windows(args[1:], d, r)
|
||||
|
||||
def function_writer(f, N: FunctionType, W: str) -> None:
|
||||
# Write to f the function type N (real type W)
|
||||
|
||||
f.write("void {0}(x64emu_t *emu, uintptr_t fcn) {2} {1} fn = ({1})fcn; ".format(N, W, "{"))
|
||||
# Generic function
|
||||
f.write(vals[FunctionType.values.index(N[0])].format(function_args(N[2:])[:-2]) + " }\n")
|
||||
conv = N.get_convention()
|
||||
if conv is systemVconv:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_systemV(N[2:])[:-2]) + " }\n")
|
||||
else:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_windows(N[2:])[:-2]) + " }\n")
|
||||
|
||||
for k in gbls:
|
||||
if k != str(Clauses()):
|
||||
@@ -1248,6 +1396,17 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
|
||||
# Write the isRetX87Wrapper function
|
||||
file.write("\nint isRetX87Wrapper(wrapper_t fun) {\n")
|
||||
for k in retx87_idxs:
|
||||
if k != str(Clauses()):
|
||||
file.write("#if " + k + "\n")
|
||||
for vf in retx87_wraps[k]:
|
||||
file.write("\tif (fun == &" + vf + ") return 1;\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
|
||||
file.write(files_guard["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
@@ -1273,13 +1432,15 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write(files_guard["wrapper.h"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the *types.h files:
|
||||
td_types[FunctionType.values.index('A')] = "va_list"
|
||||
td_types[FunctionType.values.index('V')] = "..."
|
||||
orig_val_len = len(FunctionType.values)
|
||||
for k in conventions:
|
||||
td_types[k][conventions[k].values.index('A')] = "va_list"
|
||||
td_types[k][conventions[k].values.index('V')] = "..."
|
||||
orig_val_len = {k: len(conventions[k].values) for k in conventions}
|
||||
for fn in filesspec:
|
||||
for strc in fsp_tmp[fn][1]:
|
||||
FunctionType.values.append(strc)
|
||||
td_types.append(fsp_tmp[fn][1][strc][0])
|
||||
for k in conventions:
|
||||
conventions[k].values.append(strc)
|
||||
td_types[k].append(fsp_tmp[fn][1][strc][0])
|
||||
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", fn + "types.h"), 'w') as file:
|
||||
file.write(files_header["fntypes.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
|
||||
@@ -1303,8 +1464,9 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write("#undef {defined}\n".format(defined=defined))
|
||||
file.write(files_guard["fnundefs.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
|
||||
|
||||
FunctionType.values = FunctionType.values[:orig_val_len]
|
||||
td_types = td_types[:orig_val_len]
|
||||
for k in conventions:
|
||||
conventions[k].values = conventions[k].values[:orig_val_len[k]]
|
||||
td_types[k] = td_types[k][:orig_val_len[k]]
|
||||
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
|
||||
@@ -1318,6 +1480,6 @@ if __name__ == '__main__':
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
Define.defines = list(map(DefineType, sys.argv[2:limit[0]]))
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.1.0.16") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.2.0.18") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
Executable → Regular
+4
-1
@@ -11,6 +11,9 @@ endif( NOT TEST_OUTPUT )
|
||||
if( NOT TEST_REFERENCE )
|
||||
message( FATAL_ERROR "Require TEST_REFERENCE to be defined" )
|
||||
endif( NOT TEST_REFERENCE )
|
||||
if(NOT DEFINED ENV{INTERPRETER})
|
||||
set(ENV{INTERPRETER} "")
|
||||
endif()
|
||||
|
||||
set(ENV{BOX64_LOG} 0)
|
||||
set(ENV{BOX64_NOBANNER} 1)
|
||||
@@ -24,7 +27,7 @@ endif( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
execute_process(
|
||||
COMMAND ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
|
||||
COMMAND $ENV{INTERPRETER} ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
|
||||
OUTPUT_FILE ${TEST_OUTPUT}
|
||||
ERROR_VARIABLE TEST_ERROR
|
||||
RESULT_VARIABLE TEST_RESULT
|
||||
|
||||
Executable → Regular
+150
-95
@@ -19,6 +19,8 @@
|
||||
#include "wrapper.h"
|
||||
#include "x64emu.h"
|
||||
#include "signals.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box64context_t* context)
|
||||
@@ -39,6 +41,7 @@ void finiAllHelpers(box64context_t* context)
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
DeleteParams();
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
@@ -63,8 +66,10 @@ void free_tlsdatasize(void* p)
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
free(data->tlsdata);
|
||||
free(p);
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
if(my_context)
|
||||
pthread_setspecific(my_context->tlskey, NULL);
|
||||
}
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
@@ -73,14 +78,21 @@ int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
uint32_t tid = (uint32_t)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#else
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#endif
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
@@ -100,10 +112,8 @@ void relockMutex(int locks)
|
||||
relockCustommemMutex(locks);
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
mutex_trylock(&A); \
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
@@ -118,22 +128,37 @@ void relockMutex(int locks)
|
||||
|
||||
static void init_mutexes(box64context_t* context)
|
||||
{
|
||||
#ifndef DYNAREC
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_once, &attr);
|
||||
pthread_mutex_init(&context->mutex_once2, &attr);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_lock, &attr);
|
||||
#else
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#else
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
native_lock_store(&context->mutex_trace, 0);
|
||||
native_lock_store(&context->mutex_tls, 0);
|
||||
native_lock_store(&context->mutex_thread, 0);
|
||||
native_lock_store(&context->mutex_bridge, 0);
|
||||
native_lock_store(&context->mutex_dyndump, 0);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void atfork_child_box64context(void)
|
||||
@@ -142,6 +167,31 @@ static void atfork_child_box64context(void)
|
||||
init_mutexes(my_context);
|
||||
}
|
||||
|
||||
void freeCycleLog(box64context_t* ctx)
|
||||
{
|
||||
if(cycle_log) {
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
box_free(ctx->log_call);
|
||||
box_free(ctx->log_ret);
|
||||
ctx->log_call = NULL;
|
||||
ctx->log_ret = NULL;
|
||||
}
|
||||
}
|
||||
void initCycleLog(box64context_t* context)
|
||||
{
|
||||
if(cycle_log) {
|
||||
context->log_call = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
box64context_t *NewBox64Context(int argc)
|
||||
{
|
||||
@@ -152,9 +202,11 @@ box64context_t *NewBox64Context(int argc)
|
||||
}
|
||||
#endif
|
||||
// init and put default values
|
||||
box64context_t *context = my_context = (box64context_t*)calloc(1, sizeof(box64context_t));
|
||||
box64context_t *context = my_context = (box64context_t*)box_calloc(1, sizeof(box64context_t));
|
||||
|
||||
context->deferedInit = 1;
|
||||
initCycleLog(context);
|
||||
|
||||
context->deferredInit = 1;
|
||||
context->sel_serial = 1;
|
||||
|
||||
init_custommem_helper(context);
|
||||
@@ -163,6 +215,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
// Cannot use Bridge name as the map is not initialized yet
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFEv, x64Syscall, 0, NULL);
|
||||
// create the vsyscalls
|
||||
@@ -173,12 +226,14 @@ box64context_t *NewBox64Context(int argc)
|
||||
addAlternate((void*)0xffffffffff600000, (void*)context->vsyscalls[0]);
|
||||
addAlternate((void*)0xffffffffff600400, (void*)context->vsyscalls[1]);
|
||||
addAlternate((void*)0xffffffffff600800, (void*)context->vsyscalls[2]);
|
||||
// create exit bridge
|
||||
context->exit_bridge = AddBridge(context->system, NULL, NULL, 0, NULL);
|
||||
// get handle to box64 itself
|
||||
context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
|
||||
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);
|
||||
@@ -190,11 +245,30 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->canary[getrand(4)] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x28, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
// init segments
|
||||
for(int i=0; i<16; i++) {
|
||||
context->segtls[i].limit = (uintptr_t)-1LL;
|
||||
}
|
||||
context->segtls[10].key_init = 0; // 0x53 selector
|
||||
context->segtls[10].present = 1;
|
||||
context->segtls[8].key_init = 0; // 0x43 selector
|
||||
context->segtls[8].present = 1;
|
||||
context->segtls[6].key_init = 0; // 0x33 selector
|
||||
context->segtls[6].present = 1;
|
||||
context->segtls[5].key_init = 0; // 0x2b selector
|
||||
context->segtls[5].present = 1;
|
||||
context->segtls[4].key_init = 0; // 0x23 selector
|
||||
context->segtls[4].present = 1;
|
||||
context->segtls[4].is32bits = 1;
|
||||
|
||||
context->globdata = NewMapSymbols();
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void freeALProcWrapper(box64context_t* context);
|
||||
EXPORTDYN
|
||||
void FreeBox64Context(box64context_t** context)
|
||||
{
|
||||
@@ -206,6 +280,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
box64context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
//clean_current_emuthread(); // cleaning main thread seems a bad idea
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
if(ctx->maplib)
|
||||
@@ -215,7 +290,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
box_free(ctx->elfs);
|
||||
|
||||
FreeCollection(&ctx->box64_path);
|
||||
FreeCollection(&ctx->box64_ld_lib);
|
||||
@@ -223,20 +298,22 @@ void FreeBox64Context(box64context_t** context)
|
||||
// stop trace now
|
||||
if(ctx->dec)
|
||||
DeleteX64TraceDecoder(&ctx->dec);
|
||||
if(ctx->dec32)
|
||||
DeleteX86TraceDecoder(&ctx->dec32);
|
||||
if(ctx->zydis)
|
||||
DeleteX64Trace(ctx);
|
||||
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
if(ctx->deferredInitList)
|
||||
box_free(ctx->deferredInitList);
|
||||
|
||||
free(ctx->argv);
|
||||
/*box_free(ctx->argv);*/
|
||||
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
/*for (int i=0; i<ctx->envc; ++i)
|
||||
box_free(ctx->envv[i]);
|
||||
box_free(ctx->envv);*/
|
||||
|
||||
if(ctx->atfork_sz) {
|
||||
free(ctx->atforks);
|
||||
box_free(ctx->atforks);
|
||||
ctx->atforks = NULL;
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
@@ -252,8 +329,9 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box64path);
|
||||
box_free(ctx->fullpath);
|
||||
box_free(ctx->box64path);
|
||||
box_free(ctx->bashpath);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
@@ -261,58 +339,84 @@ void FreeBox64Context(box64context_t** context)
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if(ctx->stack_clone)
|
||||
free(ctx->stack_clone);
|
||||
box_free(ctx->stack_clone);
|
||||
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
pthread_setspecific(ctx->tlskey, NULL);
|
||||
}
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
box_free(ctx->tlsdata);
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
free_neededlib(ctx->neededlibs);
|
||||
ctx->neededlibs = NULL;
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX64Emu(&ctx->emu_sig);
|
||||
|
||||
FreeMapSymbols(&ctx->globdata);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
#ifndef DYNAREC
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
#endif
|
||||
|
||||
free(ctx);
|
||||
freeCycleLog(ctx);
|
||||
|
||||
box_free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
int idx = ctx->elfsize;
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
int idx = 0;
|
||||
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
|
||||
if(idx == ctx->elfsize) {
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
} else {
|
||||
ctx->elfs[idx] = head;
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
if(GetTLSBase(head)) {
|
||||
// should remove the tls info
|
||||
int tlsbase = GetTLSBase(head);
|
||||
/*if(tlsbase == -ctx->tlssize) {
|
||||
// not really correct, but will do for now
|
||||
ctx->tlssize -= GetTLSSize(head);
|
||||
if(!(++ctx->sel_serial))
|
||||
++ctx->sel_serial;
|
||||
}*/
|
||||
}
|
||||
for(int i=0; i<ctx->elfsize; ++i)
|
||||
if(ctx->elfs[i] == head) {
|
||||
ctx->elfs[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int AddTLSPartition(box64context_t* context, int tlssize) {
|
||||
int oldsize = context->tlssize;
|
||||
// should in fact first try to map a hole, but rewinding all elfs and checking filled space, like with the mapmem utilities
|
||||
context->tlssize += tlssize;
|
||||
context->tlsdata = realloc(context->tlsdata, context->tlssize);
|
||||
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
|
||||
// clean GS segment for current emu
|
||||
@@ -325,52 +429,3 @@ int AddTLSPartition(box64context_t* context, int tlssize) {
|
||||
return -context->tlssize; // negative offset
|
||||
}
|
||||
|
||||
void add_neededlib(needed_libs_t* needed, library_t* lib)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
for(int i=0; i<needed->size; ++i)
|
||||
if(needed->libs[i] == lib)
|
||||
return;
|
||||
if(needed->size == needed->cap) {
|
||||
needed->cap += 8;
|
||||
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
|
||||
}
|
||||
needed->libs[needed->size++] = lib;
|
||||
}
|
||||
|
||||
void free_neededlib(needed_libs_t* needed)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
needed->cap = 0;
|
||||
needed->size = 0;
|
||||
if(needed->libs)
|
||||
free(needed->libs);
|
||||
needed->libs = NULL;
|
||||
}
|
||||
|
||||
void add_dependedlib(needed_libs_t* depended, library_t* lib)
|
||||
{
|
||||
if(!depended)
|
||||
return;
|
||||
for(int i=0; i<depended->size; ++i)
|
||||
if(depended->libs[i] == lib)
|
||||
return;
|
||||
if(depended->size == depended->cap) {
|
||||
depended->cap += 8;
|
||||
depended->libs = (library_t**)realloc(depended->libs, depended->cap*sizeof(library_t*));
|
||||
}
|
||||
depended->libs[depended->size++] = lib;
|
||||
}
|
||||
|
||||
void free_dependedlib(needed_libs_t* depended)
|
||||
{
|
||||
if(!depended)
|
||||
return;
|
||||
depended->cap = 0;
|
||||
depended->size = 0;
|
||||
if(depended->libs)
|
||||
free(depended->libs);
|
||||
depended->libs = NULL;
|
||||
}
|
||||
Executable → Regular
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 1
|
||||
#define BOX64_REVISION 8
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_REVISION 6
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
Executable → Regular
File mode changed.
Executable → Regular
+1
-1
@@ -1,6 +1,6 @@
|
||||
#ifndef __BUILD_INFO_H__
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
void PrintBox64Version();
|
||||
void PrintBox64Version(void);
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
+1203
-613
File diff suppressed because it is too large.
Load diff
Executable → Regular
+530
-83
@@ -24,6 +24,7 @@
|
||||
#define xR15 25
|
||||
#define xFlags 26
|
||||
#define xRIP 27
|
||||
#define xSavedSP 28
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
#define wECX xRCX
|
||||
@@ -91,24 +92,24 @@
|
||||
|
||||
// MOVZ
|
||||
#define MOVZ_gen(sf, hw, imm16, Rd) ((sf)<<31 | 0b10<<29 | 0b100101<<23 | (hw)<<21 | (imm16)<<5 | (Rd))
|
||||
#define MOVZx(Rd, imm16) EMIT(MOVZ_gen(1, 0, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVZx_LSL(Rd, imm16, shift) EMIT(MOVZ_gen(1, (shift)/16, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVZw(Rd, imm16) EMIT(MOVZ_gen(0, 0, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVZw_LSL(Rd, imm16, shift) EMIT(MOVZ_gen(0, (shift)/16, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVZx(Rd, imm16) EMIT(MOVZ_gen(1, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVZx_LSL(Rd, imm16, shift) EMIT(MOVZ_gen(1, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVZw(Rd, imm16) EMIT(MOVZ_gen(0, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVZw_LSL(Rd, imm16, shift) EMIT(MOVZ_gen(0, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
|
||||
// MOVN
|
||||
#define MOVN_gen(sf, hw, imm16, Rd) ((sf)<<31 | 0b00<<29 | 0b100101<<23 | (hw)<<21 | (imm16)<<5 | (Rd))
|
||||
#define MOVNx(Rd, imm16) EMIT(MOVN_gen(1, 0, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVNx_LSL(Rd, imm16, shift) EMIT(MOVN_gen(1, (shift)/16, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVNw(Rd, imm16) EMIT(MOVN_gen(0, 0, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVNw_LSL(Rd, imm16, shift) EMIT(MOVN_gen(0, (shift)/16, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVNx(Rd, imm16) EMIT(MOVN_gen(1, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVNx_LSL(Rd, imm16, shift) EMIT(MOVN_gen(1, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVNw(Rd, imm16) EMIT(MOVN_gen(0, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVNw_LSL(Rd, imm16, shift) EMIT(MOVN_gen(0, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
|
||||
// MOVK
|
||||
#define MOVK_gen(sf, hw, imm16, Rd) ((sf)<<31 | 0b11<<29 | 0b100101<<23 | (hw)<<21 | (imm16)<<5 | (Rd))
|
||||
#define MOVKx(Rd, imm16) EMIT(MOVK_gen(1, 0, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVKx_LSL(Rd, imm16, shift) EMIT(MOVK_gen(1, (shift)/16, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVKw(Rd, imm16) EMIT(MOVK_gen(0, 0, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVKw_LSL(Rd, imm16, shift) EMIT(MOVK_gen(0, (shift)/16, ((uint16_t)imm16)&0xffff, Rd))
|
||||
#define MOVKx(Rd, imm16) EMIT(MOVK_gen(1, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVKx_LSL(Rd, imm16, shift) EMIT(MOVK_gen(1, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVKw(Rd, imm16) EMIT(MOVK_gen(0, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVKw_LSL(Rd, imm16, shift) EMIT(MOVK_gen(0, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
|
||||
// This macro will give a -Wsign-compare warning, probably bug #38341
|
||||
#define MOV32w(Rd, imm32) \
|
||||
@@ -129,6 +130,7 @@
|
||||
}
|
||||
|
||||
#define MOV64xw(Rd, imm64) if(rex.w) {MOV64x(Rd, imm64);} else {MOV32w(Rd, imm64);}
|
||||
#define MOV64z(Rd, imm64) if(rex.is32bits) {MOV32w(Rd, imm64);} else {MOV64x(Rd, imm64);}
|
||||
|
||||
|
||||
// ADD / SUB
|
||||
@@ -140,6 +142,7 @@
|
||||
#define ADDSw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDxw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(ADDSUB_REG_gen(rex.w, 0, 0, 0b01, Rm, lsr, Rn, Rd))
|
||||
|
||||
@@ -150,6 +153,7 @@
|
||||
#define ADDSw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 0, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDz_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.is32bits?0:1, 0, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
|
||||
#define SUBx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
@@ -159,6 +163,7 @@
|
||||
#define SUBSw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define CMPSx_REG(Rn, Rm) SUBSx_REG(xZR, Rn, Rm)
|
||||
#define CMPSw_REG(Rn, Rm) SUBSw_REG(wZR, Rn, Rm)
|
||||
@@ -175,6 +180,7 @@
|
||||
#define SUBw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBz_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.is32bits?0:1, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define CMPSx_U12(Rn, imm12) SUBSx_U12(xZR, Rn, imm12)
|
||||
#define CMPSw_U12(Rn, imm12) SUBSw_U12(wZR, Rn, imm12)
|
||||
@@ -194,9 +200,15 @@
|
||||
#define SBCSw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSxw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
|
||||
|
||||
// CCMP compare if cond is true, set nzcv if false
|
||||
#define CCMP_reg(sf, Rm, cond, Rn, nzcv) ((sf)<<31 | 1<<30 | 1<<29 | 0b11010010<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (nzcv))
|
||||
#define CCMPw(Wn, Wm, nzcv, cond) EMIT(CCMP_reg(0, Wm, cond, Wn, nzcv))
|
||||
#define CCMPx(Xn, Xm, nzcv, cond) EMIT(CCMP_reg(1, Xm, cond, Xn, nzcv))
|
||||
#define CCMPxw(Xn, Xm, nzcv, cond) EMIT(CCMP_reg(rex.w, Xm, cond, Xn, nzcv))
|
||||
|
||||
// ADR
|
||||
#define ADR_gen(immlo, immhi, Rd) ((immlo)<<29 | 0b10000<<24 | (immhi)<<5 | (Rd))
|
||||
#define ADR_S20(Rd, imm) EMIT(ADR_gen((imm)&3, ((imm)>>2)&0x7ffff, (Rd))
|
||||
#define ADR_S20(Rd, imm) EMIT(ADR_gen((imm)&3, ((imm)>>2)&0x7ffff, (Rd)))
|
||||
|
||||
// LDR
|
||||
#define LDR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b01<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -220,6 +232,7 @@
|
||||
#define LDRB_U12(Rt, Rn, imm12) EMIT(LD_gen(0b00, 0b01, ((uint32_t)((imm12)))&0xfff, Rn, Rt))
|
||||
#define LDRH_U12(Rt, Rn, imm12) EMIT(LD_gen(0b01, 0b01, ((uint32_t)((imm12)>>1))&0xfff, Rn, Rt))
|
||||
#define LDRxw_U12(Rt, Rn, imm12) EMIT(LD_gen((rex.w)?0b11:0b10, 0b01, ((uint32_t)((imm12)>>(2+rex.w)))&0xfff, Rn, Rt))
|
||||
#define LDRz_U12(Rt, Rn, imm12) EMIT(LD_gen((rex.is32bits)?0b10:0b11, 0b01, ((uint32_t)((imm12)>>(rex.is32bits?2:3)))&0xfff, Rn, Rt))
|
||||
|
||||
#define LDS_gen(size, op1, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b10<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSW_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b10, 0b01, ((uint32_t)((imm12)>>2))&0xfff, Rn, Rt))
|
||||
@@ -231,7 +244,9 @@
|
||||
#define LDRw_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRw_REG_LSL2(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b011, 1, Rn, Rt))
|
||||
#define LDRxw_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRz_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRB_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRB_REG_UXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b010, 0, Rn, Rt))
|
||||
#define LDRH_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
|
||||
#define LDRS_U12_gen(size, op1, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -248,6 +263,41 @@
|
||||
#define LDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | (imm19)<<5 | (Rt))
|
||||
#define LDRx_literal(Rt, imm19) EMIT(LDR_PC_gen(0b01, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
|
||||
#define LDU_gen(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | (opc)<<22 | ((imm9)&0x1ff)<<12 | (Rn)<<5 | (Rt))
|
||||
#define LDURx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b11, 0b01, imm9, Rn, Rt))
|
||||
#define LDURw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b10, 0b01, imm9, Rn, Rt))
|
||||
#define LDURxw_I9(Rt, Rn, imm9) EMIT(LDU_gen((rex.w)?0b11:0b10, 0b01, imm9, Rn, Rt))
|
||||
#define LDURz_I9(Rt, Rn, imm9) EMIT(LDU_gen((rex.is32bits)?0b10:0b11, 0b01, imm9, Rn, Rt))
|
||||
#define LDURH_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b01, 0b01, imm9, Rn, Rt))
|
||||
#define LDURB_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, 0b01, imm9, Rn, Rt))
|
||||
#define LDURSW_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b10, 0b10, imm9, Rn, Rt))
|
||||
#define LDURSHw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b01, 0b11, imm9, Rn, Rt))
|
||||
#define LDURSHx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b01, 0b10, imm9, Rn, Rt))
|
||||
#define LDURSHxw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b01, (rex.w)?0b10:0b11, imm9, Rn, Rt))
|
||||
#define LDURSBw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, 0b11, imm9, Rn, Rt))
|
||||
#define LDURSBx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, 0b10, imm9, Rn, Rt))
|
||||
#define LDURSBxw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, (rex.w)?0b10:0b11, imm9, Rn, Rt))
|
||||
|
||||
#define LDxw(A, B, C) if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}
|
||||
#define LDz(A, B, C) if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}
|
||||
#define LDx(A, B, C) if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}
|
||||
#define LDW(A, B, C) if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}
|
||||
#define LDH(A, B, C) if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}
|
||||
#define LDB(A, B, C) if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}
|
||||
#define LDSW(A, B, C) if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}
|
||||
#define LDSHxw(A, B, C) if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}
|
||||
#define LDSHx(A, B, C) if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}
|
||||
#define LDSHw(A, B, C) if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}
|
||||
#define LDSBxw(A, B, C) if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}
|
||||
#define LDSBx(A, B, C) if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}
|
||||
#define LDSBw(A, B, C) if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}
|
||||
#define STxw(A, B, C) if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}
|
||||
#define STz(A, B, C) if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}
|
||||
#define STx(A, B, C) if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}
|
||||
#define STW(A, B, C) if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}
|
||||
#define STH(A, B, C) if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}
|
||||
#define STB(A, B, C) if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}
|
||||
|
||||
// STR
|
||||
#define STR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b00<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
|
||||
#define STRx_S9_postindex(Rt, Rn, imm9) EMIT(STR_gen(0b11, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
@@ -256,6 +306,7 @@
|
||||
#define STRw_S9_preindex(Rt, Rn, imm9) EMIT(STR_gen(0b10, 0b00, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define STRxw_S9_postindex(Rt, Rn, imm9) EMIT(STR_gen(rex.w?0b11:0b10, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define STRB_S9_postindex(Rt, Rn, imm9) EMIT(STR_gen(0b00, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define STRH_S9_preindex(Rt, Rn, imm9) EMIT(STR_gen(0b01, 0b00, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define STRH_S9_postindex(Rt, Rn, imm9) EMIT(STR_gen(0b01, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
|
||||
#define ST_gen(size, op1, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b00<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -264,6 +315,15 @@
|
||||
#define STRB_U12(Rt, Rn, imm12) EMIT(ST_gen(0b00, 0b01, ((uint32_t)((imm12)))&0xfff, Rn, Rt))
|
||||
#define STRH_U12(Rt, Rn, imm12) EMIT(ST_gen(0b01, 0b01, ((uint32_t)((imm12)>>1))&0xfff, Rn, Rt))
|
||||
#define STRxw_U12(Rt, Rn, imm12) EMIT(ST_gen((rex.w)?0b11:0b10, 0b01, ((uint32_t)((imm12)>>(2+rex.w)))&0xfff, Rn, Rt))
|
||||
#define STRz_U12(Rt, Rn, imm12) EMIT(ST_gen((rex.is32bits)?0b10:0b11, 0b01, ((uint32_t)((imm12)>>(rex.is32bits?2:3)))&0xfff, Rn, Rt))
|
||||
|
||||
#define STU_gen(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | (opc)<<22 | ((imm9)&0x1ff)<<12 | (Rn)<<5 | (Rt))
|
||||
#define STURx_I9(Rt, Rn, imm9) EMIT(STU_gen(0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STURw_I9(Rt, Rn, imm9) EMIT(STU_gen(0b10, 0b00, imm9, Rn, Rt))
|
||||
#define STURxw_I9(Rt, Rn, imm9) EMIT(STU_gen((rex.w)?0b11:0b10, 0b00, imm9, Rn, Rt))
|
||||
#define STURz_I9(Rt, Rn, imm9) EMIT(STU_gen((rex.is32bits)?0b10:0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STURH_I9(Rt, Rn, imm9) EMIT(STU_gen(0b01, 0b00, imm9, Rn, Rt))
|
||||
#define STURB_I9(Rt, Rn, imm9) EMIT(STU_gen(0b00, 0b00, imm9, Rn, Rt))
|
||||
|
||||
#define STR_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b00<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
|
||||
#define STRx_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
@@ -274,33 +334,49 @@
|
||||
#define STRB_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRH_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRxw_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRz_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
|
||||
// LOAD/STORE PAIR
|
||||
#define MEMPAIR_gen(size, L, op2, imm7, Rt2, Rn, Rt) ((size)<<31 | 0b101<<27 | (op2)<<23 | (L)<<22 | (imm7)<<15 | (Rt2)<<10 | (Rn)<<5 | (Rt))
|
||||
|
||||
#define LDPx_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 1, 0b01, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 1, 0b01, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b01, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b01, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPx_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 1, 0b11, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 1, 0b11, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b11, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b11, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPx_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 1, 0b10, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 1, 0b10, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b10, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define LDPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 1, 0b10, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
|
||||
#define STPx_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 0, 0b01, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 0, 0b01, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b01, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define STPxw_S7_postindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b01, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define STPx_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 0, 0b11, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 0, 0b11, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b11, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define STPxw_S7_preindex(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b11, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
#define STPx_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(1, 0, 0b10, (((uint32_t)(imm))>>3)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(0, 0, 0b10, (((uint32_t)(imm))>>2)&0x7f, Rt2, Rn, Rt))
|
||||
#define STPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b10, (((uint32_t)(imm))>>(2+rex.w)), Rt2, Rn, Rt))
|
||||
#define STPxw_S7_offset(Rt, Rt2, Rn, imm) EMIT(MEMPAIR_gen(rex.w, 0, 0b10, (((uint32_t)(imm))>>(2+rex.w))&0x7f, Rt2, Rn, Rt))
|
||||
|
||||
// PUSH / POP helper
|
||||
#define POP1(reg) LDRx_S9_postindex(reg, xRSP, 8)
|
||||
#define PUSH1(reg) STRx_S9_preindex(reg, xRSP, -8)
|
||||
#define POP2(reg1, reg2) LDPx_S7_postindex(reg1, reg2, xRSP, 16)
|
||||
#define PUSH2(reg1, reg2) STPx_S7_preindex(reg2, reg1, xRSP, -16)
|
||||
|
||||
#define POP1_32(reg) LDRw_S9_postindex(reg, xRSP, 4)
|
||||
#define PUSH1_32(reg) STRw_S9_preindex(reg, xRSP, -4)
|
||||
#define POP2_32(reg1, reg2) LDPw_S7_postindex(reg1, reg2, xRSP, 8)
|
||||
#define PUSH2_32(reg1, reg2) STPw_S7_preindex(reg2, reg1, xRSP, -8)
|
||||
|
||||
#define POP1_16(reg) LDRH_S9_postindex(reg, xRSP, 2)
|
||||
#define PUSH1_16(reg) STRH_S9_preindex(reg, xRSP, -2)
|
||||
|
||||
#define POP1z(reg) if(rex.is32bits) {POP1_32(reg);} else {POP1(reg);}
|
||||
#define PUSH1z(reg) if(rex.is32bits) {PUSH1_32(reg);} else {PUSH1(reg);}
|
||||
#define POP2z(reg1, reg2) if(rex.is32bits) {POP2_32(reg1, reg2);} else {POP2(reg1, reg2);}
|
||||
#define PUSH2z(reg1, reg2) if(rex.is32bits) {PUSH2_32(reg1, reg2);} else {PUSH2(reg1, reg2);}
|
||||
|
||||
// LOAD/STORE Acquire Exclusive
|
||||
#define MEMAX_gen(size, L, Rs, Rn, Rt) ((size)<<30 | 0b001000<<24 | (L)<<22 | (Rs)<<16 | 1<<15 | 0b11111<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -358,6 +434,17 @@
|
||||
// Data Memory Barrier
|
||||
#define DMB_gen(CRm) (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b01<<5 | 0b11111)
|
||||
#define DMB_ISH() EMIT(DMB_gen(0b1011))
|
||||
#define DMB_SY() EMIT(DMB_gen(0b1111))
|
||||
|
||||
// Data Synchronization Barrier
|
||||
#define DSB_gen(CRm) (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b00<<5 | 0b11111)
|
||||
#define DSB_ISH() EMIT(DSB_gen(0b1011))
|
||||
#define DSB_ISHST() EMIT(DSB_gen(0b1010))
|
||||
#define DSB_SY() EMIT(DSB_gen(0b1111))
|
||||
|
||||
// Break
|
||||
#define BRK_gen(imm16) (0b11010100<<24 | 0b001<<21 | (((imm16)&0xffff)<<5))
|
||||
#define BRK(imm16) EMIT(BRK_gen(imm16))
|
||||
|
||||
// BR and Branches
|
||||
#define BR_gen(Z, op, A, M, Rn, Rm) (0b1101011<<25 | (Z)<<24 | (op)<<21 | 0b11111<<16 | (A)<<11 | (M)<<10 | (Rn)<<5 | (Rm))
|
||||
@@ -368,9 +455,11 @@
|
||||
#define CBNZx(Rt, imm19) EMIT(CB_gen(1, 1, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBNZw(Rt, imm19) EMIT(CB_gen(0, 1, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBNZxw(Rt, imm19) EMIT(CB_gen(rex.w, 1, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBNZz(Rt, imm19) EMIT(CB_gen(rex.is32bits?0:1, 1, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBZx(Rt, imm19) EMIT(CB_gen(1, 0, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBZw(Rt, imm19) EMIT(CB_gen(0, 0, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBZxw(Rt, imm19) EMIT(CB_gen(rex.w, 0, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define CBZz(Rt, imm19) EMIT(CB_gen(rex.is32bits?0:1, 0, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
|
||||
#define TB_gen(b5, op, b40, imm14, Rt) ((b5)<<31 | 0b011011<<25 | (op)<<24 | (b40)<<19 | (imm14)<<5 | (Rt))
|
||||
#define TBZ(Rt, bit, imm16) EMIT(TB_gen(((bit)>>5)&1, 0, (bit)&0x1f, ((imm16)>>2)&0x3FFF, Rt))
|
||||
@@ -415,9 +504,9 @@
|
||||
#define CSNEGx(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSNEGw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSNEGxw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CNEGx(Rd, Rn, cond) CSNEGx(Rn, Rn, Rn, invCond(cond))
|
||||
#define CNEGw(Rd, Rn, cond) CSNEGw(Rn, Rn, Rn, invCond(cond))
|
||||
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rn, Rn, Rn, invCond(cond))
|
||||
#define CNEGx(Rd, Rn, cond) CSNEGx(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGw(Rd, Rn, cond) CSNEGw(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rn, Rn, Rd, invCond(cond))
|
||||
|
||||
// AND / ORR
|
||||
#define LOGIC_gen(sf, opc, N, immr, imms, Rn, Rd) ((sf)<<31 | (opc)<<29 | 0b100100<<23 | (N)<<22 | (immr)<<16 | (imms)<<10 | (Rn)<<5 | Rd)
|
||||
@@ -462,9 +551,19 @@
|
||||
#define EORx_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(1, 0b10, 0b01, 0, Rm, lsr, Rn, Rd))
|
||||
#define EORw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(0, 0b10, 0b01, 0, Rm, lsr, Rn, Rd))
|
||||
#define EORxw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(rex.w, 0b10, 0b01, 0, Rm, lsr, Rn, Rd))
|
||||
#define EONx_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b10, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define EONw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 0b10, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define EONxw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(rex.w, 0b10, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define EONx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(1, 0b10, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define EONw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(0, 0b10, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define EONxw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(rex.w, 0b10, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define EONx_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(1, 0b10, 0b01, 1, Rm, lsr, Rn, Rd))
|
||||
#define EONw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(0, 0b10, 0b01, 1, Rm, lsr, Rn, Rd))
|
||||
#define EONxw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(rex.w, 0b10, 0b01, 1, Rm, lsr, Rn, Rd))
|
||||
#define MOVx_REG(Rd, Rm) ORRx_REG(Rd, xZR, Rm)
|
||||
#define MOVw_REG(Rd, Rm) ORRw_REG(Rd, xZR, Rm)
|
||||
#define MOVxw_REG(Rd, Rm) ORRxw_REG(Rd, xZR, Rm)
|
||||
#define MOVz_REG(Rd, Rm) if(rex.is32bits) {MOVw_REG(Rd, Rm);} else {MOVx_REG(Rd, Rm);}
|
||||
#define LSLw_IMM(Rd, Rm, lsl) ORRw_REG_LSL(Rd, xZR, Rm, lsl)
|
||||
#define LSLx_IMM(Rd, Rm, lsl) ORRx_REG_LSL(Rd, xZR, Rm, lsl)
|
||||
#define LSLxw_IMM(Rd, Rm, lsl) ORRxw_REG_LSL(Rd, xZR, Rm, lsl)
|
||||
@@ -487,6 +586,12 @@
|
||||
#define BICx_REG BICx
|
||||
#define BICw_REG BICw
|
||||
#define BICxw_REG BICxw
|
||||
#define BICx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(1, 0b00, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(0, 0b00, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICxw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(rex.w, 0b00, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICx_REG_LSR(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(1, 0b00, 0b01, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICw_REG_LSR(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(0, 0b00, 0b01, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICxw_REG_LSR(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(rex.w, 0b00, 0b01, 1, Rm, lsl, Rn, Rd))
|
||||
#define TSTx_REG(Rn, Rm) ANDSx_REG(xZR, Rn, Rm)
|
||||
#define TSTw_REG(Rn, Rm) ANDSw_REG(wZR, Rn, Rm)
|
||||
#define TSTxw_REG(Rn, Rm) ANDSxw_REG(xZR, Rn, Rm)
|
||||
@@ -502,12 +607,12 @@
|
||||
#define BFMx(Rd, Rn, immr, imms) EMIT(BFM_gen(1, 0b01, 1, immr, imms, Rn, Rd))
|
||||
#define BFMw(Rd, Rn, immr, imms) EMIT(BFM_gen(0, 0b01, 0, immr, imms, Rn, Rd))
|
||||
#define BFMxw(Rd, Rn, immr, imms) EMIT(BFM_gen(rex.w, 0b01, rex.w, immr, imms, Rn, Rd))
|
||||
#define BFIx(Rd, Rn, lsb, width) BFMx(Rd, Rn, ((-lsb)%64)&0x3f, (width)-1)
|
||||
#define BFIw(Rd, Rn, lsb, width) BFMw(Rd, Rn, ((-lsb)%32)&0x1f, (width)-1)
|
||||
#define BFIx(Rd, Rn, lsb, width) BFMx(Rd, Rn, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFIw(Rd, Rn, lsb, width) BFMw(Rd, Rn, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFIxw(Rd, Rn, lsb, width) if(rex.w) {BFIx(Rd, Rn, lsb, width);} else {BFIw(Rd, Rn, lsb, width);}
|
||||
#define BFCx(Rd, lsb, width) BFMx(Rd, xZR, ((-lsb)%64)&0x3f, (width)-1)
|
||||
#define BFCw(Rd, lsb, width) BFMw(Rd, xZR, ((-lsb)%32)&0x1f, (width)-1)
|
||||
#define BFCxw(Rd, lsb, width) BFMxw(Rd, xZR, rex.w?(((-lsb)%64)&0x3f):(((-lsb)%32)&0x1f), (width)-1)
|
||||
#define BFCx(Rd, lsb, width) BFMx(Rd, xZR, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFCw(Rd, lsb, width) BFMw(Rd, xZR, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFCxw(Rd, lsb, width) BFMxw(Rd, xZR, rex.w?(((-(lsb))%64)&0x3f):(((-(lsb))%32)&0x1f), (width)-1)
|
||||
// Insert lsb:width part of Rn into low part of Rd (leaving rest of Rd untouched)
|
||||
#define BFXILx(Rd, Rn, lsb, width) EMIT(BFM_gen(1, 0b01, 1, (lsb), (lsb)+(width)-1, Rn, Rd))
|
||||
// Insert lsb:width part of Rn into low part of Rd (leaving rest of Rd untouched)
|
||||
@@ -546,9 +651,9 @@
|
||||
#define SBFMx(Rd, Rn, immr, imms) EMIT(SBFM_gen(1, 1, immr, imms, Rn, Rd))
|
||||
#define SBFMw(Rd, Rn, immr, imms) EMIT(SBFM_gen(0, 0, immr, imms, Rn, Rd))
|
||||
#define SBFMxw(Rd, Rn, immr, imms) EMIT(SBFM_gen(rex.w, rex.w, immr, imms, Rn, Rd))
|
||||
#define SBFXx(Rd, Rn, lsb, width) SBFMx(Rd, Rn, lsb, lsb+width-1)
|
||||
#define SBFXw(Rd, Rn, lsb, width) SBFMw(Rd, Rn, lsb, lsb+width-1)
|
||||
#define SBFXxw(Rd, Rn, lsb, width) SBFMxw(Rd, Rn, lsb, lsb+width-1)
|
||||
#define SBFXx(Rd, Rn, lsb, width) SBFMx(Rd, Rn, lsb, (lsb)+(width)-1)
|
||||
#define SBFXw(Rd, Rn, lsb, width) SBFMw(Rd, Rn, lsb, (lsb)+(width)-1)
|
||||
#define SBFXxw(Rd, Rn, lsb, width) SBFMxw(Rd, Rn, lsb, (lsb)+(width)-1)
|
||||
#define SXTBx(Rd, Rn) SBFMx(Rd, Rn, 0, 7)
|
||||
#define SXTBw(Rd, Rn) SBFMw(Rd, Rn, 0, 7)
|
||||
#define SXTHx(Rd, Rn) SBFMx(Rd, Rn, 0, 15)
|
||||
@@ -644,6 +749,10 @@
|
||||
#define REV16w(Rd, Rn) EMIT(REV_gen(0, 0b01, Rn, Rd))
|
||||
#define REV16x(Rd, Rn) EMIT(REV_gen(1, 0b01, Rn, Rd))
|
||||
|
||||
// UDF
|
||||
#define UDF_gen(imm16) ((imm16)&0xffff)
|
||||
#define UDF(imm16) EMIT(UDF_gen(imm16))
|
||||
|
||||
// MRS
|
||||
#define MRS_gen(L, o0, op1, CRn, CRm, op2, Rt) (0b1101010100<<22 | (L)<<21 | 1<<20 | (o0)<<19 | (op1)<<16 | (CRn)<<12 | (CRm)<<8 | (op2)<<5 | (Rt))
|
||||
// mrs x0, nzcv : 1101010100 1 1 1 011 0100 0010 000 00000 o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0010(2) op2=0
|
||||
@@ -679,34 +788,45 @@
|
||||
|
||||
// VLDR
|
||||
#define VMEM_gen(size, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | 0b01<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
// imm14 must be 3-aligned
|
||||
// imm13 must be 1-aligned
|
||||
#define VLDR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b01, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
// imm14 must be 2-aligned
|
||||
#define VLDR32_U12(Dt, Rn, imm14) EMIT(VMEM_gen(0b10, 0b01, ((uint32_t)((imm14)>>2))&0xfff, Rn, Dt))
|
||||
// imm15 must be 3-aligned
|
||||
#define VLDR64_U12(Dt, Rn, imm15) EMIT(VMEM_gen(0b11, 0b01, ((uint32_t)((imm15)>>3))&0xfff, Rn, Dt))
|
||||
// imm16 must be 4-aligned
|
||||
#define VLDR128_U12(Qt, Rn, imm16) EMIT(VMEM_gen(0b00, 0b11, ((uint32_t)((imm16)>>4))&0xfff, Rn, Qt))
|
||||
// (imm14) must be 3-aligned
|
||||
#define VSTR32_U12(Dt, Rn, imm14) EMIT(VMEM_gen(0b10, 0b00, ((uint32_t)(imm14>>2))&0xfff, Rn, Dt))
|
||||
#define VSTR32_U12(Dt, Rn, imm14) EMIT(VMEM_gen(0b10, 0b00, ((uint32_t)((imm14)>>2))&0xfff, Rn, Dt))
|
||||
// (imm15) must be 3-aligned
|
||||
#define VSTR64_U12(Dt, Rn, imm15) EMIT(VMEM_gen(0b11, 0b00, ((uint32_t)(imm15>>3))&0xfff, Rn, Dt))
|
||||
#define VSTR64_U12(Dt, Rn, imm15) EMIT(VMEM_gen(0b11, 0b00, ((uint32_t)((imm15)>>3))&0xfff, Rn, Dt))
|
||||
// imm16 must be 4-aligned
|
||||
#define VSTR128_U12(Qt, Rn, imm16) EMIT(VMEM_gen(0b00, 0b10, ((uint32_t)((imm16)>>4))&0xfff, Rn, Qt))
|
||||
// (imm14) must be 1-aligned
|
||||
#define VSTR16_U12(Ht, Rn, imm14) EMIT(VMEM_gen(0b01, 0b00, ((uint32_t)(imm14>>1))&0xfff, Rn, Ht))
|
||||
// (imm13) must be 1-aligned
|
||||
#define VSTR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b00, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
|
||||
#define VMEMUR_vector(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (Rn)<<5 | (Rt))
|
||||
// signed offset, no alignement!
|
||||
#define VLDR8_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR16_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b01, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR32_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b10, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR64_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b11, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR128_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b11, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR8_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR16_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b01, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR32_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b10, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VLDR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b11, (imm9)&0b111111111, Rn, Vt))
|
||||
// signed offset, no alignement!
|
||||
#define VSTR8_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR16_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b01, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR32_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b10, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR8_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR16_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b01, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR32_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b10, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
|
||||
|
||||
#define VLD128(A, B, C) if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}
|
||||
#define VLD64(A, B, C) if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}
|
||||
#define VLD32(A, B, C) if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}
|
||||
#define VLD16(A, B, C) if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}
|
||||
#define VST128(A, B, C) if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}
|
||||
#define VST64(A, B, C) if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}
|
||||
#define VST32(A, B, C) if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}
|
||||
#define VST16(A, B, C) if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}
|
||||
|
||||
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
@@ -721,18 +841,18 @@
|
||||
#define VMEM_REG_gen(size, opc, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
|
||||
|
||||
#define VLDR32_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR32_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR32_REG_LSL2(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR64_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR64_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 0, Rn, Qt))
|
||||
#define VLDR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 1, Rn, Qt))
|
||||
|
||||
#define VSTR32_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR32_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR32_REG_LSL2(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR64_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR64_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 0, Rn, Qt))
|
||||
#define VSTR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 1, Rn, Qt))
|
||||
|
||||
#define VLDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | 1<<26 | (imm19)<<5 | (Rt))
|
||||
#define VLDR32_literal(Vt, imm19) EMIT(VLDR_PC_gen(0b00, ((imm19)>>2)&0x7FFFF, Vt))
|
||||
@@ -845,6 +965,15 @@
|
||||
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
|
||||
// Reverse elements in 64-bit doublewords (vector). This instruction reverses the order of 8-bit, 16-bit, or 32-bit elements in each doubleword
|
||||
#define VREVx_vector(Q, U, size, o0, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | (o0)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VREV64_32(Vd, Vn) EMIT(VREVx_vector(0, 0, 0b10, 0, Vn, Vd))
|
||||
#define VREV64_16(Vd, Vn) EMIT(VREVx_vector(0, 0, 0b01, 0, Vn, Vd))
|
||||
#define VREV64_8(Vd, Vn) EMIT(VREVx_vector(0, 0, 0b00, 0, Vn, Vd))
|
||||
#define VREV64Q_32(Vd, Vn) EMIT(VREVx_vector(1, 0, 0b10, 0, Vn, Vd))
|
||||
#define VREV64Q_16(Vd, Vn) EMIT(VREVx_vector(1, 0, 0b01, 0, Vn, Vd))
|
||||
#define VREV64Q_8(Vd, Vn) EMIT(VREVx_vector(1, 0, 0b00, 0, Vn, Vd))
|
||||
|
||||
// Integer MATH
|
||||
#define ADDSUB_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b10000<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VADDQ_8(Vd, Vn, Vm) EMIT(ADDSUB_vector(1, 0, 0b00, Vm, Vn, Vd))
|
||||
@@ -862,6 +991,10 @@
|
||||
#define VSUB_16(Vd, Vn, Vm) EMIT(ADDSUB_vector(0, 1, 0b01, Vm, Vn, Vd))
|
||||
#define VSUB_32(Vd, Vn, Vm) EMIT(ADDSUB_vector(0, 1, 0b10, Vm, Vn, Vd))
|
||||
|
||||
#define ADDSUB_scalar(U, size, Rm, Rn, Rd) (01<<30 | (U)<<29 | 0b11110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b10000<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define ADD_64(Vd, Vn, Vm) EMIT(ADDSUB_scalar(0, 0b11, Vm, Vn, Vd))
|
||||
#define SUB_64(Vd, Vn, Vm) EMIT(ADDSUB_scalar(1, 0b11, Vm, Vn, Vd))
|
||||
|
||||
#define NEGABS_vector(Q, U, size, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b01011<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define NEG_8(Vd, Vn) EMIT(NEGABS_vector(0, 1, 0b00, Vn, Vd))
|
||||
#define NEG_16(Vd, Vn) EMIT(NEGABS_vector(0, 1, 0b01, Vn, Vd))
|
||||
@@ -984,6 +1117,12 @@
|
||||
#define FADDP_vector(Q, sz, Rm, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11010<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFADDPQS(Vd, Vn, Vm) EMIT(FADDP_vector(1, 0, Vm, Vn, Vd))
|
||||
#define VFADDPQD(Vd, Vn, Vm) EMIT(FADDP_vector(1, 1, Vm, Vn, Vd))
|
||||
#define VFADDPS(Vd, Vn, Vm) EMIT(FADDP_vector(0, 0, Vm, Vn, Vd))
|
||||
#define VFADDPD(Vd, Vn, Vm) EMIT(FADDP_vector(0, 1, Vm, Vn, Vd))
|
||||
|
||||
#define FADDP_scalar(sz, Rn, Rd) (0b01<<30 | 1<<29 | 0b11110<<24 | (sz)<<22 | 0b11000<<17 | 0b01101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define FADDPS(Sd, Sn) EMIT(FADDP_scalar(0, Sn, Sd))
|
||||
#define FADDPD(Dd, Dn) EMIT(FADDP_scalar(1, Dn, Dd))
|
||||
|
||||
// NEG / ABS
|
||||
#define FNEGABS_scalar(type, opc, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | (opc)<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1007,7 +1146,7 @@
|
||||
#define FMLA_vector(Q, op, sz, Rm, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (op)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFMLAS(Sd, Sn, Sm) EMIT(FMLA_vector(0, 0, 0, Sm, Sn, Sd))
|
||||
#define VFMLAQS(Sd, Sn, Sm) EMIT(FMLA_vector(1, 0, 0, Sm, Sn, Sd))
|
||||
#define CFMLAQD(Dd, Dn, Dm) EMIT(FMLA_vector(1, 0, 1, Dm, Dn, Dd))
|
||||
#define VFMLAQD(Dd, Dn, Dm) EMIT(FMLA_vector(1, 0, 1, Dm, Dn, Dd))
|
||||
|
||||
// DIV
|
||||
#define FDIV_vector(Q, sz, Rm, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11111<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1205,6 +1344,12 @@
|
||||
#define FCVT_D_S(Dd, Sn) EMIT(FCVT_precision(0b00, 0b01, Sn, Dd))
|
||||
#define FCVT_S_D(Sd, Dn) EMIT(FCVT_precision(0b01, 0b00, Dn, Sd))
|
||||
|
||||
#define FCVTN_vector(Q, sz, Rn, Rd) ((Q)<<30 | 0<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b10110<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert Vn from 2*Double to lower Vd as 2*float and clears the upper half, use FPCR rounding
|
||||
#define FCVTN(Vd, Vn) EMIT(FCVTN_vector(0, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Double to higher Vd as 2*float, use FPCR rounding
|
||||
#define FCVTN2(Vd, Vn) EMIT(FCVTN_vector(1, 1, Vn, Vd))
|
||||
|
||||
#define FCVTXN_vector(Q, sz, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b10110<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert Vn from 2*Double to lower Vd as 2*float and clears the upper half
|
||||
#define FCVTXN(Vd, Vn) EMIT(FCVTXN_vector(0, 1, Vn, Vd))
|
||||
@@ -1224,7 +1369,9 @@
|
||||
#define SCVTFDx(Dd, Xn) EMIT(SCVTF_scalar(1, 0b01, 0b00, 0b010, Xn, Dd))
|
||||
|
||||
#define SCVTF_vector_scalar(U, sz, Rn, Rd) (1<<30 | (U)<<29 | 0b11110<<24 | (sz)<<22 | 0b10000<<17 | 0b11101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert Vn from i32 to Vd float
|
||||
#define SCVTFSS(Vd, Vn) EMIT(SCVTF_vector_scalar(0, 0, Vn, Vd))
|
||||
// Convert Vn from i64 to Vd double
|
||||
#define SCVTFDD(Vd, Vn) EMIT(SCVTF_vector_scalar(0, 1, Vn, Vd))
|
||||
|
||||
#define SCVTF_vector(Q, U, sz, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b11101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1238,16 +1385,15 @@
|
||||
#define VFRINTIS(Vd,Vn) EMIT(FRINT_vector(0, 1, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINTISQ(Vd,Vn) EMIT(FRINT_vector(1, 1, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINTIDQ(Vd,Vn) EMIT(FRINT_vector(1, 1, 1, 1, 1, Vn, Vd))
|
||||
// round with mode, mode is 0 = TieEven, 1=+inf, 2=-inf, 3=zero
|
||||
#define VFRINTRDQ(Vd,Vn, mode) EMIT(FRINT_vector(1, 0, (mode)&1, 1, ((mode)>>1)&1, Vn, Vd))
|
||||
// round with mode, mode is 0 = TieEven, 1=+inf, 2=-inf, 3=zero
|
||||
#define VFRINTRSQ(Vd,Vn, mode) EMIT(FRINT_vector(1, 0, (mode)&1, 0, ((mode)>>1)&1, Vn, Vd))
|
||||
#define VFRINTRS(Vd, Vn, mode) EMIT(FRINT_vector(0, 0, (mode)&1, 0, ((mode)>>1)&1, Vn, Vd))
|
||||
|
||||
#define FRINTxx_scalar(type, op, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b0100<<17 | (op)<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FRINT32ZS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b00, Sn, Sd))
|
||||
#define FRINT32ZD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b00, Dn, Dd))
|
||||
#define FRINT32XS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b01, Sn, Sd))
|
||||
#define FRINT32XD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b01, Dn, Dd))
|
||||
#define FRINT64ZS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b10, Sn, Sd))
|
||||
#define FRINT64ZD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b10, Dn, Dd))
|
||||
#define FRINT64XS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b11, Sn, Sd))
|
||||
#define FRINT64XD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b11, Dn, Dd))
|
||||
#define FRINTI_scalar(type, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b001<<18 | 0b111<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FRINTIS(Sd, Sn) EMIT(FRINTI_scalar(0b00, Sn, Sd))
|
||||
#define FRINTID(Dd, Dn) EMIT(FRINTI_scalar(0b01, Dn, Dd))
|
||||
|
||||
#define FRINT_scalar(type, rmode, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b001<<18 | (rmode)<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
// round toward 0 (truncate)
|
||||
@@ -1319,14 +1465,23 @@
|
||||
#define VUZP1Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 0, Rn, Rt))
|
||||
#define VUZP2Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 1, Rn, Rt))
|
||||
|
||||
#define DUP_gen(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VDUP_8(Vd, Vn, idx) EMIT(DUP_gen(0, ((idx)<<1|1), Vn, Vd))
|
||||
#define VDUPQ_8(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<1|1), Vn, Vd))
|
||||
#define VDUP_16(Vd, Vn, idx) EMIT(DUP_gen(0, ((idx)<<2|0b10), Vn, Vd))
|
||||
#define VDUPQ_16(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<2|0b10), Vn, Vd))
|
||||
#define VDUP_32(Vd, Vn, idx) EMIT(DUP_gen(0, ((idx)<<3|0b100), Vn, Vd))
|
||||
#define VDUPQ_32(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<3|0b100), Vn, Vd))
|
||||
#define VDUPQ_64(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<4|0b1000), Vn, Vd))
|
||||
#define DUP_element(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VDUP_8(Vd, Vn, idx) EMIT(DUP_element(0, ((idx)<<1|1), Vn, Vd))
|
||||
#define VDUPQ_8(Vd, Vn, idx) EMIT(DUP_element(1, ((idx)<<1|1), Vn, Vd))
|
||||
#define VDUP_16(Vd, Vn, idx) EMIT(DUP_element(0, ((idx)<<2|0b10), Vn, Vd))
|
||||
#define VDUPQ_16(Vd, Vn, idx) EMIT(DUP_element(1, ((idx)<<2|0b10), Vn, Vd))
|
||||
#define VDUP_32(Vd, Vn, idx) EMIT(DUP_element(0, ((idx)<<3|0b100), Vn, Vd))
|
||||
#define VDUPQ_32(Vd, Vn, idx) EMIT(DUP_element(1, ((idx)<<3|0b100), Vn, Vd))
|
||||
#define VDUPQ_64(Vd, Vn, idx) EMIT(DUP_element(1, ((idx)<<4|0b1000), Vn, Vd))
|
||||
|
||||
#define DUP_general(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 0b11<<10 | (Rn)<<5 | (Rd))
|
||||
#define VDUPB(Vd, Wn) EMIT(DUP_general(0, 0b1, Wn, Vd))
|
||||
#define VDUPQB(Vd, Wn) EMIT(DUP_general(1, 0b1, Wn, Vd))
|
||||
#define VDUPH(Vd, Wn) EMIT(DUP_general(0, 0b10, Wn, Vd))
|
||||
#define VDUPQH(Vd, Wn) EMIT(DUP_general(1, 0b10, Wn, Vd))
|
||||
#define VDUPS(Vd, Wn) EMIT(DUP_general(0, 0b100, Wn, Vd))
|
||||
#define VDUPQS(Vd, Wn) EMIT(DUP_general(1, 0b100, Wn, Vd))
|
||||
#define VDUPQD(Vd, Xn) EMIT(DUP_general(1, 0b1000, Xn, Vd))
|
||||
|
||||
// TBL
|
||||
#define TBL_gen(Q, Rm, len, op, Rn, Rd) ((Q)<<30 | 0b001110<<24 | (Rm)<<16 | (len)<<13 | (op)<<12 | (Rn)<<5 | (Rd))
|
||||
@@ -1340,13 +1495,13 @@
|
||||
//Use Rm[] to pick from Rn, Rn+1, Rn+2, Rn+3 element and store in Rd. Out-of-range element gets 0
|
||||
#define VTBLQ4_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b11, 0, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ1_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b00, 0, Rn, Rd))
|
||||
#define VTBXQ1_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b00, 1, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn, Rn+1 element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ2_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b01, 0, Rn, Rd))
|
||||
#define VTBXQ2_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b01, 1, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn, Rn+1, Rn+2 element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ3_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b10, 0, Rn, Rd))
|
||||
#define VTBXQ3_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b10, 1, Rn, Rd))
|
||||
//Use Rm[] to pick from Rn, Rn+1, Rn+2, Rn+3 element and store in Rd. Out-of-range element stay untouched
|
||||
#define VTBXQ4_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b11, 0, Rn, Rd))
|
||||
#define VTBXQ4_8(Rd, Rn, Rm) EMIT(TBL_gen(1, Rm, 0b11, 1, Rn, Rd))
|
||||
|
||||
// TRN
|
||||
#define TRN_gen(Q, size, Rm, op, Rn, Rd) ((Q)<<30 | 0b001110<<24 | (size)<<22 | (Rm)<<16 | (op)<<14 | 0b10<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1354,7 +1509,6 @@
|
||||
#define VTRNQ1_32(Vd, Vn, Vm) EMIT(TRN_gen(1, 0b10, Vm, 0, Vn, Vd))
|
||||
#define VTRNQ1_16(Vd, Vn, Vm) EMIT(TRN_gen(1, 0b01, Vm, 0, Vn, Vd))
|
||||
#define VTRNQ1_8(Vd, Vn, Vm) EMIT(TRN_gen(1, 0b00, Vm, 0, Vn, Vd))
|
||||
#define VSWP(Vd, Vn) VTRNQ1_64(Vd, Vn, Vn)
|
||||
#define VTRNQ2_64(Vd, Vn, Vm) EMIT(TRN_gen(1, 0b11, Vm, 1, Vn, Vd))
|
||||
#define VTRNQ2_32(Vd, Vn, Vm) EMIT(TRN_gen(1, 0b10, Vm, 1, Vn, Vd))
|
||||
#define VTRNQ2_16(Vd, Vn, Vm) EMIT(TRN_gen(1, 0b01, Vm, 1, Vn, Vd))
|
||||
@@ -1463,6 +1617,15 @@
|
||||
#define CMEQQ_0_16(Rd, Rn) EMIT(CMEQ_0_vector(1, 0b01, Rn, Rd))
|
||||
#define CMEQQ_0_32(Rd, Rn) EMIT(CMEQ_0_vector(1, 0b10, Rn, Rd))
|
||||
#define CMEQQ_0_64(Rd, Rn) EMIT(CMEQ_0_vector(1, 0b11, Rn, Rd))
|
||||
// Greater Than 0
|
||||
#define CMCond_0_vector(Q, U, size, op, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b0100<<13 | (op)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define CMGT_0_8(Rd, Rn) EMIT(CMCond_0_vector(0, 0, 0b00, 0, Rn, Rd))
|
||||
#define CMGT_0_16(Rd, Rn) EMIT(CMCond_0_vector(0, 0, 0b01, 0, Rn, Rd))
|
||||
#define CMGT_0_32(Rd, Rn) EMIT(CMCond_0_vector(0, 0, 0b10, 0, Rn, Rd))
|
||||
#define CMGTQ_0_8(Rd, Rn) EMIT(CMCond_0_vector(1, 0, 0b00, 0, Rn, Rd))
|
||||
#define CMGTQ_0_16(Rd, Rn) EMIT(CMCond_0_vector(1, 0, 0b01, 0, Rn, Rd))
|
||||
#define CMGTQ_0_32(Rd, Rn) EMIT(CMCond_0_vector(1, 0, 0b10, 0, Rn, Rd))
|
||||
#define CMGTQ_0_64(Rd, Rn) EMIT(CMCond_0_vector(1, 0, 0b11, 0, Rn, Rd))
|
||||
|
||||
// Vector Float CMP
|
||||
// EQual
|
||||
@@ -1613,10 +1776,19 @@
|
||||
#define UADDLV_16(Rd, Rn) EMIT(ADDLV_vector(0, 1, 0b01, Rn, Rd))
|
||||
#define UADDLV_32(Rd, Rn) EMIT(ADDLV_vector(0, 1, 0b10, Rn, Rd))
|
||||
|
||||
// Population Count per byte
|
||||
#define CNT_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b00101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define CNT_8(Rd, Rn) EMIT(CNT_vector(0, 0b00, Rn, Rd))
|
||||
#define CNTQ_8(Rd, Rn) EMIT(CNT_vector(1, 0b00, Rn, Rd))
|
||||
|
||||
// MOV Immediate
|
||||
#define MOVI_vector(Q, op, abc, cmode, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
#define MOVIQ_8(Rd, imm8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_16(Rd, imm8, lsl8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b1000|((lsl8)?0b10:0), ((imm8)&0b11111), Rd))
|
||||
#define MOVI_8(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_16(Rd, imm8, lsl8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1000|((lsl8)?0b10:0), ((imm8)&0b11111), Rd))
|
||||
#define MOVI_32(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b0000, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_64(Rd, imm8) EMIT(MOVI_vector(0, 1, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
|
||||
// SHLL and eXtend Long
|
||||
#define SHLL_vector(Q, U, immh, immb, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b10100<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1686,35 +1858,35 @@
|
||||
#define SMAX_8(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b00, Vm, 0, Vn, Vd))
|
||||
#define SMAX_16(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b01, Vm, 0, Vn, Vd))
|
||||
#define SMAX_32(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b10, Vm, 0, Vn, Vd))
|
||||
#define SMAX_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b11, Vm, 0, Vn, Vd))
|
||||
//#define SMAX_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b11, Vm, 0, Vn, Vd))
|
||||
#define UMAX_8(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b00, Vm, 0, Vn, Vd))
|
||||
#define UMAX_16(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b01, Vm, 0, Vn, Vd))
|
||||
#define UMAX_32(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b10, Vm, 0, Vn, Vd))
|
||||
#define UMAX_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b11, Vm, 0, Vn, Vd))
|
||||
//#define UMAX_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b11, Vm, 0, Vn, Vd))
|
||||
#define SMIN_8(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b00, Vm, 1, Vn, Vd))
|
||||
#define SMIN_16(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b01, Vm, 1, Vn, Vd))
|
||||
#define SMIN_32(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b10, Vm, 1, Vn, Vd))
|
||||
#define SMIN_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b11, Vm, 1, Vn, Vd))
|
||||
//#define SMIN_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 0, 0b11, Vm, 1, Vn, Vd))
|
||||
#define UMIN_8(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b00, Vm, 1, Vn, Vd))
|
||||
#define UMIN_16(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b01, Vm, 1, Vn, Vd))
|
||||
#define UMIN_32(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b10, Vm, 1, Vn, Vd))
|
||||
#define UMIN_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b11, Vm, 1, Vn, Vd))
|
||||
//#define UMIN_64(Vd, Vn, Vm) EMIT(MINMAX_vector(0, 1, 0b11, Vm, 1, Vn, Vd))
|
||||
#define SMAXQ_8(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b00, Vm, 0, Vn, Vd))
|
||||
#define SMAXQ_16(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b01, Vm, 0, Vn, Vd))
|
||||
#define SMAXQ_32(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b10, Vm, 0, Vn, Vd))
|
||||
#define SMAXQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b11, Vm, 0, Vn, Vd))
|
||||
//#define SMAXQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b11, Vm, 0, Vn, Vd))
|
||||
#define UMAXQ_8(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b00, Vm, 0, Vn, Vd))
|
||||
#define UMAXQ_16(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b01, Vm, 0, Vn, Vd))
|
||||
#define UMAXQ_32(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b10, Vm, 0, Vn, Vd))
|
||||
#define UMAXQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b11, Vm, 0, Vn, Vd))
|
||||
//#define UMAXQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b11, Vm, 0, Vn, Vd))
|
||||
#define SMINQ_8(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b00, Vm, 1, Vn, Vd))
|
||||
#define SMINQ_16(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b01, Vm, 1, Vn, Vd))
|
||||
#define SMINQ_32(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b10, Vm, 1, Vn, Vd))
|
||||
#define SMINQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b11, Vm, 1, Vn, Vd))
|
||||
//#define SMINQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 0, 0b11, Vm, 1, Vn, Vd))
|
||||
#define UMINQ_8(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b00, Vm, 1, Vn, Vd))
|
||||
#define UMINQ_16(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b01, Vm, 1, Vn, Vd))
|
||||
#define UMINQ_32(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b10, Vm, 1, Vn, Vd))
|
||||
#define UMINQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b11, Vm, 1, Vn, Vd))
|
||||
//#define UMINQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b11, Vm, 1, Vn, Vd))
|
||||
|
||||
// HADD vector
|
||||
#define HADD_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1760,7 +1932,7 @@
|
||||
#define SQDMULHQ_16(Vd, Vn, Vm) EMIT(QDMULH_vector(1, 0, 0b01, Vm, Vn, Vd))
|
||||
#define SQDMULHQ_32(Vd, Vn, Vm) EMIT(QDMULH_vector(1, 0, 0b10, Vm, Vn, Vd))
|
||||
|
||||
// AES extensions
|
||||
// AES extension
|
||||
#define AES_gen(D, Rn, Rd) (0b01001110<<24 | 0b00<<22 | 0b10100<<17 | 0b0010<<13 | (D)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define AESD(Vd, Vn) EMIT(AES_gen(1, Vn, Vd))
|
||||
#define AESE(Vd, Vn) EMIT(AES_gen(0, Vn, Vd))
|
||||
@@ -1769,4 +1941,279 @@
|
||||
#define AESIMC(Vd, Vn) EMIT(AESMC_gen(1, Vn, Vd))
|
||||
#define AESMC(Vd, Vn) EMIT(AESMC_gen(0, Vn, Vd))
|
||||
|
||||
// PMULL extension is PMULL_128
|
||||
#define PMULL_gen(Q, size, Rm, Rn, Rd) (0<<31 | (Q)<<30 | 0b001110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b1110<<12 | (Rn)<<5 | (Rd))
|
||||
#define PMULL(Rd, Rn, Rm) EMIT(PMULL_gen(0, 0b00, Rm, Rn, Rd))
|
||||
#define PMULL2(Rd, Rn, Rm) EMIT(PMULL_gen(1, 0b00, Rm, Rn, Rd))
|
||||
#define PMULL_128(Rd, Rn, Rm) EMIT(PMULL_gen(0, 0b11, Rm, Rn, Rd))
|
||||
#define PMULL2_128(Rd, Rn, Rm) EMIT(PMULL_gen(1, 0b11, Rm, Rn, Rd))
|
||||
|
||||
// ATOMIC extension
|
||||
#define ATOMIC_gen(size, A, R, Rs, opc, Rn, Rt) ((size)<<30 | 0b111<<27 | (A)<<23 | (R)<<22 | 1<<21 | (Rs)<<16 | (opc)<<12 | (Rn)<<5 | (Rt))
|
||||
// Atomic ADD
|
||||
#define LDADDxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b000, Rn, Rt))
|
||||
#define STADDxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b000, Rn, 0b11111))
|
||||
#define STADDLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b000, Rn, 0b11111))
|
||||
#define LDADDB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b000, Rn, Rt))
|
||||
#define STADDB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b000, Rn, 0b11111))
|
||||
#define STADDLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b000, Rn, 0b11111))
|
||||
#define LDADDH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b000, Rn, Rt))
|
||||
#define LDADDLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b000, Rn, Rt))
|
||||
#define STADDH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b000, Rn, 0b11111))
|
||||
#define STADDLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b000, Rn, 0b11111))
|
||||
// Atomic AND with complement (i.e. BIC)
|
||||
#define LDCLRxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b001, Rn, Rt))
|
||||
#define STCLRxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b001, Rn, 0b11111))
|
||||
#define STCLRLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b001, Rn, 0b11111))
|
||||
#define LDCLRB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b001, Rn, Rt))
|
||||
#define STCLRB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b001, Rn, 0b11111))
|
||||
#define STCLRLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b001, Rn, 0b11111))
|
||||
#define LDCLRH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b001, Rn, Rt))
|
||||
#define LDCLRLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b001, Rn, Rt))
|
||||
#define STCLRH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b001, Rn, 0b11111))
|
||||
#define STCLRLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b001, Rn, 0b11111))
|
||||
// Atomic EOR
|
||||
#define LDEORxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b010, Rn, Rt))
|
||||
#define STEORxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b010, Rn, 0b11111))
|
||||
#define STEORLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b010, Rn, 0b11111))
|
||||
#define LDEORB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b010, Rn, Rt))
|
||||
#define STEORB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b010, Rn, 0b11111))
|
||||
#define STEORLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b010, Rn, 0b11111))
|
||||
#define LDEORH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b010, Rn, Rt))
|
||||
#define LDEORLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b010, Rn, Rt))
|
||||
#define STEORH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b010, Rn, 0b11111))
|
||||
#define STEORLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b010, Rn, 0b11111))
|
||||
// Atomic OR
|
||||
#define LDSETxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b011, Rn, Rt))
|
||||
#define STSETxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b011, Rn, 0b11111))
|
||||
#define STSETLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b011, Rn, 0b11111))
|
||||
#define LDSETB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b011, Rn, Rt))
|
||||
#define STSETB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b011, Rn, 0b11111))
|
||||
#define STSETLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b011, Rn, 0b11111))
|
||||
#define LDSETH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b011, Rn, Rt))
|
||||
#define LDSETLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b011, Rn, Rt))
|
||||
#define STSETH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b011, Rn, 0b11111))
|
||||
#define STSETLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b011, Rn, 0b11111))
|
||||
// Atomic Signel Max
|
||||
#define LDSMAXxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b100, Rn, Rt))
|
||||
#define STSMAXxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b100, Rn, 0b11111))
|
||||
#define STSMAXLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b100, Rn, 0b11111))
|
||||
#define LDSMAXB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b100, Rn, Rt))
|
||||
#define STSMAXB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b100, Rn, 0b11111))
|
||||
#define STSMAXLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b100, Rn, 0b11111))
|
||||
#define LDSMAXH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b100, Rn, Rt))
|
||||
#define STSMAXH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b100, Rn, 0b11111))
|
||||
#define STSMAXLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b100, Rn, 0b11111))
|
||||
// Atomic Signed Min
|
||||
#define LDSMINxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b101, Rn, Rt))
|
||||
#define STSMINxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b101, Rn, 0b11111))
|
||||
#define STSMINLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b101, Rn, 0b11111))
|
||||
#define LDSMINB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b101, Rn, Rt))
|
||||
#define STSMINB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b101, Rn, 0b11111))
|
||||
#define STSMINLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b101, Rn, 0b11111))
|
||||
#define LDSMINH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b101, Rn, Rt))
|
||||
#define LDSMINLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b101, Rn, Rt))
|
||||
#define STSMINH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b101, Rn, 0b11111))
|
||||
#define STSMINLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b101, Rn, 0b11111))
|
||||
// Atomic Unsigned Max
|
||||
#define LDUMAXxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b110, Rn, Rt))
|
||||
#define STUMAXxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b110, Rn, 0b11111))
|
||||
#define STUMAXLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b110, Rn, 0b11111))
|
||||
#define LDUMAXB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b110, Rn, Rt))
|
||||
#define STUMAXB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b110, Rn, 0b11111))
|
||||
#define STUMAXLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b110, Rn, 0b11111))
|
||||
#define LDUMAXH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b110, Rn, Rt))
|
||||
#define LDUMAXLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b110, Rn, Rt))
|
||||
#define STUMAXH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b110, Rn, 0b11111))
|
||||
#define STUMAXLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b110, Rn, 0b11111))
|
||||
// Atomic Unsigned Min
|
||||
#define LDUMINxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINLxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b111, Rn, Rt))
|
||||
#define STUMINxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b111, Rn, 0b11111))
|
||||
#define STUMINLxw(Rs, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 1, Rs, 0b111, Rn, 0b11111))
|
||||
#define LDUMINB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINAB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 0, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINALB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 1, 1, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINLB(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b111, Rn, Rt))
|
||||
#define STUMINB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 0, Rs, 0b111, Rn, 0b11111))
|
||||
#define STUMINLB(Rs, Rn) EMIT(ATOMIC_gen(0b00, 0, 1, Rs, 0b111, Rn, 0b11111))
|
||||
#define LDUMINH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINAH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 0, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINALH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 1, 1, Rs, 0b111, Rn, Rt))
|
||||
#define LDUMINLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b111, Rn, Rt))
|
||||
#define STUMINH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b111, Rn, 0b11111))
|
||||
#define STUMINLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b111, Rn, 0b11111))
|
||||
|
||||
// SWAPxx(Xs, Xt, Xn) : [Xn] => Xt, Xs => [Xn]
|
||||
#define SWAP_gen(size, A, R, Rs, Rn, Rt) ((size)<<30 | 0b111<<27 | (A)<<23 | (R)<<22 | 1<<21 | (Rs)<<16 | 1<<15 | (Rn)<<5 | (Rt))
|
||||
#define SWPxw(Rs, Rt, Rn) EMIT(SWAP_gen(0b10+rex.w, 0, 0, Rs, Rn, Rt))
|
||||
#define SWPAxw(Rs, Rt, Rn) EMIT(SWAP_gen(0b10+rex.w, 1, 0, Rs, Rn, Rt))
|
||||
#define SWPALxw(Rs, Rt, Rn) EMIT(SWAP_gen(0b10+rex.w, 1, 1, Rs, Rn, Rt))
|
||||
#define SWPLxw(Rs, Rt, Rn) EMIT(SWAP_gen(0b10+rex.w, 0, 1, Rs, Rn, Rt))
|
||||
#define SWPB(Rs, Rt, Rn) EMIT(SWAP_gen(0b00, 0, 0, Rs, Rn, Rt))
|
||||
#define SWPAB(Rs, Rt, Rn) EMIT(SWAP_gen(0b00, 1, 0, Rs, Rn, Rt))
|
||||
#define SWPALB(Rs, Rt, Rn) EMIT(SWAP_gen(0b00, 1, 1, Rs, Rn, Rt))
|
||||
#define SWPLB(Rs, Rt, Rn) EMIT(SWAP_gen(0b00, 0, 1, Rs, Rn, Rt))
|
||||
#define SWPH(Rs, Rt, Rn) EMIT(SWAP_gen(0b01, 0, 0, Rs, Rn, Rt))
|
||||
#define SWPAH(Rs, Rt, Rn) EMIT(SWAP_gen(0b01, 1, 0, Rs, Rn, Rt))
|
||||
#define SWPALH(Rs, Rt, Rn) EMIT(SWAP_gen(0b01, 1, 1, Rs, Rn, Rt))
|
||||
#define SWPLH(Rs, Rt, Rn) EMIT(SWAP_gen(0b01, 0, 1, Rs, Rn, Rt))
|
||||
|
||||
#define CAS_gen(size, L, Rs, O0, Rn, Rt) ((size)<<30 | 0b001000<<24 | 1<<23 | (L)<<22 | 1<<21 | (Rs)<<16 | (O0)<<15 | 0b11111<<10 | (Rn)<<5 | (Rt))
|
||||
// Compare and Swap compare Rs with [Rn], write Rt is same, return old [Rn] in Rs
|
||||
#define CASxw(Rs, Rt, Rn) EMIT(CAS_gen(0b10+rex.w, 0, Rs, 0, Rn, Rt))
|
||||
#define CASAxw(Rs, Rt, Rn) EMIT(CAS_gen(0b10+rex.w, 1, Rs, 0, Rn, Rt))
|
||||
#define CASALxw(Rs, Rt, Rn) EMIT(CAS_gen(0b10+rex.w, 1, Rs, 1, Rn, Rt))
|
||||
#define CASLxw(Rs, Rt, Rn) EMIT(CAS_gen(0b10+rex.w, 0, Rs, 1, Rn, Rt))
|
||||
#define CASB(Rs, Rt, Rn) EMIT(CAS_gen(0b00, 0, Rs, 0, Rn, Rt))
|
||||
#define CASAB(Rs, Rt, Rn) EMIT(CAS_gen(0b00, 1, Rs, 0, Rn, Rt))
|
||||
#define CASALB(Rs, Rt, Rn) EMIT(CAS_gen(0b00, 1, Rs, 1, Rn, Rt))
|
||||
#define CASLB(Rs, Rt, Rn) EMIT(CAS_gen(0b00, 0, Rs, 1, Rn, Rt))
|
||||
#define CASH(Rs, Rt, Rn) EMIT(CAS_gen(0b01, 0, Rs, 0, Rn, Rt))
|
||||
#define CASAH(Rs, Rt, Rn) EMIT(CAS_gen(0b01, 1, Rs, 0, Rn, Rt))
|
||||
#define CASALH(Rs, Rt, Rn) EMIT(CAS_gen(0b01, 1, Rs, 1, Rn, Rt))
|
||||
#define CASLH(Rs, Rt, Rn) EMIT(CAS_gen(0b01, 0, Rs, 1, Rn, Rt))
|
||||
|
||||
#define CASP_gen(size, L, Rs, O0, Rn, Rt) ((size)<<30 | 0b001000<<24 | 0<<23 | (L)<<22 | 1<<21 | (Rs)<<16 | (O0)<<15 | 0b11111<<10 | (Rn)<<5 | (Rt))
|
||||
// Compare and Swap with pair, Rs, Rs+1 and Rt,Rt+1 with [Rt]
|
||||
#define CASPxw(Rs, Rt, Rn) EMIT(CASP_gen(0b00+rex.w, 0, Rs, 0, Rn, Rt))
|
||||
#define CASPAxw(Rs, Rt, Rn) EMIT(CASP_gen(0b00+rex.w, 1, Rs, 0, Rn, Rt))
|
||||
#define CASPALxw(Rs, Rt, Rn) EMIT(CASP_gen(0b00+rex.w, 1, Rs, 1, Rn, Rt))
|
||||
#define CASPLxw(Rs, Rt, Rn) EMIT(CASP_gen(0b00+rex.w, 0, Rs, 1, Rn, Rt))
|
||||
|
||||
// FLAGM extension
|
||||
// Invert Carry Flag
|
||||
#define CFINV() EMIT(0b1101010100<<22 | 0b0100<<12 | 0b000<<5 | 0b11111)
|
||||
|
||||
#define RMIF_gen(imm6, Rn, mask) (0b10111010000<<21 | (imm6)<<15 | 0b00001<<10 | (Rn)<<5 | (mask))
|
||||
// Rotate right reg and use as NZCV
|
||||
#define RMIF(Xn, shift, mask) EMIT(RMIF_gen(shift, Xn, mask))
|
||||
|
||||
#define SETF_gen(sz, Rn) (0b00111010000<<21 | (sz)<<14 | 0b0010<<10 | (Rn)<<5 | 0b1101)
|
||||
// Set NZVc with 8bit value of reg: N=bit7, Z=[0..7]==0, V=bit8 eor bit7, C unchanged
|
||||
#define SETF8(Wn) EMIT(SETF_gen(0, Wn))
|
||||
// Set NZVc with 16bit value of reg: N=bit15, Z=[0..15]==0, V=bit16 eor bit15, C unchanged
|
||||
#define SETF16(Wn) EMIT(SETF_gen(1, Wn))
|
||||
|
||||
// FLAGM2 extension
|
||||
// NZCV -> N=0 Z=C|V C=C&!V V=0
|
||||
#define AXFLAG() EMIT(0b1101010100<<22 | 0b0100<<12 | 0b010<<5 | 0b11111)
|
||||
// NZCV -> N=!C&!Z Z=Z&C C=C|Z V=!C&Z
|
||||
#define XAFLAG() EMIT(0b1101010100<<22 | 0b0100<<12 | 0b001<<5 | 0b11111)
|
||||
|
||||
// FRINTTS extension
|
||||
#define FRINTxx_scalar(type, op, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b0100<<17 | (op)<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FRINT32ZS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b00, Sn, Sd))
|
||||
#define FRINT32ZD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b00, Dn, Dd))
|
||||
#define FRINT32XS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b01, Sn, Sd))
|
||||
#define FRINT32XD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b01, Dn, Dd))
|
||||
#define FRINT64ZS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b10, Sn, Sd))
|
||||
#define FRINT64ZD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b10, Dn, Dd))
|
||||
#define FRINT64XS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b11, Sn, Sd))
|
||||
#define FRINT64XD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b11, Dn, Dd))
|
||||
|
||||
// CRC32 extension
|
||||
#define CRC32C_gen(sf, Rm, sz, Rn, Rd) ((sf)<<31 | 0b11010110<<21 | (Rm)<<16 | 0b010<<13 | 1<<12 | (sz)<<10 | (Rn)<<5 | (Rd))
|
||||
#define CRC32CB(Wd, Wn, Wm) EMIT(CRC32C_gen(0, Wm, 0b00, Wn, Wd))
|
||||
#define CRC32CH(Wd, Wn, Wm) EMIT(CRC32C_gen(0, Wm, 0b01, Wn, Wd))
|
||||
#define CRC32CW(Wd, Wn, Wm) EMIT(CRC32C_gen(0, Wm, 0b10, Wn, Wd))
|
||||
#define CRC32CX(Wd, Wn, Xm) EMIT(CRC32C_gen(1, Xm, 0b11, Wn, Wd))
|
||||
#define CRC32Cxw(Wd, Wn, Rm) EMIT(CRC32C_gen(rex.w, Rm, 0b10|rex.w, Wn, Wd))
|
||||
|
||||
// SHA1 extension
|
||||
#define SHA1H_gen(Rn, Rd) (0b01011110<<24 | 0b10100<<17 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// SHA1 fixed rotate (ROL 30 of 32bits value)
|
||||
#define SHA1H(Sd, Sn) EMIT(SHA1H_gen(Sn, Sd))
|
||||
|
||||
#define SHA1SU1_gen(Rn, Rd) (0b01011110<<24 | 0b10100<<17 | 0b00001<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// SHA1 schedule update 1
|
||||
#define SHA1SU1(Vd, Vn) EMIT(SHA1SU1_gen(Vn, Vd))
|
||||
|
||||
#define SHA1C_gen(Rm, Rn, Rd) (0b01011110<<24 | (Rm)<<16 | (Rn)<<5 | (Rd))
|
||||
// SHA1 hash update (choose)
|
||||
#define SHA1C(Qd, Sn, Vm) EMIT(SHA1C_gen(Vm, Sn, Qd))
|
||||
|
||||
#define SHA1M_gen(Rm, Rn, Rd) (0b01011110<<24 | (Rm)<<16 | 0b010<<12 | (Rn)<<5 | (Rd))
|
||||
// SHA1 hash update (majority)
|
||||
#define SHA1M(Qd, Sn, Vm) EMIT(SHA1M_gen(Vm, Sn, Qd))
|
||||
|
||||
#define SHA1P_gen(Rm, Rn, Rd) (0b01011110<<24 | (Rm)<<16 | 0b001<<12 | (Rn)<<5 | (Rd))
|
||||
// SHA1 hash update (parity)
|
||||
#define SHA1P(Qd, Sn, Vm) EMIT(SHA1P_gen(Vm, Sn, Qd))
|
||||
|
||||
#define SHA256SU0_gen(Rn,Rd) (0b01011110<<24 | 0b10100<<17 | 0b00010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
//SHA256 schedule update 0
|
||||
#define SHA256SU0(Vd, Vn) EMIT(SHA256SU0_gen(Vn, Vd))
|
||||
|
||||
#define SHA256SU1_gen(Rm, Rn, Rd) (0b01011110<<24 | (Rm)<<16 | 0b110<<12 | (Rn)<<5 | (Rd))
|
||||
//SHA256 schedule update 1
|
||||
#define SHA256SU1(Vd, Vn, Vm) EMIT(SHA256SU1_gen(Vm, Vn, Vd))
|
||||
|
||||
#define SHA256H_gen(Rm, Rn, Rd) (0b01011110<<24 | (Rm)<<16 | 0b100<<12 | (Rn)<<5 | (Rd))
|
||||
//SHA256 hash update (part 1)
|
||||
#define SHA256H(Vd, Vn, Vm) EMIT(SHA256H_gen(Vm, Vn, Vd))
|
||||
|
||||
#define SHA256H2_gen(Rm, Rn, Rd) (0b01011110<<24 | (Rm)<<16 | 0b101<<12 | (Rn)<<5 | (Rd))
|
||||
//SHA256 hash update (part 2)
|
||||
#define SHA256H2(Vd, Vn, Vm) EMIT(SHA256H2_gen(Vm, Vn, Vd))
|
||||
|
||||
#endif //__ARM64_EMITTER_H__
|
||||
Executable → Regular
+6
-4
@@ -19,18 +19,19 @@ arm64_epilog:
|
||||
stp x24, x25, [x0, (8 * 14)]
|
||||
stp x26, x27, [x0, (8 * 16)] // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
add sp, x28, 0
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldr x27, [sp, (8 * 8)]
|
||||
ldp x27, x28, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp lr, fp, [sp], 16 // saved lr
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
@@ -38,17 +39,18 @@ arm64_epilog:
|
||||
.global arm64_epilog_fast
|
||||
arm64_epilog_fast:
|
||||
//restore all used register
|
||||
add sp, x28, 0
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldr x27, [sp, (8 * 8)]
|
||||
ldp x27, x28, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp lr, fp, [sp], 16 // saved lr
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
Executable → Regular
+166
-20
@@ -15,10 +15,24 @@
|
||||
.global arm64_lock_write_dd
|
||||
.global arm64_lock_read_dq
|
||||
.global arm64_lock_write_dq
|
||||
.global arm64_lock_xchg
|
||||
.global arm64_lock_xchg_dd
|
||||
.global arm64_lock_xchg_d
|
||||
.global arm64_lock_xchg_h
|
||||
.global arm64_lock_xchg_b
|
||||
.global arm64_lock_storeifnull
|
||||
.global arm64_lock_storeifnull_d
|
||||
.global arm64_lock_storeifref
|
||||
|
||||
.global arm64_lock_storeifref_d
|
||||
.global arm64_lock_storeifref2_d
|
||||
.global arm64_lock_decifnot0b
|
||||
.global arm64_lock_storeb
|
||||
.global arm64_lock_incif0
|
||||
.global arm64_lock_decifnot0
|
||||
.global arm64_lock_store
|
||||
.global arm64_lock_store_dd
|
||||
.global arm64_lock_get_b
|
||||
.global arm64_lock_get_d
|
||||
.global arm64_lock_get_dd
|
||||
|
||||
arm64_lock_read_b:
|
||||
dmb ish
|
||||
@@ -89,43 +103,175 @@ arm64_lock_write_dq:
|
||||
ret
|
||||
|
||||
|
||||
arm64_lock_xchg:
|
||||
arm64_lock_xchg_dd:
|
||||
dmb ish
|
||||
arm64_lock_xchg_0:
|
||||
arm64_lock_xchg_dd_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxr x2, [x0]
|
||||
stlxr w3, x1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_0
|
||||
dmb ish
|
||||
cbnz w3, arm64_lock_xchg_dd_0
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_d:
|
||||
dmb ish
|
||||
arm64_lock_xchg_d_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxr w2, [x0]
|
||||
stlxr w3, w1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_d_0
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_h:
|
||||
dmb ish
|
||||
arm64_lock_xchg_h_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxrh w2, [x0]
|
||||
stlxrh w3, w1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_h_0
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_b:
|
||||
dmb ish
|
||||
arm64_lock_xchg_b_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxrb w2, [x0]
|
||||
stlxrb w3, w1, [x0]
|
||||
cbnz w3, arm64_lock_xchg_b_0
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
dmb ish
|
||||
arm64_lock_storeifnull_0:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return new [x0] value (so x1 or old value)
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
ldaxr x2, [x0]
|
||||
cbnz x2, arm64_lock_storeifnull_exit
|
||||
mov x2, x1
|
||||
stlxr w3, x2, [x0]
|
||||
cbnz w3, arm64_lock_storeifnull_0
|
||||
arm64_lock_storeifnull_exit:
|
||||
dmb ish
|
||||
cbnz x2, 2f
|
||||
stlxr w3, x1, [x0]
|
||||
cbnz w3, 1b
|
||||
2:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull_d:
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
ldaxr w2, [x0]
|
||||
cbnz w2, 2f
|
||||
stlxr w3, w1, [x0]
|
||||
cbnz w3, 1b
|
||||
2:
|
||||
dmb ish
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref:
|
||||
dmb ish
|
||||
arm64_lock_storeifref_0:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x3. return new [x0] value (so x1 or old value)
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
|
||||
ldaxr x3, [x0]
|
||||
cmp x2, x3
|
||||
bne arm64_lock_storeifref_exit
|
||||
bne 2f
|
||||
stlxr w4, x1, [x0]
|
||||
cbnz w4, arm64_lock_storeifref_0
|
||||
cbnz w4, 1b
|
||||
mov x0, x1
|
||||
ret
|
||||
arm64_lock_storeifref_exit:
|
||||
dmb ish
|
||||
2:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref_d:
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so x1 or old value)
|
||||
ldaxr w3, [x0]
|
||||
cmp w2, w3
|
||||
bne 2f
|
||||
stlxr w4, w1, [x0]
|
||||
cbnz w4, 1b
|
||||
mov w0, w1
|
||||
ret
|
||||
2:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref2_d:
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
|
||||
ldaxr w3, [x0]
|
||||
cmp w2, w3
|
||||
bne 2f
|
||||
stlxr w4, w1, [x0]
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0b:
|
||||
dmb ish
|
||||
1:
|
||||
ldaxrb w1, [x0]
|
||||
cmp w1, #0
|
||||
beq 2f
|
||||
sub w1, w1, #1
|
||||
stlxrb w2, w1, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
ret
|
||||
|
||||
arm64_lock_storeb:
|
||||
strb w1, [x0]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0:
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
cmp w1, #0
|
||||
beq 2f
|
||||
sub w3, w1, #1
|
||||
stlxr w2, w3, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_incif0:
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
cmp w1, #0
|
||||
bne 2f
|
||||
add w3, w1, #1
|
||||
stlxr w2, w3, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_store:
|
||||
str w1, [x0]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_store_dd:
|
||||
str x1, [x0]
|
||||
dmb ish
|
||||
ret
|
||||
|
||||
arm64_lock_get_b:
|
||||
ldaxrb w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_get_d:
|
||||
ldaxr w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_get_dd:
|
||||
ldaxr x0, [x0]
|
||||
ret
|
||||
Executable → Regular
+50
-5
@@ -27,13 +27,58 @@ extern void arm64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
|
||||
// STLXRD of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg(void* p, uintptr_t val);
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg_dd(void* p, uintptr_t val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_d(void* p, uint32_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_h(void* p, uint32_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_b(void* p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern uint32_t arm64_lock_storeifnull_d(void*p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* arm64_lock_storeifnull(void*p, void* val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
|
||||
|
||||
#endif //__ARM64_LOCK__H__
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref2_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// decrement atomically the byte at [p] (but only if p not 0)
|
||||
extern void arm64_lock_decifnot0b(void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_storeb(void*p, uint8_t b);
|
||||
|
||||
// increment atomically the int at [p] only if it was 0. Return the old value of [p]
|
||||
extern int arm64_lock_incif0(void*p);
|
||||
|
||||
// decrement atomically the int at [p] (but only if p not 0)
|
||||
extern int arm64_lock_decifnot0(void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_store(void*p, uint32_t v);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_store_dd(void*p, uint64_t v);
|
||||
|
||||
// atomic get (with memory barrier)
|
||||
extern uint8_t arm64_lock_get_b(void*p);
|
||||
|
||||
// atomic get (with memory barrier)
|
||||
extern uint32_t arm64_lock_get_d(void*p);
|
||||
|
||||
// atomic get (with memory barrier)
|
||||
extern void* arm64_lock_get_dd(void*p);
|
||||
|
||||
#endif //__ARM64_LOCK__H__
|
||||
Executable → Regular
+3
-1
@@ -9,6 +9,8 @@
|
||||
.extern LinkNext
|
||||
|
||||
.global arm64_next
|
||||
|
||||
.8byte 0 // NULL pointer before arm64_next, for getDB
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
@@ -20,7 +22,7 @@ arm64_next:
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
|
||||
|
||||
mov x2, lr // "from" is in lr, so put in x2
|
||||
mov x2, x30 // "from" is in lr, so put in x2
|
||||
add x3, sp, 8*11 // x3 is address to change rip
|
||||
// call the function
|
||||
bl LinkNext
|
||||
|
||||
Executable → Regular
+425
-22
@@ -16,7 +16,7 @@ static const char* conds[] = {"cEQ", "cNE", "cCS", "cCC", "cMI", "cPL", "cVS", "
|
||||
#define abs(A) (((A)<0)?(-(A)):(A))
|
||||
|
||||
typedef struct arm64_print_s {
|
||||
int N, S, U, L, Q;
|
||||
int N, S, U, L, Q, A, R;
|
||||
int t, n, m, d, t2, a;
|
||||
int f, c, o, h, p;
|
||||
int i, r, s;
|
||||
@@ -25,7 +25,7 @@ typedef struct arm64_print_s {
|
||||
|
||||
uint64_t DecodeBitMasks(int N, int imms, int immr)
|
||||
{
|
||||
int len = 31-__builtin_clz(N<<6 | ((~imms)&0b111111));
|
||||
int len = 31-__builtin_clz((N<<6) | ((~imms)&0b111111));
|
||||
if(len<1) return 0;
|
||||
int levels = (1<<len) - 1;
|
||||
int s = imms & levels;
|
||||
@@ -60,6 +60,8 @@ int isMask(uint32_t opcode, const char* mask, arm64_print_t *a)
|
||||
case 'N': a->N = (a->N<<1) | v; break;
|
||||
case 'S': a->S = (a->S<<1) | v; break;
|
||||
case 'U': a->U = (a->U<<1) | v; break;
|
||||
case 'A': a->A = (a->A<<1) | v; break;
|
||||
case 'R': a->R = (a->R<<1) | v; break;
|
||||
case 'L': a->L = (a->L<<1) | v; break;
|
||||
case 'Q': a->Q = (a->Q<<1) | v; break;
|
||||
case 't': a->t = (a->t<<1) | v; break;
|
||||
@@ -160,13 +162,60 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
if(isMask(opcode, "1x111000010iiiiiiiii01nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDR %s, [%s], %s0x%x", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
snprintf(buff, sizeof(buff), "LDUR %s, [%s], %s0x%x", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x111000010iiiiiiiii11nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDR %s, [%s, %s0x%x]!", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
snprintf(buff, sizeof(buff), "LDUR %s, [%s, %s0x%x]!", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x111000010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00111000010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01111000010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "001110001x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "011110001x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10111000100iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x111000000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00111000000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01111000000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x11100101iiiiiiiiiiiinnnnnttttt", &a)) {
|
||||
@@ -748,6 +797,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "CSEL %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1111010010mmmmmcccc00nnnnn0iiii", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CCMP %s, %s, %s 0x%x", sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond], imm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// MISC Bits
|
||||
if(isMask(opcode, "f10110101100000000010onnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CL%c %s, %s", option?'S':'Z', sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn]);
|
||||
@@ -776,7 +830,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10011011U10mmmmm011111nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%cMULH %s, %s, %s", a.U?'U':'S', Xt[Rd], Wt[Rn], Wt[Rm]);
|
||||
snprintf(buff, sizeof(buff), "%cMULH %s, %s, %s", a.U?'U':'S', Xt[Rd], Xt[Rn], Xt[Rm]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0011011000mmmmm0aaaaannnnnddddd", &a)) {
|
||||
@@ -903,6 +957,54 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "VCMEQ V%d.%s, V%d.%s, V%d.%s", Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
// CMP zero
|
||||
if(isMask(opcode, "0QU01110ff100000100o10nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
const char* Z[] = {"GT", "GE", "EQ", "LE"};
|
||||
const char* Vd = Y[((sf)<<1) | a.Q];
|
||||
const char* Cond = Z[(a.o << 1 | a.U)];
|
||||
snprintf(buff, sizeof(buff), "VCM%s V%d.%s, V%d.%s, #0", Cond, Rd, Vd, Rn, Vd);
|
||||
return buff;
|
||||
}
|
||||
// CMPLT zero
|
||||
if(isMask(opcode, "0Q001110ff100000101010nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
const char* Vd = Y[((sf)<<1) | a.Q];
|
||||
snprintf(buff, sizeof(buff), "VCMLT V%d.%s, V%d.%s, #0", Rd, Vd, Rn, Vd);
|
||||
return buff;
|
||||
}
|
||||
// MIN/MAX
|
||||
if(isMask(opcode, "0QU01110ff1mmmmm0110o1nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
const char* Vd = Y[((sf)<<1) | a.Q];
|
||||
snprintf(buff, sizeof(buff), "%c%s V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', a.o?"MIN":"MAX", Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// MOV immediate (not)shifted 8bits
|
||||
if(isMask(opcode, "0Q00111100000iii111001iiiiiddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B"};
|
||||
const char* Vd = Y[a.Q];
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm);
|
||||
return buff;
|
||||
}
|
||||
// MOV immediate notshifted 16bits & 32bits
|
||||
if(isMask(opcode, "0Q00111100000iiif00001iiiiiddddd", &a)) {
|
||||
const char* Y[] = {"2S", "4S", "4H", "8H"};
|
||||
const char* Vd = Y[(sf<<1)| a.Q];
|
||||
int sh = 0;
|
||||
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm<<sh);
|
||||
return buff;
|
||||
}
|
||||
// MOV immediate shifted 16bits
|
||||
if(isMask(opcode, "0Q00111100000iii101001iiiiiddddd", &a)) {
|
||||
const char* Y[] = {"4H", "8H"};
|
||||
const char* Vd = Y[a.Q];
|
||||
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm<<8);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// Shift
|
||||
if(isMask(opcode, "0QU011110hhhhrrr000001nnnnnddddd", &a)) {
|
||||
@@ -965,7 +1067,30 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%s %c%d, [%s]", op?"STR":"LDR", s, Rt, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%s %c%d, [%s, %d]", op?"STR":"LDR", s, Rt, XtSp[Rn], offset);
|
||||
snprintf(buff, sizeof(buff), "%s %c%d, [%s, 0x%x]", op?"STR":"LDR", s, Rt, XtSp[Rn], offset);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "ss111100cc1mmmmmoooS10nnnnnttttt", &a)) {
|
||||
char s = '?';
|
||||
int size=imms;
|
||||
int op=0;
|
||||
if(size==0 && opc==1) {s='B';}
|
||||
else if(size==1 && opc==1) {s='H';}
|
||||
else if(size==2 && opc==1) {s='S';}
|
||||
else if(size==3 && opc==1) {s='D';}
|
||||
else if(size==0 && opc==3) {s='Q'; size = 4;}
|
||||
else if(size==0 && opc==0) {s='B'; op=1;}
|
||||
else if(size==1 && opc==0) {s='H'; op=1;}
|
||||
else if(size==2 && opc==0) {s='S'; op=1;}
|
||||
else if(size==3 && opc==0) {s='D'; op=1;}
|
||||
else if(size==0 && opc==2) {s='Q'; op=1; size = 4;}
|
||||
|
||||
const char* extend[] = {"?0", "?1", "UXTW", "LSL", "?4", "?5", "SXTW", "SXTX"};
|
||||
int amount = size*a.S;
|
||||
if(option==3 && !amount)
|
||||
snprintf(buff, sizeof(buff), "%s %c%d, [%s, %s]", op?"STR":"LDR", s, Rt, XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%s %c%d, [%s, %s, %s %d]", op?"STR":"LDR", s, Rt, XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm], extend[option], amount);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1025,6 +1150,20 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// FADDP
|
||||
if(isMask(opcode, "0Q1011100f1mmmmm110101nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFADDP %c%d.%d%c, %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d, s, Rm, n, d);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "011111100f110000110110nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FADDP %c%d, %c%d, %c%d", s, Rd, s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// SQRT
|
||||
if(isMask(opcode, "0Q1011101f100001111110nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
@@ -1038,6 +1177,84 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "FSQRT %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
// FPRINTX
|
||||
if(isMask(opcode, "0Q1011100f100001100110nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFRINTX %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00011110ff100111010000nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FRINTX %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
// FRINTI
|
||||
if(isMask(opcode, "0Q1011101f100001100110nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFRINTI %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00011110ff100111110000nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FRINTI %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
// FRINTN
|
||||
if(isMask(opcode, "0Q0011100f100001100010nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFRINTN %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "000111100f100100010000nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FRINTN %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
// FRINTM
|
||||
if(isMask(opcode, "0Q0011100f100001100110nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFRINTM %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "000111100f100101010000nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FRINTM %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
// FRINTP
|
||||
if(isMask(opcode, "0Q0011101f100001100010nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFRINTP %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "000111100f100100110000nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FRINTP %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
// FRINTZ
|
||||
if(isMask(opcode, "0Q0011101f100001100110nnnnnddddd", &a)) {
|
||||
char s = a.Q?'V':'D';
|
||||
char d = sf?'D':'S';
|
||||
int n = (a.Q && !sf)?4:2;
|
||||
snprintf(buff, sizeof(buff), "VFRINTZ %c%d.%d%c, %c%d.%d%c", s, Rd, n, d, s, Rn, n, d);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "000111100f100101110000nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
snprintf(buff, sizeof(buff), "FRINTZ %c%d, %c%d", s, Rd, s, Rn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
//CMP
|
||||
if(isMask(opcode, "00011110ff1mmmmm001000nnnnn0c000", &a)) {
|
||||
@@ -1048,6 +1265,16 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "FCMP %c%d, %c%d", s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
//FCMP vector
|
||||
if(isMask(opcode, "0QU01110cf1mmmmm111001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
int op = (a.c<<1) | (a.U);
|
||||
const char* OP[] = {"EQ", "GE", "??", "GT"};
|
||||
snprintf(buff, sizeof(buff), "FCMP%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", OP[op], a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
//FMIN/FMAX
|
||||
if(isMask(opcode, "00011110ff1mmmmm01oo10nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
@@ -1061,6 +1288,27 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "F%sNM%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q001110of1mmmmm111101nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "F%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// NEG
|
||||
if(isMask(opcode, "0Q101110ff100000101110nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
const char* Vd = Y[(sf<<1) | a.Q];
|
||||
snprintf(buff, sizeof(buff), "NEG%s V%d.%s, V%d.%s", a.Q?"Q":"", Rd, Vd, Rn, Vd);
|
||||
return buff;
|
||||
}
|
||||
// SSHL vector
|
||||
if(isMask(opcode, "0QU01110ff1mmmmm010rS1nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
const char* Vd = Y[(sf<<1) | a.Q];
|
||||
snprintf(buff, sizeof(buff), "%c%s%sSHL%s V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', a.r?"R":"", a.S?"Q":"", a.Q?"Q":"", Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// FCVT
|
||||
if(isMask(opcode, "f0011110pp10010U000000nnnnnddddd", &a)) {
|
||||
@@ -1124,6 +1372,14 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "FCVT%sS %s, %c%d", roundings[a.c], sf?Xt[Rd]:Wt[Rd], s, Rn);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0QU01110of100001101o10nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"2S", "4S", "??", "2D"};
|
||||
const char* Z[] = {"S", "S", "??", "D"};
|
||||
const char* Vd = Y[(sf<<1) | a.Q];
|
||||
const char* roundings[] = {"N", "M", "P", "Z"};
|
||||
snprintf(buff, sizeof(buff), "VFCVT%s%s%s%s V%d.%s, V%d.%s", roundings[option], a.U?"U":"S", a.Q?"Q":"", Z[(sf<<1)|a.Q], Rd, Vd, Rn, Vd);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// FMOV
|
||||
if(isMask(opcode, "00011110pp100000010000nnnnnddddd", &a)) {
|
||||
@@ -1140,8 +1396,8 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
else if(sf==0 && type==0 && rmode==0 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, S%d", Wt[Rn], Rd);}
|
||||
else if(sf==1 && type==1 && rmode==0 && opcd==7) {snprintf(buff, sizeof(buff), "FMOV D%d, %s", Rd, Xt[Rn]);}
|
||||
else if(sf==1 && type==2 && rmode==1 && opcd==7) {snprintf(buff, sizeof(buff), "FMOV V%d.D[1], %s", Rd, Xt[Rn]);}
|
||||
else if(sf==1 && type==1 && rmode==0 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, S%d", Xt[Rn], Rd);}
|
||||
else if(sf==1 && type==2 && rmode==1 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, V%d.D[1]", Xt[Rn], Rd);}
|
||||
else if(sf==1 && type==1 && rmode==0 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, D%d", Xt[Rd], Rn);}
|
||||
else if(sf==1 && type==2 && rmode==1 && opcd==6) {snprintf(buff, sizeof(buff), "FMOV %s, V%d.D[1]", Xt[Rd], Rn);}
|
||||
else snprintf(buff, sizeof(buff), "FMOV ????");
|
||||
return buff;
|
||||
}
|
||||
@@ -1236,14 +1492,6 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// MOV immediate
|
||||
if(isMask(opcode, "0Q00111100000iii111001iiiiiddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B"};
|
||||
const char* Vd = Y[a.Q];
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// LD1/ST1 single structure
|
||||
if(isMask(opcode, "0Q0011010L000000cc0Sffnnnnnttttt", &a)) {
|
||||
int scale = a.c;
|
||||
@@ -1272,9 +1520,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
sz = 4;
|
||||
int offset = signExtend(imm, 9);
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rd, XtSp[Rn]);
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %+d]", a.L?"LD":"ST", Y[sz], Rd, XtSp[Rn], imm);
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
// LDR/STR vector immediate
|
||||
@@ -1285,9 +1533,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
sz = 4;
|
||||
int offset = imm<<sz;
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%sR %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rd, XtSp[Rn]);
|
||||
snprintf(buff, sizeof(buff), "%sR %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%sR %s%d, [%s, %+d]", a.L?"LD":"ST", Y[sz], Rd, XtSp[Rn], imm);
|
||||
snprintf(buff, sizeof(buff), "%sR %s%d, [%s, %+d]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], imm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1329,7 +1577,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
|
||||
// DUP
|
||||
if(isMask(opcode, "0Q001110000iiiii000001nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "2D", "??"};
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
const char* Z[] = {"B", "H", "S", "D"};
|
||||
int sz = 3;
|
||||
if((imm&0b0001)==0b0001) sz=0;
|
||||
@@ -1341,7 +1589,18 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "DUP V%d.%s, V%d.%s[%d]", Rd, Vd, Rn, Vn, sh);
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
if(isMask(opcode, "0Q001110000iiiii000011nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
int sz = 3;
|
||||
if((imm&0b0001)==0b0001) sz=0;
|
||||
else if((imm&0b0011)==0b0010) sz=1;
|
||||
else if((imm&0b0111)==0b0100) sz=2;
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
snprintf(buff, sizeof(buff), "DUP V%d.%s, X%d", Rd, Vd, Rn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// AES
|
||||
if(isMask(opcode, "0100111000101000010f10nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "AES%c V%d.16B, V%d.16B", sf?'D':'E', Rd, Rn);
|
||||
@@ -1351,11 +1610,155 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "AES%sMC V%d.16B, V%d.16B", sf?"I":"", Rd, Rn);
|
||||
return buff;
|
||||
}
|
||||
// PMULL
|
||||
if(isMask(opcode, "0Q001110ff1mmmmm111000nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "??", "??", "??", "??", "1D", "2D"};
|
||||
const char* Z[] = {"8H", "??", "??", "1Q"};
|
||||
int sz = sf;
|
||||
const char* Vn = Y[(sz<<1)|a.Q];
|
||||
const char* Vd = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "PMULL%s V%d.%s, V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DMB ISH
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");
|
||||
return buff;
|
||||
}
|
||||
// DSB ISH/ISHST
|
||||
if(isMask(opcode, "11010101000000110011nnnn10011111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DSB %s", (Rn==0b1011)?"ISH":((Rn==0b1010)?"ISHST":"???"));
|
||||
return buff;
|
||||
}
|
||||
|
||||
// CASxw
|
||||
if(isMask(opcode, "1f0010001L1ssssso11111nnnnnttttt", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CAS%s%s %s, %s, [%s]", a.o?"A":"", a.L?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// CAS B/H
|
||||
if(isMask(opcode, "0f0010001L1ssssso11111nnnnnttttt", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CAS%s%s%s %s, %s, [%s]", a.o?"A":"", a.L?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// CASPxw
|
||||
if(isMask(opcode, "0f0010000L1ssssso11111nnnnnttttt", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CASP%s%s %s,%s, %s,%s, [%s]", a.o?"A":"", a.L?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rs+1]:Wt[Rs+1], sf?Xt[Rt]:Wt[Rt], sf?Xt[Rt+1]:Wt[Rt+1], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// SWPxw
|
||||
if(isMask(opcode, "1f111000AR1sssss100000nnnnnttttt", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SWP%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// SWPxw
|
||||
if(isMask(opcode, "0f111000AR1sssss100000nnnnnttttt", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CAS%s%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// LDXXXxw
|
||||
if(isMask(opcode, "1f111000AR1sssss0ooo00nnnnnttttt", &a)) {
|
||||
const char* ops[] = { "ADD", "CLR", "EOR", "SET", "SMAX, SMIN", "UMAX", "UMIN" };
|
||||
if((Rt == 0b11111) && !a.A) {
|
||||
snprintf(buff, sizeof(buff), "ST%s%s %s, [%s]", ops[a.o], a.R?"L":"", sf?Xt[Rs]:Wt[Rs], XtSp[Rn]);
|
||||
} else {
|
||||
snprintf(buff, sizeof(buff), "LD%s%s%s %s, %s, [%s]", ops[a.o], a.A?"A":"", a.R?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
// LDXXX B/H
|
||||
if(isMask(opcode, "0f111000AR1sssss0ooo00nnnnnttttt", &a)) {
|
||||
const char* ops[] = { "ADD", "CLR", "EOR", "SET", "SMAX, SMIN", "UMAX", "UMIN" };
|
||||
if((Rt == 0b11111) && !a.A) {
|
||||
snprintf(buff, sizeof(buff), "ST%s%s%s %s, [%s]", ops[a.o], a.R?"L":"", sf?"H":"B", Xt[Rs], XtSp[Rn]);
|
||||
} else {
|
||||
snprintf(buff, sizeof(buff), "LD%s%s%s%s %s, %s, [%s]", ops[a.o], a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
// AXFLAG
|
||||
if(isMask(opcode, "11010101000000000100000001011111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "AXFLAG");
|
||||
return buff;
|
||||
}
|
||||
// XAFLAG
|
||||
if(isMask(opcode, "11010101000000000100000000111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "XAFLAG");
|
||||
return buff;
|
||||
}
|
||||
// CFINV
|
||||
if(isMask(opcode, "11010101000000000100000000011111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CFINV");
|
||||
return buff;
|
||||
}
|
||||
// RMIF
|
||||
if(isMask(opcode, "10111010000iiiiii00001nnnnn0oooo", &a)) {
|
||||
snprintf(buff, sizeof(buff), "RMIF %s, #%d, #0x%x", Xt[Rn], imm, opc);
|
||||
return buff;
|
||||
}
|
||||
// SETF
|
||||
if(isMask(opcode, "00111010000000000f0010nnnnn01101", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SETF%d %s", 8<<sf, Xt[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// REV64
|
||||
if(isMask(opcode, "0Q001110ff100000000010nnnnnddddd", &a)) {
|
||||
const char* T[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"};
|
||||
int sz = sf;
|
||||
const char* Vn = T[(sz<<1)|a.Q];
|
||||
const char* Vd = T[(sz<<1)|a.Q];
|
||||
snprintf(buff, sizeof(buff), "REV64 V%d.%s, V%d.%s",Rd, Vd, Rn, Vn);
|
||||
return buff;
|
||||
}
|
||||
//TRNx
|
||||
if(isMask(opcode, "0Q001110ff0mmmmm0o1010nnnnnddddd", &a)) {
|
||||
const char* T[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
int sz = sf;
|
||||
const char* Vn = T[(sz<<1)|a.Q];
|
||||
const char* Vm = T[(sz<<1)|a.Q];
|
||||
const char* Vd = T[(sz<<1)|a.Q];
|
||||
snprintf(buff, sizeof(buff), "TRN%d V%d.%s, V%d.%s, V%d.%s", a.o+1, Rd, Vd, Rn, Vn, Rm, Vm);
|
||||
return buff;
|
||||
}
|
||||
//SHA1 stuffs
|
||||
if(isMask(opcode, "0101111000101000000010nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA1H S%d, S%d", Rd, Rn);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0101111000101000000110nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA1SU1 V%d.4S, V%d.4S", Rd, Rn);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011110000mmmmm000000nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA1C Q%d, S%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011110000mmmmm001000nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA1M Q%d, S%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011110000mmmmm000100nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA1P Q%d, S%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
//SHA256 stuffs
|
||||
if(isMask(opcode, "0101111000101000001010nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA256SU0 V%d.4S, V%d.4S", Rd, Rn);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011110000mmmmm011000nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA256SU1 V%d.4S, V%d.4S, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011110000mmmmm010000nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA256H Q%d, Q%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011110000mmmmm010100nnnnnddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SHA256H2 Q%d, Q%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X ???", __builtin_bswap32(opcode));
|
||||
return buff;
|
||||
|
||||
Executable → Regular
+9
-2
@@ -6,16 +6,18 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_next
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
stp lr, fp, [sp, -16]! // save lr
|
||||
stp x30, x29, [sp, -16]! // save lr
|
||||
sub sp, sp, (8 * 18)
|
||||
stp x19, x20, [sp, (8 * 0)]
|
||||
stp x21, x22, [sp, (8 * 2)]
|
||||
stp x23, x24, [sp, (8 * 4)]
|
||||
stp x25, x26, [sp, (8 * 6)]
|
||||
str x27, [sp, (8 * 8)]
|
||||
stp x27, X28, [sp, (8 * 8)]
|
||||
stp d8, d9, [sp, (8 *10)]
|
||||
stp d10, d11, [sp, (8 *12)]
|
||||
stp d12, d13, [sp, (8 *14)]
|
||||
@@ -31,5 +33,10 @@ arm64_prolog:
|
||||
ldp x22, x23, [x0, (8 * 12)]
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
// Push a jump next on the stack
|
||||
adr x28, arm64_next
|
||||
stp x28, xzr, [sp, -16]!
|
||||
// Save old xSP in x28
|
||||
add x28, sp, 16
|
||||
//jump to function
|
||||
br x1
|
||||
Executable → Regular
+1145
-398
File diff suppressed because it is too large.
Load diff
Executable → Regular
+964
-316
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -16,14 +15,13 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
@@ -34,10 +32,12 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t gd, ed, eb1, eb2, gb1, gb2;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
int64_t i64, j64;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(wb1);
|
||||
@@ -54,15 +54,20 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("ADD Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x5);
|
||||
WBACKO(x4);
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -91,9 +96,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR64_U12(v0, x4, fixedaddress); // upper part reseted
|
||||
VLD64(v0, x4, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -101,15 +107,17 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR32_U12(v0, x4, fixedaddress);
|
||||
VLD32(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -129,9 +137,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR128_U12(v0, x4, fixedaddress);
|
||||
VST128(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -145,9 +154,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR64_U12(v0, x4, fixedaddress);
|
||||
VST64(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -156,13 +166,15 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VSTR32_U12(v0, x4, fixedaddress);
|
||||
VST32(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -182,9 +194,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -194,56 +207,69 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
MOVw_REG(gd, gd);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
MOVw_REG(gd, gd);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
LDRB_REG(gd, ed, x4);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -252,6 +278,49 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_and32(dyn, ninst, rex, ed, gd, x3, x5);
|
||||
WBACKO(x4);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("SUB Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x5);
|
||||
WBACKO(x4);
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("XOR Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x5);
|
||||
WBACKO(x4);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -261,7 +330,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEDO(x4, 0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -283,30 +352,49 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0x63:
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
LDRSW_REG(gd, ed, x4);
|
||||
}
|
||||
if(rex.is32bits) {
|
||||
// ARPL here
|
||||
DEFAULT;
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
LDRw_REG(gd, ed, x4);
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRSW_REG(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRw_REG(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _GS, ok, need_epilog);
|
||||
break;
|
||||
case 0x66:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, seg, ok, need_epilog);
|
||||
break;
|
||||
case 0x67:
|
||||
if(rex.is32bits)
|
||||
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, seg, ok, need_epilog);
|
||||
else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
@@ -481,7 +569,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
gd = (nextop&0x38)>>3;
|
||||
gb1 = xRAX+(gd&3);
|
||||
gb2 = ((gd&4)>>2);
|
||||
gb2 = ((gd&4)<<1);
|
||||
}
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
@@ -500,11 +588,12 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(x4, wback, x4);
|
||||
ed = x4;
|
||||
}
|
||||
BFIx(gb1, ed, gb2*8, 8);
|
||||
BFIx(gb1, ed, gb2, 8);
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
@@ -514,8 +603,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRxw_REG(gd, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -527,11 +617,90 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(gd!=ed) { // it's sometimes used as a 3 bytes NOP
|
||||
MOVxw_REG(gd, ed);
|
||||
}
|
||||
else if(!rex.w && !rex.is32bits) {
|
||||
MOVw_REG(gd, gd); //truncate the higher 32bits as asked
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg,Ew");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
u8 = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRH_REG(x1, wback, x4);
|
||||
ed = x1;
|
||||
}
|
||||
STRH_U12(ed, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
STRw_U12(wZR, xEmu, offsetof(x64emu_t, segs_serial[u8]));
|
||||
break;
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
POP1z(xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
POP1z(x2); // so this can handle POP [ESP] and maybe some variant too
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed==xRSP) {
|
||||
STRz_REG(x2, ed, x4);
|
||||
} else {
|
||||
// complicated to just allow a segfault that can be recovered correctly
|
||||
SUBz_U12(xRSP, xRSP, rex.is32bits?4:8);
|
||||
STRz_REG(x2, ed, x4);
|
||||
ADDz_U12(xRSP, xRSP, rex.is32bits?4:8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,FS:Od");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
LDRxw_REG(xRAX, x1, x4);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Od,EAX");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
STRxw_REG(xRAX, x1, x4);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
@@ -544,15 +713,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
} else {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0;
|
||||
eb2 = 0;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
BFIx(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
STRB_REG(x3, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
@@ -564,10 +734,11 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_REG(x3, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -774,9 +945,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1:
|
||||
@@ -785,11 +957,11 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEDO(x6, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
GETEDO(x6, 4);
|
||||
GETEDO(x6, 0);
|
||||
MVNxw_REG(ed, ed);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
@@ -803,7 +975,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
GETEDO(x6, 0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -817,11 +988,11 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
GETEDO(x6, 0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -835,6 +1006,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
@@ -854,8 +1026,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRDX, x4);
|
||||
} else {
|
||||
if(ninst
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
|
||||
SET_DFNONE(x2);
|
||||
GETEDO(x6, 0);
|
||||
@@ -878,6 +1050,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2)
|
||||
@@ -890,7 +1063,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRDX, x4);
|
||||
} else {
|
||||
if(ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) {
|
||||
SET_DFNONE(x2)
|
||||
@@ -916,7 +1089,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
@@ -937,35 +1110,56 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF(((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
PASS2IF((box64_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDOx(x6, 0);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
GETEDOz(x6, 0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
PUSH1(xRIP);
|
||||
if(box64_dynarec_callret) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
BARRIER(1);
|
||||
GETEDOx(x6, 0);
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETEDOz(x6, 0);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH Ed");
|
||||
GETEDOx(x6, 0);
|
||||
PUSH1(ed);
|
||||
GETEDOz(x6, 0);
|
||||
PUSH1z(ed);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Executable → Regular
+626
-164
File diff suppressed because it is too large.
Load diff
Executable → Regular
+1290
-277
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -22,24 +21,20 @@
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
int64_t j64;
|
||||
int v0, v1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(j64);
|
||||
|
||||
// REX prefix before the 66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
GETREX();
|
||||
|
||||
/*if(rex.w && opcode!=0x0f) { // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
MESSAGE(LOG_DUMP, "Here!\n");
|
||||
@@ -51,7 +46,26 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
@@ -61,9 +75,10 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -86,13 +101,14 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
STRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
STRH_REG(gd, ed, x4);
|
||||
}
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -110,8 +126,9 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
LDRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, u8;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j64);
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
case 0x09:
|
||||
INST_NAME("LOCK OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDSETALH(x5, x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STSETLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
UXTHw(x6, xRAX);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
UXTHw(x1, ed);
|
||||
CMPSxw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
BFIx(ed, gd, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
}
|
||||
// Aligned version
|
||||
if(arm64_atomics) {
|
||||
MOVw_REG(x1, x6);
|
||||
CASALH(x1, gd, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
CMPSw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRH(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
}
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_MARK_nocond;
|
||||
// Unaligned version
|
||||
MARK3;
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
CMPSw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARK3(x4);
|
||||
STRH_U12(gd, wback, 0);
|
||||
}
|
||||
}
|
||||
SMDMB();
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("LOCK XADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
UXTHx(x5, gd);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
BFIx(gd, ed, 0, 16);
|
||||
emit_add16(dyn, ninst, x5, gd, x3, x4);
|
||||
BFIx(ed, x5, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
LDADDALH(x5, x1, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
ADDxw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add16(dyn, ninst, x2, x5, x3, x4);
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("LOCK ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_adc16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
LDADDALH(x5, x1, wback);
|
||||
UFLAG_IF {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("LOCK OR Ew, Iw");} else {INST_NAME("LOCK OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDSETALH(x5, x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STSETLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("LOCK ADC Ew, Iw");} else {INST_NAME("LOCK ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_adc16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SBB Ew, Iw");} else {INST_NAME("LOCK SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_sbb16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("LOCK AND Ew, Iw");} else {INST_NAME("LOCK AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_and16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
if(arm64_atomics) {
|
||||
MOV32w(x5, ~i32);
|
||||
UFLAG_IF {
|
||||
LDCLRALH(x5, x1, wback);
|
||||
MVNw_REG(x5, x5);
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STCLRLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MOV32w(x5, i32);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SUB Ew, Iw");} else {INST_NAME("LOCK SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_sub16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
NEGw_REG(x4, x5);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x4, x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STADDLH(x4, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("LOCK XOR Ew, Iw");} else {INST_NAME("LOCK XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
UXTHw(x6, ed);
|
||||
emit_xor16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDEORALH(x5, x1, wback);
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STEORLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("(LOCK) CMP Ew, Iw");} else {INST_NAME("(LOCK) CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x6, (opcode==0x81)?2:1);
|
||||
(void)wb1;
|
||||
// No need to LOCK, this is readonly
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
if(i32) {
|
||||
MOV32w(x5, i32);
|
||||
emit_cmp16(dyn, ninst, x6, x5, x3, x4, x6);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, ed, x3, x4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Ew
|
||||
INST_NAME("LOCK INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_inc16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
MOV32w(x3, 1);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x3, x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x4);
|
||||
} else {
|
||||
STADDLH(x3, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("LOCK DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_dec16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
MOV32w(x3, -1);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x3, x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x4);
|
||||
} else {
|
||||
STADDLH(x3, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
|
||||
uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x38: // SSE 4.x
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF1:
|
||||
INST_NAME("CRC32 Gd, Ew");
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGD;
|
||||
if(arm64_crc32) {
|
||||
CRC32CH(gd, gd, ed);
|
||||
} else {
|
||||
MOV32w(x2, 0x82f63b78);
|
||||
for(int j=0; j<2; ++j) {
|
||||
UBFXxw(x3, ed, 8*j, 8);
|
||||
EORw_REG(gd, gd, x3);
|
||||
for(int i=0; i<8; ++i) {
|
||||
LSRw_IMM((i&1)?gd:x4, (i&1)?x4:gd, 1);
|
||||
TBZ((i&1)?x4:gd, 0, 4+4);
|
||||
EORw_REG((i&1)?gd:x4, (i&1)?gd:x4, x2);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
|
||||
uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Executable → Regular
+789
-63
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -22,14 +21,6 @@
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
#define GETGm gd = ((nextop&0x38)>>3)
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
@@ -38,25 +29,32 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
// REX prefix before the 67 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
if(rex.is32bits) {
|
||||
// should do a different file
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
@@ -64,58 +62,244 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
INST_NAME("ADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x02:
|
||||
INST_NAME("ADD Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_add8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("ADD AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_add8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_add32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
INST_NAME("OR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x2);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("OR Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_or8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_or32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x0C:
|
||||
INST_NAME("OR AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_or8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_or32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
opcode=F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x11:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVUPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(rep) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVQ Gm, Em");
|
||||
nextop = F8;
|
||||
GETGm;
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); // no rex.b on MMX
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVQ Gm, Em");
|
||||
nextop = F8;
|
||||
GETGm;
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); // no rex.b on MMX
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("MOVDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
INST_NAME("MOVQ Em, Gm");
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVQ Em, Gm");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOV(v1, v0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOV(v1, v0);
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDB(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xB7:
|
||||
INST_NAME("MOVZX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UBFXxw(gd, ed, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDH(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -124,6 +308,484 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("ADC Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_adc32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("ADC Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x3);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_adc32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("ADC AL, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("ADC EAX, Id");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
MOV64xw(x1, i64);
|
||||
emit_adc32(dyn, ninst, rex, xRAX, x1, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x18:
|
||||
INST_NAME("SBB Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x1A:
|
||||
INST_NAME("SBB Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("SBB AL, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB EAX, Id");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_and8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_and32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("AND Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_and8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_and32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x24:
|
||||
INST_NAME("AND AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_and8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_and32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
INST_NAME("SUB Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sub8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("SUB Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_sub8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("SUB AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_sub8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_sub32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x30:
|
||||
INST_NAME("XOR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_xor8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x32:
|
||||
INST_NAME("XOR Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_xor8(dyn, ninst, x1, x2, x3, x4);
|
||||
GBBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x34:
|
||||
INST_NAME("XOR AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
emit_xor8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_xor32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
INST_NAME("CMP Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_cmp32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
break;
|
||||
case 0x3A:
|
||||
INST_NAME("CMP Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x3C:
|
||||
INST_NAME("CMP AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
UXTBw(x1, xRAX);
|
||||
if(u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
if(i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, xRAX, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x63:
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDSW(gd, ed, fixedaddress);
|
||||
}
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDW(gd, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
opcode=F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
STH(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ed, Id");} else {INST_NAME("ADD Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
nextop = F8;
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3);
|
||||
if(rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = xRAX + gd;
|
||||
} else {
|
||||
gb2 = ((gd&4)<<1);
|
||||
gb1 = xRAX+(gd&3);
|
||||
}
|
||||
if(gb2) {
|
||||
gd = x4;
|
||||
UBFXw(gd, gb1, gb2, 8);
|
||||
} else {
|
||||
gd = gb1; // no need to extract
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = (nextop&7) + (rex.b<<3);
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+ed;
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed&4)>>2); // L or H
|
||||
}
|
||||
BFIx(eb1, gd, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, &lock, 0, 0);
|
||||
STB(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ed, Gd");
|
||||
nextop=F8;
|
||||
@@ -131,8 +793,55 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
STRxw_U12(gd, ed, fixedaddress);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
STxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8A:
|
||||
INST_NAME("MOV Gb, Eb");
|
||||
nextop = F8;
|
||||
if(rex.rex) {
|
||||
gb1 = gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
gb2=0;
|
||||
} else {
|
||||
gd = (nextop&0x38)>>3;
|
||||
gb1 = xRAX+(gd&3);
|
||||
gb2 = ((gd&4)<<1);
|
||||
}
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
if(wb2) {
|
||||
UBFXw(x4, wback, wb2*8, 8);
|
||||
ed = x4;
|
||||
} else {
|
||||
ed = wback;
|
||||
}
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDB(x4, wback, fixedaddress);
|
||||
ed = x4;
|
||||
}
|
||||
BFIx(gb1, ed, gb2, 8);
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -143,8 +852,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
// should a geted32 be created, to use 32bits regs instead of 64bits?
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=gd) {
|
||||
MOVw_REG(gd, ed);
|
||||
}
|
||||
@@ -223,7 +931,24 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ed, Id");
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STxw(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
@@ -233,11 +958,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x64.barrier) \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
B(i32); \
|
||||
} \
|
||||
@@ -298,11 +1023,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED32H(x1, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
GETED32(4);
|
||||
GETED32(0);
|
||||
MVNxw_REG(ed, ed);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -316,7 +1041,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -330,11 +1054,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -348,6 +1072,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
@@ -366,9 +1091,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRAX, x2);
|
||||
MOVw_REG(xRDX, x4);
|
||||
} else {
|
||||
if(ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
|
||||
if(ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
|
||||
SET_DFNONE(x2);
|
||||
GETED32(0);
|
||||
@@ -391,6 +1116,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2)
|
||||
@@ -403,7 +1129,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRDX, x4);
|
||||
} else {
|
||||
if(ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) {
|
||||
SET_DFNONE(x2)
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGm gd = ((nextop&0x38)>>3)
|
||||
|
||||
uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
if(!rex.is32bits) {
|
||||
// should do a different file
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Seg:[Od], EAX");
|
||||
i32 = F16;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(i32<4096 && !(i32&3)) {
|
||||
STRw_U12(xRAX, x4, i32);
|
||||
} else if(i32<256) {
|
||||
STURw_I9(xRAX, x4, i32);
|
||||
} else {
|
||||
MOV32w(x1, i32);
|
||||
STRw_REG(xRAX, x4, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0, 0, 0);
|
||||
LDRw_REG(x3, ed, x4);
|
||||
PUSH1_32(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGm gd = ((nextop&0x38)>>3)
|
||||
|
||||
uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
if(!rex.is32bits) {
|
||||
// should do a different file
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 64:
|
||||
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -31,6 +30,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
|
||||
@@ -108,7 +108,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -178,15 +178,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
@@ -198,8 +198,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
@@ -211,8 +211,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
@@ -225,8 +225,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
@@ -234,14 +234,14 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
@@ -253,8 +253,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
} else {
|
||||
@@ -266,8 +266,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
@@ -279,8 +279,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -31,7 +30,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
@@ -50,7 +51,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v2 = x87_do_push(dyn, ninst, x1, X87_ST(nextop&7));
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, X87_ST(nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS(v2, v1);
|
||||
@@ -71,6 +72,8 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
|
||||
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
@@ -79,6 +82,24 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FNOP");
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
INST_NAME("FSTPNCE ST0, ST0");
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FSTPNCE ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
x87_get_st_empty(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
|
||||
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
INST_NAME("FCHS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
@@ -117,7 +138,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
@@ -126,82 +147,123 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, L2T);
|
||||
break;
|
||||
case 0xEA:
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, L2E);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, PI);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, LG2);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
FTABLE64(v1, LN2);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
VEOR(v1, v1, v1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1);
|
||||
CALL(native_f2xm1, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
CALL(native_fyl2x, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
CALL(native_ftan, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
if(PK(0)==0xdd && PK(1)==0xd8) {
|
||||
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emiting 1\n");
|
||||
u8 = F8;
|
||||
u8 = F8;
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
CALL(native_fpatan, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1);
|
||||
CALL(native_fxtract, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
#if 0
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1);
|
||||
CALL(native_fprem1, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
#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(dyn);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
FMULD(s0, s0, v2);
|
||||
FSUBD(v1, v1, s0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -221,18 +283,45 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1);
|
||||
CALL(native_fprem, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
#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(dyn);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
FMULD(s0, s0, v2);
|
||||
FSUBD(v1, v1, s0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
CALL(native_fyl2xp1, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
@@ -246,46 +335,54 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fsincos, -1);
|
||||
CALL(native_fsincos, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
#if 0
|
||||
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);
|
||||
/*
|
||||
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
|
||||
CALL(native_frndint, -1);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
VCVT_S32_F64(x1, v1); // limit to 32bits....
|
||||
VCVT_F64_S32(v1, x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTIS(v1, v1);
|
||||
} else {
|
||||
FRINTID(v1, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
*/
|
||||
#endif
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fscale, -1);
|
||||
CALL(native_fscale, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fsin, -1);
|
||||
CALL(native_fsin, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fcos, -1);
|
||||
CALL(native_fcos, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
|
||||
|
||||
@@ -294,14 +391,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
@@ -309,20 +398,16 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xEF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_D_S(v1, s0);
|
||||
FCVT_D_S(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -334,27 +419,24 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(s0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(s0, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_S_D(v1, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(s0, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
VST32(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
@@ -365,14 +447,12 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFXw(x1, x1, 10, 2); // extract round
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_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, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
@@ -381,7 +461,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
int64_t j64;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
int v1, v2;
|
||||
int d0;
|
||||
int s0;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(ed);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVB ST0, STx");
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTw_mask(xFlags, 0, 0); //mask=1<<F_CF
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cNE); // F_CF==1
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cNE); // F_CF==1
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVE ST0, STx");
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=1<<F_ZF
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cNE);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cNE); // F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVBE ST0, STx");
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
MOV32w(x1, (1<<F_CF)|(1<<F_ZF));
|
||||
TSTw_REG(xFlags, x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cNE);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cNE); // F_CF==0 & F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVU ST0, STx");
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTw_mask(xFlags, 0b011110, 0); //mask=1<<F_PF
|
||||
if(ST_IS_F(0)) {
|
||||
FCSELS(v1, v2, v1, cNE);
|
||||
} else {
|
||||
FCSELD(v1, v2, v1, cNE); // F_PF==0
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FUCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -33,6 +32,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
@@ -156,7 +156,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
@@ -188,25 +188,19 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
SXTL_32(v1, s0);
|
||||
SCVTFDD(v1, v1);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
SXTL_32(v1, v1); // i32 -> i64
|
||||
SCVTFDD(v1, v1); // i64 -> double
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
FRINT32ZD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
@@ -217,28 +211,23 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FRINTZD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
VST32(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
@@ -249,11 +238,11 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
VST32(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -262,15 +251,10 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
@@ -281,47 +265,114 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VSTR32_U12(s0, wback, fixedaddress);
|
||||
VST32(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x80000000);
|
||||
STRw_U12(x5, wback, fixedaddress);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if((PK(0)==0xDB && ((PK(1)>>3)&7)==7) || (PK(0)>=0x40 && PK(0)<=0x4f && PK(1)==0xDB && ((PK(2)>>3)&7)==7)) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; //0xDB
|
||||
nextop = F8; // 0xDB or rex
|
||||
if(nextop>=0x40 && nextop<=0x4f) {
|
||||
rex.rex = nextop;
|
||||
nextop = F8; //0xDB
|
||||
} else
|
||||
rex.rex = 0;
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
if(box64_x87_no80bits) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x3);
|
||||
CALL(native_fld, -1);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
if(box64_x87_no80bits) {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
#if 0
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL(native_fstp, -1);
|
||||
#else
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
FMOVxD(x1, v1);
|
||||
// do special value first
|
||||
TSTx_mask(x1, 1, 0b00000, 0b111110); //0x7fffffffffffffffL
|
||||
B_MARK(cNE);
|
||||
// Zero
|
||||
LSRx(x3, x1, 63-15); //x3 = sign+exp
|
||||
MOVZw(x5, 0); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// get sign, in main ouput x5 for sign+exp
|
||||
ANDx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
LSRx(x5, x5, 63-15); // x5 = sign
|
||||
// get exp
|
||||
LSRx(x3, x1, 52); // x3 = exp11
|
||||
ANDw_mask(x3, x3, 0, 0b1010); //0x7ff
|
||||
MOV32w(x4, 0x7ff);
|
||||
CMPSw_REG(x3, x4);
|
||||
B_MARK2(cNE);
|
||||
// NaN and Infinite
|
||||
ORRw_mask(x3, x5, 0, 0b1110); //x3 = sign | 0x7fff
|
||||
TSTx_mask(x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
ORRx_mask(x4, xZR, 1, 0b10, 0b01); //0xc000000000000000
|
||||
CSELx(x5, x5, x4, cEQ); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// regular / denormals
|
||||
ANDx_mask(x1, x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
LSLx_IMM(x1, x1, 11); //x1 = mantisse missing "1"
|
||||
MOVZw(x4, 16383-1023); //BIAS80 - BIAS64
|
||||
CBZw(x3, 4+3*4); // exp11 == 0?
|
||||
// normals
|
||||
ADDw_REG(x3, x3, x4); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
#endif
|
||||
}
|
||||
CALL(arm_fstp, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -31,6 +30,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t nextop = F8;
|
||||
uint8_t wback;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
@@ -106,7 +106,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -158,7 +158,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
@@ -182,24 +182,24 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADD ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
@@ -207,42 +207,42 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
|
||||
VLDR64_U12(v2, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -31,12 +30,15 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -72,7 +74,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -83,8 +85,10 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
x87_get_st_empty(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
|
||||
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -122,7 +126,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -156,53 +160,72 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_I64);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
if(ST_IS_I64(0)) {
|
||||
VST64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// those are ARM 8.5 opcode!
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTRRD(s0, v1, 3);
|
||||
FCVTZSxD(x2, s0);
|
||||
STx(x2, ed, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STx(x5, ed, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1);
|
||||
CALL(native_frstor, -1);
|
||||
break;
|
||||
case 6:
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1);
|
||||
CALL(native_fsave, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
//fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
if(dyn->n.x87stack) {
|
||||
@@ -215,7 +238,8 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, x2, 0, 2);
|
||||
}
|
||||
BFIw(x3, x2, 11, 3); // inject TOP at bit 11 (3 bits)
|
||||
STRH_U12(x3, ed, fixedaddress); // store whole sw flags
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
STH(x3, ed, fixedaddress); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t wback;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOMP ST0, STx"); //yep
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
INST_NAME("FCOMPP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
DEFAULT;
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -34,6 +33,8 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int s0;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int i1;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
@@ -51,15 +52,24 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
if(dyn->n.x87stack) {
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUBw_U12(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADDw_U12(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
}
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
BFIw(x1, x2, 11, 3); // inject top
|
||||
BFIw(xRAX, x1, 0, 16);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -80,7 +90,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -101,7 +111,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -150,9 +160,9 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRSHw_U12(x1, wback, fixedaddress);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDSHw(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
SCVTFSw(v1, x1);
|
||||
} else {
|
||||
@@ -162,7 +172,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -172,10 +182,11 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
VST16(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
BFCw(x5, FPSR_QC, 1); // reset QC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
VFCVTZSs(s0, v1);
|
||||
@@ -183,21 +194,24 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, v1);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
SXTHw(x5, x3); // check if 16bits value is fine
|
||||
SUBw_REG(x5, x5, x3);
|
||||
CBZw_MARK3(x5);
|
||||
MARK2;
|
||||
MOV32w(x3, 0x8000);
|
||||
MARK3;
|
||||
STH(x3, wback, fixedaddress);
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -206,10 +220,11 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
VST16(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
BFCw(x5, FPSR_QC, 1); // reset QC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTXS(s0, v1);
|
||||
@@ -219,13 +234,16 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
SXTHw(x5, x3); // check if 16bits value is fine
|
||||
SUBw_REG(x5, x5, x3);
|
||||
CBZw_MARK3(x5);
|
||||
MARK2;
|
||||
MOV32w(x3, 0x8000);
|
||||
MARK3;
|
||||
STH(x3, wback, fixedaddress);
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -233,7 +251,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
@@ -242,7 +260,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
VST16(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
@@ -255,65 +273,120 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
SQXTN_H_S(s0, s0);
|
||||
VSTR16_U12(s0, wback, fixedaddress);
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV32w(x5, 0x8000);
|
||||
STRH_U12(x5, wback, fixedaddress);
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
SXTHw(x5, x3); // check if 16bits value is fine
|
||||
SUBw_REG(x5, x5, x3);
|
||||
CBZw_MARK3(x5);
|
||||
MARK2;
|
||||
MOV32w(x3, 0x8000);
|
||||
MARK3;
|
||||
STH(x3, wback, fixedaddress);
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbld, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
LDRx_U12(x1, wback, fixedaddress);
|
||||
SCVTFDx(v1, x1);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_I64);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, wback, fixedaddress);
|
||||
if(!ST_IS_I64(0)) {
|
||||
if(rex.is32bits) {
|
||||
// need to also feed the STll stuff...
|
||||
ADDx_U12(x4, xEmu, offsetof(x64emu_t, fpu_ll));
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUBw_U12(x1, x1, -a);
|
||||
} else {
|
||||
ADDw_U12(x1, x1, a);
|
||||
}
|
||||
ANDw_mask(x1, x1, 0, 2); //mask=7
|
||||
}
|
||||
ADDx_REG_LSL(x1, x4, x1, 4); // fpu_ll is 2 i64
|
||||
VSTR64_U12(v1, x1, 8); // ll
|
||||
}
|
||||
SCVTFDD(v1, v1);
|
||||
if(rex.is32bits) {
|
||||
VSTR64_U12(v1, x1, 0); // ref
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_I64);
|
||||
if(!ST_IS_I64(0)) {
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT64XD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
MOV64x(x5, 0x8000000000000000LL);
|
||||
STRx_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(ST_IS_I64(0)) {
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
#if 0
|
||||
FRINT64XD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VSTR64_U12(s0, wback, fixedaddress);
|
||||
#else
|
||||
if(rex.is32bits) {
|
||||
// need to check STll first...
|
||||
ADDx_U12(x5, xEmu, offsetof(x64emu_t, fpu_ll));
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, top));
|
||||
VMOVQDto(x3, v1, 0);
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUBw_U12(x1, x1, -a);
|
||||
} else {
|
||||
ADDw_U12(x1, x1, a);
|
||||
}
|
||||
ANDw_mask(x1, x1, 0, 2); //mask=7
|
||||
}
|
||||
ADDx_REG_LSL(x1, x5, x1, 4); // fpu_ll is 2 i64
|
||||
LDRx_U12(x5, x1, 0); // ref
|
||||
SUBx_REG(x5, x5, x3);
|
||||
CBNZx_MARK2(x5);
|
||||
LDRx_U12(x5, x1, 8); // ll
|
||||
STx(x5, wback, fixedaddress);
|
||||
B_MARK3(c__);
|
||||
MARK2;
|
||||
}
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STx(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
Executable → Regular
+15
-101
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -16,7 +15,6 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
@@ -28,8 +26,6 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -49,7 +45,7 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -60,14 +56,11 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
MOV64xw(s3, c);
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -83,7 +76,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -95,8 +88,6 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -116,7 +107,7 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -127,14 +118,11 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
MOV64xw(s3, c);
|
||||
EORxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -150,7 +138,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -162,8 +150,6 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -186,7 +172,7 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -197,14 +183,11 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
MOV64xw(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
@@ -223,7 +206,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -235,8 +218,6 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -249,15 +230,7 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -268,8 +241,6 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -282,15 +253,7 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -301,8 +264,6 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -315,15 +276,7 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -334,8 +287,6 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -348,15 +299,7 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -367,8 +310,6 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -403,8 +344,6 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -440,8 +379,6 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -454,15 +391,7 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -519,8 +448,6 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -533,15 +460,7 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -598,8 +517,6 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -612,9 +529,6 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
|
||||
Executable → Regular
+41
-222
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -16,7 +15,6 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
@@ -77,7 +75,7 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.need_flags==X_PEND))
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<0x1000) {
|
||||
@@ -157,8 +155,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
MVNxw_REG(s3, s1);
|
||||
ORRxw_REG(s3, s3, s2); // s3 = ~op1 | op2
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICxw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
@@ -201,7 +198,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.need_flags==X_PEND))
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
// special case when doing math on RSP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<0x1000) {
|
||||
@@ -306,15 +303,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); //mask=0xff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -332,7 +321,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
if(X_PEND) {} else {MOV32w(s4, c&0xff);}
|
||||
IFX(X_PEND) {} else {MOV32w(s4, c&0xff);}
|
||||
ORRw_REG(s3, s1, s4); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s1, s4); // s4 = op1 & op2
|
||||
}
|
||||
@@ -358,15 +347,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -410,15 +391,7 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); //mask=0xff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -433,7 +406,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sub8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -468,15 +441,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -519,15 +484,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -612,8 +569,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s3, s1);
|
||||
ORRw_REG(s3, s3, s2); // s3 = ~op1 | op2
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICw_REG(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
|
||||
@@ -638,15 +594,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -796,16 +744,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); //mask=0xff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -842,15 +781,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_mask(s1, 0, 0b001111); // mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -910,7 +841,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -920,7 +851,11 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
ANDw_mask(s4, s3, 0, 0); // s4 = ~op1 & op2
|
||||
ORRw_mask(s3, s3, 0, 0); // s3 = ~op1 | op2
|
||||
}
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
IFX(X_ZF) {
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
} else {
|
||||
SUBw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -962,7 +897,11 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1);
|
||||
}
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
IFX(X_ZF) {
|
||||
SUBSw_U12(s1, s1, 1);
|
||||
} else {
|
||||
SUBw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1158,15 +1097,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
LSRw(s3, s1, 8);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); //mask=0xff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -1177,54 +1108,7 @@ void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
{
|
||||
MAYUSE(s5);
|
||||
MOV32w(s5, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_adc8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
MOVw_REG(s4, s1);
|
||||
}
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
ADCw_REG(s1, s1, s5);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_REG(s3, s4, s5); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s4, s5); // s4 = op1 & op2
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s4 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRw(s3, s1, 8);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
emit_adc8(dyn, ninst, s1, s5, s3, s4);
|
||||
}
|
||||
|
||||
// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1246,7 +1130,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
ADCw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_REG(s3, s4, s2); // s3 = op1 | op2
|
||||
@@ -1267,15 +1151,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
LSRw(s3, s1, 16);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -1517,15 +1393,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); //mask=0xff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -1536,55 +1404,7 @@ void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
{
|
||||
MAYUSE(s5);
|
||||
MOV32w(s5, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sbb8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C, bit 29
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s4, s1);
|
||||
}
|
||||
SBCw_REG(s1, s1, s5);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORRw_REG(s3, s4, s5); // s3 = ~op1 | op2
|
||||
ANDw_REG(s4, s4, s5); // s4 = ~op1 & op2
|
||||
ANDw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 7);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
emit_sbb8(dyn, ninst, s1, s5, s3, s4);
|
||||
}
|
||||
|
||||
// emit SBB16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1628,15 +1448,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -1773,7 +1585,11 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGSw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
NEGSw_REG(s1, s1);
|
||||
} else {
|
||||
NEGw_REG(s1, s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1819,7 +1635,10 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGSw_REG(s1, s1);
|
||||
NEGw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); // mask 0xff
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
Executable → Regular
+986
-72
File diff suppressed because it is too large.
Load diff
Executable → Regular
+18
-71
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -16,7 +15,6 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
@@ -85,19 +83,14 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
SUBSxw_U12(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_OF|X_AF) {
|
||||
MOV32w(s4, (1<<F_OF)|(1<<F_AF));
|
||||
IFX(X_OF|X_AF|X_CF) {
|
||||
MOV32w(s4, (1<<F_OF)|(1<<F_AF)|(1<<F_CF));
|
||||
BICw(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
@@ -122,15 +115,7 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_mask(s5, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s5, 16)
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1); // s4 = ~d
|
||||
@@ -174,15 +159,7 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s1, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -198,22 +175,11 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
SUBSw_REG(s5, s1, s2); // res = s1 - s2
|
||||
} else {
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
}
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s5, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s5, 8)
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
ORNw_REG(s4, s2, s1); // s4 = ~d | s
|
||||
@@ -255,22 +221,14 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX_PENDOR0 {
|
||||
@@ -296,18 +254,11 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
ANDw_mask(s3, s3, 0b011011, 0b000010); // 0xE0
|
||||
LSRw(s3, s3, 5);
|
||||
MOV64x(s4, (uintptr_t)GetParityTab());
|
||||
LDRw_REG_LSL2(s4, s4, s3);
|
||||
ANDw_mask(s3, s1, 0, 0b000100); // 0x1f
|
||||
LSRw_REG(s4, s4, s3);
|
||||
MVNx_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
@@ -316,11 +267,9 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
@@ -340,7 +289,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, s4 and s5 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
@@ -349,11 +298,9 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
|
||||
+1090
-567
File diff suppressed because it is too large.
Load diff
Executable → Regular
+172
-92
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -22,28 +21,6 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x2 get used)
|
||||
#define GETEX(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a, w) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
@@ -51,18 +28,15 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t u8;
|
||||
uint64_t u64, j64;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
#ifdef PRECISE_CVT
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
#endif
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
@@ -81,9 +55,10 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress); // upper part reseted
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -96,8 +71,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -109,9 +85,10 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
break;
|
||||
@@ -134,33 +111,94 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0, 0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
ADR(xLR, GETMARK);
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR);
|
||||
MARK;
|
||||
FCVTNSxwD(gd, q0); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
FCVTMSxwD(gd, q0); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
FCVTPSxwD(gd, q0); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
FCVTZSxwD(gd, q0); // 3: Toward 0
|
||||
#else
|
||||
FCVTNSxwD(gd, q0);
|
||||
#endif
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FRINTID(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38: // these are some more SSSE4.2+ opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("CRC32 Gd, Eb");
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGD;
|
||||
if(arm64_crc32) {
|
||||
CRC32CB(gd, gd, ed);
|
||||
} else {
|
||||
EORw_REG(gd, gd, ed);
|
||||
MOV32w(x2, 0x82f63b78);
|
||||
for(int i=0; i<8; ++i) {
|
||||
LSRw_IMM((i&1)?gd:x4, (i&1)?x4:gd, 1);
|
||||
TBZ((i&1)?x4:gd, 0, 4+4);
|
||||
EORw_REG((i&1)?gd:x4, (i&1)?gd:x4, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("CRC32 Gd, Ed");
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(arm64_crc32) {
|
||||
CRC32Cxw(gd, gd, ed);
|
||||
} else {
|
||||
MOV32w(x2, 0x82f63b78);
|
||||
for(int j=0; j<4*(1+rex.w); ++j) {
|
||||
UBFXxw(x3, ed, 8*j, 8);
|
||||
EORw_REG(gd, gd, x3);
|
||||
for(int i=0; i<8; ++i) {
|
||||
LSRw_IMM((i&1)?gd:x4, (i&1)?x4:gd, 1);
|
||||
TBZ((i&1)?x4:gd, 0, 4+4);
|
||||
EORw_REG((i&1)?gd:x4, (i&1)?gd:x4, x2);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -169,15 +207,15 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FCMLTD_0(v1, d0);
|
||||
SHL_64(v1, v1, 63);
|
||||
}
|
||||
FSQRTD(d1, d0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FSQRTD(d1, d0);
|
||||
VORR(d1, d1, v1);
|
||||
} else {
|
||||
FSQRTD(d1, d0);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -187,20 +225,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
FCMEQD(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -209,20 +247,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FMULD(v1, d1, d0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FMULD(v1, d1, d0);
|
||||
FCMEQD(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULD(v1, d1, d0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -230,7 +268,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -241,20 +279,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSUBD(v1, d1, d0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FSUBD(v1, d1, d0);
|
||||
FCMEQD(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBD(v1, d1, d0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -262,7 +300,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -270,7 +308,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPD(v0, v1);
|
||||
B_NEXT(cLS); //Less than or equal
|
||||
B_NEXT(cCC); //Less than
|
||||
VMOVeD(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
@@ -279,20 +317,20 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// check if any input value was NAN
|
||||
FMAXD(d0, v0, v1); // propagate NAN
|
||||
FCMEQD(d0, d0, d0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FDIVD(d1, v0, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FDIVD(d1, v0, v1);
|
||||
FCMEQD(q0, d1, d1); // 0 => out is NAN
|
||||
VBIC(q0, d0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVD(d1, v0, v1);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -300,7 +338,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -308,7 +346,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPD(v0, v1);
|
||||
B_NEXT(cGE); //Greater than or equal
|
||||
B_NEXT(cGT); //Greater than
|
||||
VMOVeD(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
@@ -343,18 +381,33 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
VLD128(v1, ed, fixedaddress);
|
||||
}
|
||||
VFADDPQS(v0, v0, v1);
|
||||
break;
|
||||
|
||||
case 0x7D:
|
||||
INST_NAME("HSUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLD128(v1, ed, fixedaddress);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VUZP1Q_32(d0, v0, v1);
|
||||
VUZP2Q_32(v0, v0, v1);
|
||||
VFSUBQS(v0, d0, v0);
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
GETEXSD(v1, 0, 1);
|
||||
u8 = F8;
|
||||
FCMPD(v0, v1);
|
||||
switch(u8&7) {
|
||||
@@ -387,7 +440,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
VMOV(v0, v1);
|
||||
break;
|
||||
|
||||
@@ -396,11 +449,37 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(v0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VFCVTNSQD(v0, v0); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
if(box64_dynarec_fastround) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(v0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VFCVTNSQD(v0, v0); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x4);
|
||||
VMOVQSfrom(v0, i, x1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
@@ -413,8 +492,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 7, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 7, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Executable → Regular
+143
-90
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -22,24 +21,6 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get Ex as a single, not a quad (warning, x2 get used)
|
||||
#define GETEX(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
|
||||
VLDR32_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a, w) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
@@ -53,6 +34,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(d0);
|
||||
@@ -75,21 +57,23 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -98,9 +82,10 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
@@ -112,9 +97,10 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
@@ -144,39 +130,54 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0, 0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
ADR(xLR, GETMARK);
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR);
|
||||
FCVTNSxwS(gd, q0); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
FCVTMSxwS(gd, q0); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
FCVTPSxwS(gd, q0); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
FCVTZSxwS(gd, q0); // 3: Toward 0
|
||||
#else
|
||||
FCVTNSxwS(gd, q0);
|
||||
#endif
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FRINTIS(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -184,7 +185,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
@@ -201,7 +202,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("RCPSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
@@ -213,7 +214,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -222,7 +223,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -230,17 +231,35 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d0, v1);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(d0, 0, 0);
|
||||
GETEX(v1, 0, 0) ;
|
||||
GETGX_empty(v0);
|
||||
VFCVTZSQS(v0, d0);
|
||||
if(box64_dynarec_fastround) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
@@ -248,7 +267,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -256,7 +275,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -273,7 +292,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0, 0);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -281,7 +300,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
@@ -297,21 +316,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 1);
|
||||
GETEX(v1, 0, 1) ;
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
@@ -339,8 +358,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
@@ -351,8 +371,45 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
GETED(0);
|
||||
if(rex.w)
|
||||
VMOVQDfrom(v1, 0, ed);
|
||||
else {
|
||||
MOVxw_REG(x1, ed); // need to clear uper part
|
||||
VMOVQDfrom(v1, 0, x1);
|
||||
}
|
||||
} else {
|
||||
if(rex.w) {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
GETED(0); // just load and clear the upper part
|
||||
VMOVQDfrom(v1, 0, ed);
|
||||
}
|
||||
}
|
||||
CNT_8(v1, v1);
|
||||
UADDLV_8(v1, v1);
|
||||
VMOVQDto(gd, v1, 0);
|
||||
IFX(X_ALL) {
|
||||
MOV32w(x1, (1<<F_OF) | (1<<F_SF) | (1<<F_ZF) | (1<<F_AF) | (1<<F_CF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
CBNZx(gd, 4+4);
|
||||
BFIw(xFlags, xFlags, F_ZF, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -364,12 +421,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
BFIw(xFlags, x1, F_CF, 1); // CF = is source 0?
|
||||
RBITxw(x1, ed); // reverse
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == TZCNT
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
RBITxw(x3, ed); // reverse
|
||||
CLZxw(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1); // ZF = is dest 0?
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
@@ -379,18 +437,19 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
BFIw(xFlags, x1, F_CF, 1); // CF = is source 0?
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == LZCNT
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
CLZxw(gd, ed); // x2 gets leading 0 == LZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1); // ZF = is dest 0?
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
GETEXSS(v1, 0, 1);
|
||||
u8 = F8;
|
||||
FCMPS(v0, v1);
|
||||
switch(u8&7) {
|
||||
@@ -415,22 +474,16 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
// cannot use GETEX because we want 64bits not 32bits
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
SXTL_32(v0, v1);
|
||||
|
||||
Executable → Regular
+122
-389
@@ -1,7 +1,6 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
@@ -13,7 +12,6 @@
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -28,293 +26,10 @@
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
}
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
(void)emu;
|
||||
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
}
|
||||
void arm_fyl2x(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
}
|
||||
void arm_ftan(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_fpatan(x64emu_t* emu)
|
||||
{
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void arm_fxtract(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
}
|
||||
void arm_fprem(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
void arm_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void arm_fsincos(x64emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_frndint(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void arm_fscale(x64emu_t* emu)
|
||||
{
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void arm_fsin(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_fcos(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).sq = tmp;
|
||||
STll(0).sref = ST0.sq;
|
||||
}
|
||||
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).sref==ST(0).sq) {
|
||||
memcpy(ed, &STll(0).sq, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_ud(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void arm_fprem1(x64emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void arm_aesimc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void arm_aesmc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void arm_aesdlast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
const uint8_t invsubbytes[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
|
||||
|
||||
}
|
||||
void arm_aeselast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A F K P E J O D I N C H M B G L
|
||||
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
const uint8_t subbytes[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
|
||||
//STATE ← SubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
|
||||
}
|
||||
void arm_aesd(x64emu_t* emu, int xmm)
|
||||
{
|
||||
arm_aesdlast(emu, xmm);
|
||||
arm_aesimc(emu, xmm);
|
||||
}
|
||||
void arm_aese(x64emu_t* emu, int xmm)
|
||||
{
|
||||
arm_aeselast(emu, xmm);
|
||||
arm_aesmc(emu, xmm);
|
||||
}
|
||||
|
||||
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
#define SCRATCH0 24
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn)
|
||||
@@ -342,7 +57,7 @@ void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
dyn->n.fpuused[reg] = 0;
|
||||
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D)
|
||||
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_I64)
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
}
|
||||
// Get an MMX double reg
|
||||
@@ -351,6 +66,7 @@ int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
|
||||
dyn->n.fpuused[EMM0 + emm] = 1;
|
||||
dyn->n.neoncache[EMM0 + emm].t = NEON_CACHE_MM;
|
||||
dyn->n.neoncache[EMM0 + emm].n = emm;
|
||||
dyn->n.news |= (1<<(EMM0 + emm));
|
||||
return EMM0 + emm;
|
||||
}
|
||||
// Get an XMM quad reg
|
||||
@@ -365,6 +81,7 @@ int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
|
||||
dyn->n.fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.neoncache[i].n = xmm;
|
||||
dyn->n.news |= (1<<i);
|
||||
return i;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
@@ -378,6 +95,15 @@ void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
|
||||
}
|
||||
|
||||
int neoncache_no_i64(dynarec_arm_t* dyn, int ninst, int st, int a)
|
||||
{
|
||||
if(a==NEON_CACHE_ST_I64) {
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if (dyn->insts[ninst].n.swapped) {
|
||||
@@ -388,7 +114,8 @@ int neoncache_get_st(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].t==NEON_CACHE_ST_D)
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_I64)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return dyn->insts[ninst].n.neoncache[i].t;
|
||||
// not in the cache yet, so will be fetched...
|
||||
@@ -402,7 +129,8 @@ int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
return NEON_CACHE_ST_D;
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_D
|
||||
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_I64)
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
return dyn->n.neoncache[i].t;
|
||||
// not in the cache yet, so will be fetched...
|
||||
@@ -419,7 +147,18 @@ int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int neoncache_get_st_f_i64(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
/*if(a+dyn->insts[ninst].n.stack_next-st<0)
|
||||
// The STx has been pushed at the end of instructon, so stop going back
|
||||
return -1;*/
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_I64 || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F)
|
||||
&& 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)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
@@ -427,7 +166,15 @@ int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int neoncache_get_st_f_i64_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_I64 || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
@@ -435,7 +182,15 @@ int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a)
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int neoncache_get_current_st_f_i64(dynarec_arm_t* dyn, int a)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_ST_I64 || dyn->n.neoncache[i].t==NEON_CACHE_ST_F)
|
||||
&& 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);
|
||||
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)
|
||||
@@ -443,9 +198,9 @@ static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int
|
||||
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
|
||||
} else
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
int i = neoncache_get_st_f_i64_noback(dyn, ninst, a);
|
||||
//if(box64_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;
|
||||
@@ -464,7 +219,7 @@ static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int
|
||||
return;
|
||||
while(ninst>=0) {
|
||||
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);
|
||||
int i = neoncache_get_st_f_i64(dyn, ninst, a);
|
||||
//if(box64_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;
|
||||
@@ -499,7 +254,7 @@ static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
int i = neoncache_get_st_f_i64_noback(dyn, ninst, a);
|
||||
//if(box64_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;
|
||||
@@ -520,7 +275,7 @@ static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int
|
||||
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
int i = neoncache_get_current_st_f(dyn, a);
|
||||
int i = neoncache_get_current_st_f_i64(dyn, a);
|
||||
//if(box64_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;
|
||||
@@ -553,31 +308,23 @@ int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
if( neoncache_get_current_st(dyn, ninst, a)==NEON_CACHE_ST_F
|
||||
&& neoncache_get_current_st(dyn, ninst, b)==NEON_CACHE_ST_F )
|
||||
return NEON_CACHE_ST_F;
|
||||
// don't combine i64, it's only for load/store
|
||||
/*if( neoncache_get_current_st(dyn, ninst, a)==NEON_CACHE_ST_I64
|
||||
&& neoncache_get_current_st(dyn, ninst, b)==NEON_CACHE_ST_I64 )
|
||||
return NEON_CACHE_ST_I64;*/
|
||||
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];
|
||||
}
|
||||
|
||||
int isCacheEmpty(dynarec_arm_t* dyn, int ninst) {
|
||||
static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 0;
|
||||
}
|
||||
for(int i=0; i<24; ++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].t==NEON_CACHE_ST_F
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_I64)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
return 0;
|
||||
}
|
||||
@@ -600,7 +347,9 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
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].t==NEON_CACHE_ST_F
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_I64)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
ret = 1;
|
||||
}
|
||||
@@ -636,10 +385,10 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
{
|
||||
if(cache->swapped) {
|
||||
// unswap
|
||||
int a = -1;
|
||||
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].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F || cache->neoncache[j].t == NEON_CACHE_ST_I64)) {
|
||||
if(cache->neoncache[j].n == cache->combined1)
|
||||
a = j;
|
||||
else if(cache->neoncache[j].n == cache->combined2)
|
||||
@@ -663,7 +412,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
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].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F || cache->neoncache[j].t == NEON_CACHE_ST_I64)) {
|
||||
if(cache->neoncache[j].n<cache->stack_push)
|
||||
cache->neoncache[j].v = 0;
|
||||
else
|
||||
@@ -708,6 +457,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
case NEON_CACHE_ST_D:
|
||||
case NEON_CACHE_ST_I64:
|
||||
cache->x87cache[x87reg] = cache->neoncache[i].n;
|
||||
cache->x87reg[x87reg] = i;
|
||||
++x87reg;
|
||||
@@ -725,7 +475,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
@@ -765,64 +514,8 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
(void)dyn; (void)addr; (void)ninst;
|
||||
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
|
||||
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = (uintptr_t)getAlternate(*(void**)a1);
|
||||
}
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
#undef F32S64
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
@@ -830,6 +523,7 @@ const char* getCacheName(int t, int n)
|
||||
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_ST_I64: sprintf(buff, "STi%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;
|
||||
@@ -839,20 +533,59 @@ const char* getCacheName(int t, int n)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst)
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
// check flags cache
|
||||
if(dyn->insts[ninst].f_entry.dfnone || dyn->insts[ninst].f_entry.pending)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].x64.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;
|
||||
if(box64_dynarec_dump) {
|
||||
printf_x64_instruction(rex.is32bits?my_context->dec32:my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d/%d",
|
||||
(box64_dynarec_dump>1)?"\e[32m":"",
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address),
|
||||
dyn->insts[ninst].size/4,
|
||||
ninst,
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
dyn->f.pending,
|
||||
dyn->f.dfnone,
|
||||
dyn->insts[ninst].x64.may_set?"may":"set",
|
||||
dyn->insts[ninst].x64.set_flags,
|
||||
dyn->insts[ninst].x64.gen_flags,
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smread, dyn->smwrite);
|
||||
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].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)
|
||||
dynarec_log(LOG_NONE, ", jmp=out");
|
||||
if(dyn->last_ip)
|
||||
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);
|
||||
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:%s", ii, 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, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_I64: dynarec_log(LOG_NONE, " D%d:%s", ii, 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, 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, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, 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 || 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", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode)
|
||||
{
|
||||
dynarec_log(LOG_NONE, "\t%08x\t%s\n", opcode, arm64_print(opcode, (uintptr_t)dyn->block));
|
||||
}
|
||||
Executable → Regular
+17
-53
@@ -1,42 +1,9 @@
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
#include "../dynarec_native_functions.h"
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu);
|
||||
void arm_fyl2x(x64emu_t* emu);
|
||||
void arm_ftan(x64emu_t* emu);
|
||||
void arm_fpatan(x64emu_t* emu);
|
||||
void arm_fxtract(x64emu_t* emu);
|
||||
void arm_fprem(x64emu_t* emu);
|
||||
void arm_fyl2xp1(x64emu_t* emu);
|
||||
void arm_fsincos(x64emu_t* emu);
|
||||
void arm_frndint(x64emu_t* emu);
|
||||
void arm_fscale(x64emu_t* emu);
|
||||
void arm_fsin(x64emu_t* emu);
|
||||
void arm_fcos(x64emu_t* emu);
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x64emu_t* emu);
|
||||
|
||||
void arm_aesd(x64emu_t* emu, int xmm);
|
||||
void arm_aese(x64emu_t* emu, int xmm);
|
||||
void arm_aesdlast(x64emu_t* emu, int xmm);
|
||||
void arm_aeselast(x64emu_t* emu, int xmm);
|
||||
void arm_aesimc(x64emu_t* emu, int xmm);
|
||||
|
||||
|
||||
void arm_ud(x64emu_t* emu);
|
||||
#define SCRATCH0 24
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn);
|
||||
@@ -56,38 +23,35 @@ void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
// ---- Neon cache functions
|
||||
// Get type for STx
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or DOUBLE
|
||||
// Get if STx is FLOAT
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or I64
|
||||
int neoncache_get_st_f_i64(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
|
||||
// Get actual STx is FLOAT
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a);
|
||||
// Get actual STx is FLOAT or I64
|
||||
int neoncache_get_current_st_f_i64(dynarec_arm_t* dyn, int a);
|
||||
// Back-propagate a change float->double
|
||||
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*
|
||||
// Do not allow i64 type
|
||||
int neoncache_no_i64(dynarec_arm_t* dyn, int ninst, int st, int a);
|
||||
|
||||
// FPU Cache transformation (for loops)
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
|
||||
// FPU Cache transformation (for loops) // Specific, need to be written by backend
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// 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, int delta);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
int getedparity(dynarec_native_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex);
|
||||
void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode);
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
Executable → Regular
+657
-126
File diff suppressed because it is too large.
Load diff
Executable → Regular
+516
-166
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arm64_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
LDRx_literal(x2, (intptr_t)next - (intptr_t)addr);
|
||||
BR(x2);
|
||||
}
|
||||
Executable → Regular
+13
-12
@@ -6,24 +6,24 @@
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; dyn->f.dfnone = 1;\
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
if(B!=SF_MAYSET) { \
|
||||
dyn->insts[ninst].x64.state_flags = B; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0; \
|
||||
}
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.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) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier = A
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst].x64.barrier_next = A
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_native_t*)realloc(dyn->insts, sizeof(instruction_native_t)*dyn->cap*2); \
|
||||
dyn->insts = (instruction_native_t*)dynaRealloc(dyn->insts, sizeof(instruction_native_t)*dyn->cap*2);\
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_native_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
@@ -41,9 +41,10 @@
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_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(box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of %sOpcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, rex.is32bits?"32bits ":"",\
|
||||
PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
|
||||
Executable → Regular
File mode changed.
Executable → Regular
+9
-8
@@ -1,17 +1,18 @@
|
||||
#define INIT dyn->native_size = 0
|
||||
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define FINI \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x64.size>(dyn->insts[ninst].size/4))?dyn->insts[ninst].x64.size:(dyn->insts[ninst].size/4))/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->native_size+=4
|
||||
#define EMIT(A) do{dyn->insts[ninst].size+=4; dyn->native_size+=4;}while(0)
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
dyn->last_ip = 0; \
|
||||
++dyn->sons_size; \
|
||||
} \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>(dyn->insts[ninst-1].size/4))?dyn->insts[ninst-1].x64.size:(dyn->insts[ninst-1].size/4))/15; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);}
|
||||
#define TABLE64(A, V) {Table64(dyn, (V), 2); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
|
||||
Executable → Regular
+17
-60
@@ -1,65 +1,22 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define EMIT(A) \
|
||||
if(box64_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (uint32_t)(A), arm64_print(A, (uintptr_t)dyn->block));} \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->native_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x64.size, dyn->insts[ninst].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#define EMIT(A) \
|
||||
do{ \
|
||||
if(box64_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
|
||||
if((uintptr_t)dyn->block<dyn->tablestart) \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->native_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4; \
|
||||
}while(0)
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
dyn->last_ip = 0; \
|
||||
dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_native[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4);
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box64_dynarec_dump) {\
|
||||
printf_x64_instruction(my_context->dec, &dyn->insts[ninst].x64, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), set=%X, use=%X, need=%X", \
|
||||
(box64_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x64.barrier, \
|
||||
dyn->insts[ninst].x64.state_flags, \
|
||||
dyn->f.pending, \
|
||||
dyn->f.dfnone, \
|
||||
dyn->insts[ninst].x64.set_flags, \
|
||||
dyn->insts[ninst].x64.use_flags, \
|
||||
dyn->insts[ninst].x64.need_flags); \
|
||||
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].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)\
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);\
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)\
|
||||
dynarec_log(LOG_NONE, ", jmp=out"); \
|
||||
if(dyn->last_ip) \
|
||||
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);\
|
||||
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:%s", ii, 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, 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, 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, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, 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 || 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", (box64_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
|
||||
Executable → Regular
+48
-30
@@ -5,28 +5,30 @@
|
||||
|
||||
typedef struct x64emu_s x64emu_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
|
||||
#define NEON_CACHE_ST_F 2
|
||||
#define NEON_CACHE_MM 3
|
||||
#define NEON_CACHE_XMMW 4
|
||||
#define NEON_CACHE_XMMR 5
|
||||
#define NEON_CACHE_SCR 6
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
#define NEON_CACHE_ST_F 2
|
||||
#define NEON_CACHE_ST_I64 3
|
||||
#define NEON_CACHE_MM 4
|
||||
#define NEON_CACHE_XMMW 5
|
||||
#define NEON_CACHE_XMMR 6
|
||||
#define NEON_CACHE_SCR 7
|
||||
typedef union neon_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
unsigned int t:4; // reg type
|
||||
unsigned int n:4; // reg number
|
||||
uint8_t t:4; // reg type
|
||||
uint8_t n:4; // reg number
|
||||
};
|
||||
} neon_cache_t;
|
||||
typedef union sse_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
unsigned int reg:7;
|
||||
unsigned int write:1;
|
||||
uint8_t reg:7;
|
||||
uint8_t write:1;
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
@@ -56,69 +58,85 @@ typedef struct neoncache_s {
|
||||
|
||||
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
|
||||
int dfnone; // if deferred flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm64_s {
|
||||
instruction_x64_t x64;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t address; // (start) address of the arm emitted instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, or barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
int size; // size of the arm emitted instruction
|
||||
int size2; // size of the arm emitted instrucion after pass2
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markf, markf2;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
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_exit; // flags status at end of instruction
|
||||
neoncache_t n; // neoncache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_arm64_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm64_t *insts;
|
||||
instruction_arm64_t*insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in byte of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uint32_t isize; // size in bytes of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emitted
|
||||
uintptr_t native_start; // start of the arm code
|
||||
size_t native_size; // size of emitted arm code
|
||||
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state) TODO: move to a cache something
|
||||
uint64_t *table64; // table of 64bits value
|
||||
uint64_t* table64; // table of 64bits values
|
||||
int table64size;// size of table (will be appended at end of executable code)
|
||||
int table64cap;
|
||||
uintptr_t tablestart;
|
||||
uintptr_t jmp_next; // address of the jump_next address
|
||||
flagcache_t f;
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x64; // the x64 address of potential dynablock sons
|
||||
void** sons_native; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* jmps; // variable array of jump instructions
|
||||
int jmp_sz;
|
||||
int jmp_cap;
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint8_t doublepush;
|
||||
uint8_t doublepop;
|
||||
uint8_t always_test;
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
void add_jump(dynarec_arm_t *dyn, int ninst);
|
||||
int get_first_jump(dynarec_arm_t *dyn, int next);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
int Table64(dynarec_arm_t *dyn, uint64_t val, int pass); // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
#define GO_TRACE() \
|
||||
GETIP_(ip); \
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#define GO_TRACE(A, B, s0) \
|
||||
GETIP(addr); \
|
||||
MOVx_REG(x1, xRIP); \
|
||||
STORE_XEMU_CALL(xRIP); \
|
||||
MOV32w(x2, 1); \
|
||||
CALL(PrintTrace, -1); \
|
||||
MOV32w(x2, B); \
|
||||
CALL(A, -1); \
|
||||
LOAD_XEMU_CALL(xRIP)
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
Executable → Regular
+205
-415
@@ -1,14 +1,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -19,6 +18,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "native_lock.h"
|
||||
@@ -26,8 +26,6 @@
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
@@ -37,23 +35,37 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return NULL; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
// remove jumptable without waiting
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
ret->minstart = text;
|
||||
ret->maxend = text+textsz-1;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
return db;
|
||||
}
|
||||
|
||||
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(!db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
@@ -61,493 +73,271 @@ 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 x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->parent, db->father, db->sons_size, db->gone);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
// remove jumptable without waiting
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
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->x64_addr;
|
||||
if(addr>=startdb && addr<enddb)
|
||||
native_lock_xchg(&db->parent->direct[addr-startdb], 0); // secured write
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)native_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son, 0);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
free(db->sons);
|
||||
free(db->instsize);
|
||||
}
|
||||
free(db);
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
FreeDynablock((*dynablocks)->direct[i], 1);
|
||||
}
|
||||
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
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p with %d son(s) %p-%p\n", db, db->sons_size, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
db->need_test = 1;
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault64(db->sons[i]->x64_addr);
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
if(!setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) {
|
||||
dynablock_t* old = db;
|
||||
db = getDB((uintptr_t)old->x64_addr);
|
||||
if(!old->gone && db!=old) {
|
||||
printf_log(LOG_INFO, "Warning, couldn't mark block as dirty for %p, block=%p, current_block=%p\n", old->x64_addr, old, db);
|
||||
// the block is lost, need to invalidate it...
|
||||
old->gone = 1;
|
||||
old->done = 0;
|
||||
if(!db || db->previous)
|
||||
FreeInvalidDynablock(old, 1);
|
||||
else
|
||||
db->previous = old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text;
|
||||
return 0;
|
||||
}
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text+db->textsz-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t sizedb = dynablocks->textsz;
|
||||
dynablock_t *db;
|
||||
dynarec_log(LOG_DEBUG, "MarkDirectDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)startdb, (void*)sizedb);
|
||||
for(uintptr_t i = 0; i<sizedb; ++i)
|
||||
if((db=dynablocks->direct[i]))
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
if(db) {
|
||||
if(getNeedTest((uintptr_t)db->x64_addr))
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!db)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size);
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
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
|
||||
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*)native_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);
|
||||
// check emptyness
|
||||
for(uintptr_t i=0; i<dynablocks->textsz; ++i)
|
||||
if(dynablocks->direct[i])
|
||||
return 0;
|
||||
return 1;
|
||||
int need_lock = my_context?1:0;
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) {
|
||||
FreeDynablock(db, need_lock);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p\n", (void*)addr, (void*)addr+size-1);
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t new_addr = dynablocks->minstart;
|
||||
uintptr_t new_size = dynablocks->maxend - new_addr + 1;
|
||||
MarkDirectDynablock(dynablocks, addr, size);
|
||||
// the blocks check before
|
||||
for(unsigned idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
|
||||
MarkDirectDynablock(getDB(idx), addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
dynablock_t* db;
|
||||
kh_foreach_value(dynablocks, db,
|
||||
const uintptr_t s = (uintptr_t)db->block;
|
||||
const uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
|
||||
return db->father?db->father:db;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t 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))) {
|
||||
return AddNewDynablock(getDBFromAddress(addr), addr, created);
|
||||
}
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(native_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
#endif
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)native_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
*created = 1;
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
return block;
|
||||
}
|
||||
|
||||
//TODO: move this to dynrec_arm.c and track allocated structure to avoid memory leak
|
||||
static __thread struct __jmp_buf_tag dynarec_jmpbuf;
|
||||
static __thread JUMPBUFF dynarec_jmpbuf;
|
||||
#ifdef ANDROID
|
||||
#define DYN_JMPBUF dynarec_jmpbuf
|
||||
#else
|
||||
#define DYN_JMPBUF &dynarec_jmpbuf
|
||||
#endif
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
longjmp(&dynarec_jmpbuf, 1);
|
||||
longjmp(DYN_JMPBUF, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks) {
|
||||
dynablocks = getDBFromAddress(addr);
|
||||
if(!dynablocks) {
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
return block;
|
||||
|
||||
if(need_lock) {
|
||||
if(box64_dynarec_wait) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
|
||||
if((block = dynablocks->direct[addr-dynablocks->text]))
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
}
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x64_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(sigsetjmp(DYN_JMPBUF, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, canceling\n", (void*)addr);
|
||||
FreeDynablock(block, 0);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock64(block, filladdr);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
void* ret = FillBlock64(block, filladdr, (addr==filladdr)?0:1, is32bits);
|
||||
if(!ret) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
void* old = (void*)native_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 be writen
|
||||
}
|
||||
free(block);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && block->x64_size) {
|
||||
if(dynablocks->minstart>addr)
|
||||
dynablocks->minstart = addr;
|
||||
if(block) {
|
||||
int blocksz = block->x64_size;
|
||||
if(dynablocks->maxend<addr+blocksz) {
|
||||
dynablocks->maxend = addr+blocksz;
|
||||
for(unsigned idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz-1)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->minstart>addr)
|
||||
dblist->minstart = addr;
|
||||
}
|
||||
}
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault64(block->x64_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i) {
|
||||
addJumpTableIfDefault64(block->sons[i]->x64_addr, block->sons[i]->block);
|
||||
block->sons[i]->done = 1;
|
||||
if(!addJumpTableIfDefault64(block->x64_addr, block->dirty?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0);
|
||||
block = getDB(addr);
|
||||
MarkDynablock(block); // just in case...
|
||||
} else {
|
||||
if(block->x64_size)
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
}
|
||||
block->done = 1;
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", GetTID(), created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", GetTID(), (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
#define MAX_HOTPAGE 64
|
||||
#define HOTPAGE_STEP 64
|
||||
static int volatile hotpage_count[MAX_HOTPAGE] = {0};
|
||||
static uintptr_t volatile hotpage[MAX_HOTPAGE] = {0};
|
||||
static uintptr_t volatile hotpage_size[MAX_HOTPAGE] = {0};
|
||||
static volatile int hotpages = 0;
|
||||
|
||||
int IsInHotPage(uintptr_t addr) {
|
||||
if(!hotpages)
|
||||
return 0;
|
||||
for(int i=0; i<MAX_HOTPAGE; ++i) {
|
||||
if((hotpage_count[i]>0) && (addr>=hotpage[i]) && (addr<hotpage[i]+0x1000*(hotpage_size[i]+1))) {
|
||||
--hotpage_count[i];
|
||||
if(!hotpage_count[i]) {
|
||||
--hotpages;
|
||||
hotpage_size[i] = 0;
|
||||
dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]);
|
||||
}
|
||||
__sync_synchronize();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AreaInHotPage(uintptr_t start, uintptr_t end) {
|
||||
if(!hotpages)
|
||||
return 0;
|
||||
for(int i=0; i<MAX_HOTPAGE; ++i) {
|
||||
if(hotpage_count[i]>0)
|
||||
if(IntervalIntersects(start, end, hotpage[i], hotpage[i]+0x1000*(hotpage_size[i]+1)-1)) {
|
||||
--hotpage_count[i];
|
||||
if(!hotpage_count[i]) {
|
||||
--hotpages;
|
||||
hotpage_size[i] = 0;
|
||||
dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]);
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) {
|
||||
emu->test.test = 0;
|
||||
if(box64_dynarec_fastpage) {
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(hash==db->hash) { // seems ok, run it without reprotecting it
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
return db;
|
||||
}
|
||||
return 1;
|
||||
db->done = 0; // invalidating the block, it's already not good
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 1);
|
||||
return NULL; // not building a new one, it's still a hotpage
|
||||
} else {
|
||||
dynarec_log(LOG_INFO, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AddHotPage(uintptr_t addr) {
|
||||
addr&=~0xfff;
|
||||
// look for same address
|
||||
for(int i=0; i<MAX_HOTPAGE; ++i) {
|
||||
if(addr>=hotpage[i] && addr<hotpage[i]+0x1000*(hotpage_size[i]+1)) {
|
||||
if(!hotpage_count[i])
|
||||
++hotpages;
|
||||
hotpage_count[i] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
return;
|
||||
}
|
||||
if(addr==hotpage[i]+0x1000*(hotpage_size[i]+1)) {
|
||||
++hotpage_size[i];
|
||||
hotpage_count[i] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
return;
|
||||
}
|
||||
if(addr+0x1000==hotpage[i]) {
|
||||
++hotpage_size[i];
|
||||
hotpage[i] = addr;
|
||||
hotpage_count[i] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// look for empty spot / minium
|
||||
int mincnt = hotpage_count[0];
|
||||
int minidx = 0;
|
||||
for(int i=1; i<MAX_HOTPAGE; ++i)
|
||||
if(hotpage_count[i]<mincnt) {
|
||||
mincnt = hotpage_count[i];
|
||||
minidx = i;
|
||||
}
|
||||
if(hotpage_count[minidx]) {
|
||||
static int cnt = 0;
|
||||
if(cnt<50) {
|
||||
dynarec_log(LOG_NONE, "Warning, not enough Hotpage, replacing %p(%p/%d) with %p\n", (void*)hotpage[minidx], (void*)(0x1000*(hotpage_size[minidx]+1)), hotpage_count[minidx], (void*)addr);
|
||||
++cnt;
|
||||
if(cnt==50) // stop spamming console with message...
|
||||
dynarec_log(LOG_NONE, " will stop warning about not enough Hotpage now\n");
|
||||
}
|
||||
hotpage_size[minidx] = 0;
|
||||
} else
|
||||
++hotpages;
|
||||
hotpage[minidx] = addr;
|
||||
hotpage_count[minidx] = HOTPAGE_STEP;
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
|
||||
dynablock_t *father = (db && db->father)?db->father:db;
|
||||
if(father && father->done && db->block && father->need_test) {
|
||||
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) with %d son(s) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->sons_size, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(AreaInHotPage((uintptr_t)father->x64_addr, (uintptr_t)father->x64_addr + father->x64_size - 1)) {
|
||||
dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with %d son(s) for %p because it's in a hotpage\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->sons_size, (void*)addr);
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
father->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && IntervalIntersects(
|
||||
(uintptr_t)father->x64_addr,
|
||||
(uintptr_t)father->x64_addr+father->x64_size-1,
|
||||
(uintptr_t)(*current)->x64_addr,
|
||||
(uintptr_t)(*current)->x64_addr+(*current)->x64_size-1))
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, need_lock, is32bits);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->hash, father->sons_size, (void*)addr);
|
||||
protectDB((uintptr_t)father->x64_addr, father->x64_size);
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr);
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(father->x64_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
|
||||
if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int is32bits)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p%s\n", (void*)addr, (void*)filladdr, is32bits?" 32bits":"");
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
|
||||
dynablock_t *father = (db && db->father)?db->father:db;
|
||||
if(father && father->done && db->block && father->need_test) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
father->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits);
|
||||
if(db && db->done && db->block && getNeedTest(filladdr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_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->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, need_lock, is32bits);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x64_addr, father->x64_size);
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(father->x64_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
|
||||
if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
Executable → Regular
+8
-19
@@ -1,37 +1,26 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x64:4;
|
||||
unsigned int nat:4;
|
||||
unsigned char x64:4;
|
||||
unsigned char nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
struct dynablock_s* previous; // a previous block that might need to be freed
|
||||
int size;
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
uint8_t always_test;
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
instsize_t* instsize;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
uintptr_t maxend; // max address end for anyblock on this blocklist
|
||||
uintptr_t minstart; // min start address for block overlapping this blocklist
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
Executable → Regular
+116
-166
@@ -1,6 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
@@ -8,7 +7,6 @@
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -20,22 +18,10 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "dynarec_next.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM64
|
||||
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm64_epilog() EXPORTDYN;
|
||||
#define native_prolog arm64_prolog
|
||||
#define native_epilog arm64_epilog
|
||||
#elif defined(LA464)
|
||||
void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void la464_epilog() EXPORTDYN;
|
||||
#define native_prolog la464_prolog
|
||||
#define native_epilog la464_epilog
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
#include "elfloader.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
@@ -43,33 +29,36 @@ uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
|
||||
void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
{
|
||||
int is32bits = (R_CS == 0x23);
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
dynablock_t* block = NULL;
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_DEBUG, "Jmp address has alternate: %p", (void*)addr);
|
||||
if(box64_log<LOG_DEBUG) dynarec_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
uintptr_t old_addr = addr;
|
||||
addr = (uintptr_t)getAlternate((void*)addr); // set new address
|
||||
R_RIP = addr; // but also new RIP!
|
||||
*x3 = addr; // and the RIP in x27 register
|
||||
printf_log(LOG_DEBUG, " -> %p\n", (void*)addr);
|
||||
block = DBAlternateBlock(emu, old_addr, addr, is32bits);
|
||||
} else
|
||||
block = DBGetBlock(emu, addr, 1, is32bits);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_DEBUG, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr); // set new address
|
||||
R_RIP = addr; // but also new RIP!
|
||||
*x3 = addr; // and the RIP in x27 register
|
||||
printf_log(LOG_DEBUG, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=box64_dynarec_log) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
|
||||
#endif
|
||||
//tableupdate(native_epilog, addr, table);
|
||||
return native_epilog;
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2-4);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p(elf=%s))\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
|
||||
}
|
||||
#endif
|
||||
//tableupdate(native_epilog, addr, table);
|
||||
return native_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
@@ -84,162 +73,123 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
// Disable "clobbered" warnings
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclobbered"
|
||||
#endif
|
||||
void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
int jmpbuf_reset = 0;
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_RIP; // not sure if it should still be inside DynaCall!
|
||||
}
|
||||
}
|
||||
uint64_t old_rsp = R_RSP;
|
||||
uint64_t old_rbx = R_RBX;
|
||||
uint64_t old_rdi = R_RDI;
|
||||
uint64_t old_rsi = R_RSI;
|
||||
uint64_t old_rbp = R_RBP;
|
||||
uint64_t old_rip = R_RIP;
|
||||
// save defered flags
|
||||
deferred_flags_t old_df = emu->df;
|
||||
multiuint_t old_op1 = emu->op1;
|
||||
multiuint_t old_op2 = emu->op2;
|
||||
multiuint_t old_res = emu->res;
|
||||
multiuint_t old_op1_sav= emu->op1_sav;
|
||||
multiuint_t old_res_sav= emu->res_sav;
|
||||
deferred_flags_t old_df_sav= emu->df_sav;
|
||||
// uc_link
|
||||
x64_ucontext_t* old_uc_link = emu->uc_link;
|
||||
emu->uc_link = NULL;
|
||||
|
||||
PushExit(emu);
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
DynaRun(emu);
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
emu->uc_link = old_uc_link;
|
||||
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
|
||||
if(emu->flags.quitonlongjmp==1)
|
||||
emu->flags.longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
// restore defered flags
|
||||
emu->df = old_df;
|
||||
emu->op1 = old_op1;
|
||||
emu->op2 = old_op2;
|
||||
emu->res = old_res;
|
||||
emu->op1_sav = old_op1_sav;
|
||||
emu->res_sav = old_res_sav;
|
||||
emu->df_sav = old_df_sav;
|
||||
// and the old registers
|
||||
R_RBX = old_rbx;
|
||||
R_RDI = old_rdi;
|
||||
R_RSI = old_rsi;
|
||||
R_RBP = old_rbp;
|
||||
R_RSP = old_rsp;
|
||||
R_RIP = old_rip; // and set back instruction pointer
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
EmuCall(emu, addr);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
uint64_t old_rsp = R_RSP;
|
||||
uint64_t old_rbx = R_RBX;
|
||||
uint64_t old_rdi = R_RDI;
|
||||
uint64_t old_rsi = R_RSI;
|
||||
uint64_t old_rbp = R_RBP;
|
||||
uint64_t old_rip = R_RIP;
|
||||
PushExit(emu);
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* current = NULL;
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
while(!emu->quit) {
|
||||
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_RIP, emu);
|
||||
Run(emu, 1);
|
||||
block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
block = NULL;
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_RIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
if(emu->quitonlongjmp && emu->longjmp) {
|
||||
if(emu->quitonlongjmp==1)
|
||||
emu->longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
R_RBX = old_rbx;
|
||||
R_RDI = old_rdi;
|
||||
R_RSI = old_rsi;
|
||||
R_RBP = old_rbp;
|
||||
R_RSP = old_rsp;
|
||||
R_RIP = old_rip; // and set back instruction pointer
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
}
|
||||
|
||||
int DynaRun(x64emu_t* emu)
|
||||
int my_setcontext(x64emu_t* emu, void* ucp);
|
||||
void DynaRun(x64emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
#ifdef DYNAREC
|
||||
int jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
JUMPBUFF jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
JUMPBUFF *old_jmpbuf = emu->jmpbuf;
|
||||
emu->flags.jmpbuf_ready = 0;
|
||||
|
||||
while(!(emu->quit)) {
|
||||
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
|
||||
emu->jmpbuf = jmpbuf;
|
||||
emu->flags.jmpbuf_ready = 1;
|
||||
#ifdef ANDROID
|
||||
if((skip=sigsetjmp(*(JUMPBUFF*)emu->jmpbuf, 1)))
|
||||
#else
|
||||
if((skip=sigsetjmp(emu->jmpbuf, 1)))
|
||||
#endif
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", emu->segs[_FS]);
|
||||
#ifdef DYNAREC
|
||||
if(box64_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
x64test_check(emu, R_RIP);
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->flags.need_jmpbuf = 0;
|
||||
|
||||
#ifdef DYNAREC
|
||||
if(!box64_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
return Run(emu, 0);
|
||||
Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* current = NULL;
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1, ¤t);;
|
||||
current = block;
|
||||
while(!emu->quit) {
|
||||
if(!block || !block->block || !block->done) {
|
||||
else {
|
||||
int is32bits = (emu->segs[_CS]==0x23);
|
||||
dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
if(!block || !block->block || !block->done || ACCESS_FLAG(F_TF)) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
if(box64_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
block = DBGetBlock(emu, R_RIP, 1, ¤t);
|
||||
current = block;
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (hash=0x%x) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->hash, emu);
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
block = NULL;
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->quit = 0;
|
||||
}
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
return 0;
|
||||
#endif
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
Executable → Regular
+29
-6
@@ -2,22 +2,45 @@
|
||||
#define __DYNAREC_ARCH__H_
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
|
||||
#define instruction_native_t instruction_arm64_t
|
||||
#define dynarec_native_t dynarec_arm_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
#elif defined(LA464)
|
||||
#include "la464/la464_printer.h"
|
||||
#include "la464/dynarec_la464_private.h"
|
||||
#include "la464/dynarec_la464_functions.h"
|
||||
|
||||
#define instruction_native_t instruction_la464_t
|
||||
#define dynarec_native_t dynarec_la464_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION()
|
||||
|
||||
#define OTHER_CACHE()
|
||||
|
||||
#include "la464/la464_printer.h"
|
||||
#include "la464/dynarec_la464_private.h"
|
||||
#include "la464/dynarec_la464_functions.h"
|
||||
#elif defined(RV64)
|
||||
|
||||
#define instruction_native_t instruction_rv64_t
|
||||
#define dynarec_native_t dynarec_rv64_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
|
||||
#include "rv64/rv64_printer.h"
|
||||
#include "rv64/dynarec_rv64_private.h"
|
||||
#include "rv64/dynarec_rv64_functions.h"
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
Executable → Regular
+2
@@ -5,6 +5,8 @@
|
||||
#include "arm64/dynarec_arm64_helper.h"
|
||||
#elif defined(LA464)
|
||||
#include "la464/dynarec_la464_helper.h"
|
||||
#elif defined(RV64)
|
||||
#include "rv64/dynarec_rv64_helper.h"
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
Executable → Regular
+312
-291
@@ -1,6 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@@ -10,7 +9,6 @@
|
||||
#include "custommem.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -23,21 +21,22 @@
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_next.h"
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
|
||||
uintptr_t a = *(uintptr_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (box64_dynarec_dump>1)?"\e[1m":"", (void*)ip, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (box64_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box64_dynarec_dump>1)?"\e[1m":"", (void*)ip, (void*)a, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box64_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (void*)a, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[1m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[01;33m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[01;33m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
@@ -61,31 +60,55 @@ void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const cha
|
||||
void add_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
if(!box64_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_cap += 64;
|
||||
dyn->next = (uintptr_t*)dynaRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
// get closest, but no addresses befores
|
||||
// get closest, but no addresses before
|
||||
uintptr_t best = 0;
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
memmove(dyn->next+i, dyn->next+i+1, (dyn->next_sz-i-1)*sizeof(uintptr_t));
|
||||
--dyn->next_sz;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
if(dyn->next[i]) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
void add_jump(dynarec_native_t *dyn, int ninst) {
|
||||
// add slots
|
||||
if(dyn->jmp_sz == dyn->jmp_cap) {
|
||||
dyn->jmp_cap += 64;
|
||||
dyn->jmps = (int*)dynaRealloc(dyn->jmps, dyn->jmp_cap*sizeof(int));
|
||||
}
|
||||
dyn->jmps[dyn->jmp_sz++] = ninst;
|
||||
}
|
||||
int get_first_jump(dynarec_native_t *dyn, int next) {
|
||||
for(int i=0; i<dyn->jmp_sz; ++i)
|
||||
if(dyn->insts[dyn->jmps[i]].x64.jmp == next)
|
||||
return i;
|
||||
return -2;
|
||||
}
|
||||
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_native_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
@@ -116,8 +139,8 @@ int is_nops(dynarec_native_t *dyn, uintptr_t addr, int n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return size of next instuciton, -1 is unknown
|
||||
// not all instrction are setup
|
||||
// return size of next instruction, -1 is unknown
|
||||
// not all instructions are setup
|
||||
int next_instruction(dynarec_native_t *dyn, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode = PK(0);
|
||||
@@ -232,7 +255,7 @@ int is_instructions(dynarec_native_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 x64_size, int native_size)
|
||||
void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
|
||||
{
|
||||
// x64 instruction is <16 bytes
|
||||
int toadd;
|
||||
@@ -240,10 +263,6 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size,
|
||||
toadd = 1 + x64_size/15;
|
||||
else
|
||||
toadd = 1 + native_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
while(toadd) {
|
||||
if(x64_size>15)
|
||||
insts[*size].x64 = 15;
|
||||
@@ -258,11 +277,10 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size,
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
|
||||
{
|
||||
// find the value if already present
|
||||
int idx = -1;
|
||||
@@ -272,11 +290,15 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
// not found, add it
|
||||
if(idx==-1) {
|
||||
if(dyn->table64size == dyn->table64cap) {
|
||||
dyn->table64cap+=4;
|
||||
dyn->table64 = (uint64_t*)realloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
dyn->table64cap+=16;
|
||||
if(pass<3) // do not resize on pass3, it's not the same type of memory anymore
|
||||
dyn->table64 = (uint64_t*)dynaRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
}
|
||||
idx = dyn->table64size++;
|
||||
dyn->table64[idx] = val;
|
||||
if(idx < dyn->table64cap)
|
||||
dyn->table64[idx] = val;
|
||||
else
|
||||
printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap);
|
||||
}
|
||||
// calculate offset
|
||||
int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
|
||||
@@ -285,23 +307,31 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
|
||||
static void fillPredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
int pred_sz = 0;
|
||||
// compute total size of predecessor to alocate the array
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to allocate the array
|
||||
// first compute the jumps
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1) {
|
||||
++pred_sz;
|
||||
++dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz;
|
||||
if(dyn->insts[i].x64.jmp && (dyn->insts[i].x64.jmp_insts!=-1)) {
|
||||
pred_sz++;
|
||||
dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz++;
|
||||
}
|
||||
}
|
||||
// remove "has_next" from orphan branch
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(!dyn->insts[i].x64.has_next) {
|
||||
if(dyn->insts[i+1].x64.has_next && !dyn->insts[i+1].pred_sz)
|
||||
dyn->insts[i+1].x64.has_next = 0;
|
||||
}
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x64.has_next && (!i || dyn->insts[i].pred_sz)) {
|
||||
++pred_sz;
|
||||
++dyn->insts[i+1].pred_sz;
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x64.has_next) {
|
||||
pred_sz++;
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)malloc(pred_sz*sizeof(int));
|
||||
int alloc_size = pred_sz;
|
||||
dyn->predecessor = (int*)dynaMalloc(pred_sz*sizeof(int));
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
@@ -309,102 +339,141 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
p += dyn->insts[i].pred_sz;
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
assert(p==dyn->predecessor+pred_sz);
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x64.has_next && (!i || dyn->insts[i].pred_sz))
|
||||
if((i!=dyn->size-1) && dyn->insts[i].x64.has_next)
|
||||
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1)
|
||||
dyn->insts[dyn->insts[i].x64.jmp_insts].pred[dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz++] = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void updateNeed(dynarec_native_t* dyn, int ninst, uint32_t need) {
|
||||
uint32_t old_need = dyn->insts[ninst].x64.need_flags;
|
||||
uint32_t new_need = old_need | need;
|
||||
uint32_t new_use = dyn->insts[ninst].x64.use_flags;
|
||||
uint32_t old_use = dyn->insts[ninst].x64.old_use;
|
||||
|
||||
if((new_need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET) {
|
||||
new_need &=~X_PEND;
|
||||
new_need |= X_ALL;
|
||||
}
|
||||
|
||||
uint32_t new_set = 0;
|
||||
if(dyn->insts[ninst].x64.state_flags & SF_SET)
|
||||
new_set = dyn->insts[ninst].x64.set_flags;
|
||||
if(dyn->insts[ninst].x64.state_flags & SF_PENDING)
|
||||
new_set |= X_PEND;
|
||||
if((new_need&X_PEND) && (
|
||||
dyn->insts[ninst].x64.state_flags==SF_SET || dyn->insts[ninst].x64.state_flags==SF_SUBSET)) {
|
||||
new_need &=~X_PEND;
|
||||
new_need |=X_ALL;
|
||||
}
|
||||
|
||||
dyn->insts[ninst].x64.need_flags = new_need;
|
||||
dyn->insts[ninst].x64.old_use = new_use;
|
||||
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1)
|
||||
new_need |= X_PEND;
|
||||
|
||||
// a Flag Barrier will change all need to "Pending", as it clear all flags optimisation
|
||||
if(new_need && dyn->insts[ninst].x64.barrier&BARRIER_FLAGS)
|
||||
new_need = X_PEND;
|
||||
|
||||
if((new_need == old_need) && (new_use == old_use)) // no changes, bye
|
||||
return;
|
||||
|
||||
if(!(new_need && dyn->insts[ninst].x64.barrier&BARRIER_FLAGS)) {
|
||||
new_need &=~new_set; // clean needed flag that were suplied
|
||||
new_need |= new_use; // new need
|
||||
}
|
||||
|
||||
if((new_need == (X_ALL|X_PEND)) && (dyn->insts[ninst].x64.state_flags & SF_SET))
|
||||
new_need = X_ALL;
|
||||
|
||||
//update need to new need on predecessor
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], new_need);
|
||||
}
|
||||
|
||||
static void resetNeed(dynarec_native_t* dyn) {
|
||||
for(int i = dyn->size; i-- > 0;) {
|
||||
dyn->insts[i].x64.old_use = 0;
|
||||
dyn->insts[i].x64.need_flags = dyn->insts[i].x64.default_need;
|
||||
if(dyn->insts[i].x64.jmp && (dyn->insts[i].x64.jmp_insts!=-1)) {
|
||||
int j = dyn->insts[i].x64.jmp_insts;
|
||||
dyn->insts[j].pred[dyn->insts[j].pred_sz++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__thread void* current_helper = NULL;
|
||||
// updateNeed goes backward, from last instruction to top
|
||||
static int updateNeed(dynarec_native_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].x64.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SUBSET)) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
}
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SET)) {
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x64.set_flags; // SF_SET will compute all flags, it's not SUBSET!
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x64.set_flags);
|
||||
}
|
||||
dyn->insts[ninst].x64.gen_flags = need&dyn->insts[ninst].x64.set_flags;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags&SF_PENDING))
|
||||
dyn->insts[ninst].x64.gen_flags |= X_PEND;
|
||||
dyn->insts[ninst].x64.need_after = need;
|
||||
need = dyn->insts[ninst].x64.need_after&~dyn->insts[ninst].x64.gen_flags;
|
||||
|
||||
void CancelBlock64()
|
||||
if(dyn->insts[ninst].x64.may_set)
|
||||
need |= dyn->insts[ninst].x64.gen_flags; // forward the flags
|
||||
else if((need&X_PEND) && (dyn->insts[ninst].x64.set_flags&SF_PENDING))
|
||||
need &=~X_PEND; // Consume X_PEND if relevant
|
||||
need |= dyn->insts[ninst].x64.use_flags;
|
||||
if(dyn->insts[ninst].x64.need_before == need)
|
||||
return ninst - 1;
|
||||
dyn->insts[ninst].x64.need_before = need;
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) {
|
||||
need = need?X_PEND:0;
|
||||
}
|
||||
int ok = 0;
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
if(dyn->insts[ninst].pred[i] == ninst-1)
|
||||
ok = 1;
|
||||
else
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], need);
|
||||
}
|
||||
--ninst;
|
||||
if(!ok)
|
||||
return ninst;
|
||||
}
|
||||
return ninst;
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
|
||||
void CancelBlock64(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_native_t* helper = (dynarec_native_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(!helper)
|
||||
return;
|
||||
free(helper->next);
|
||||
free(helper->insts);
|
||||
free(helper->table64);
|
||||
free(helper->sons_x64);
|
||||
free(helper->sons_native);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
|
||||
if(helper) {
|
||||
dynaFree(helper->next);
|
||||
dynaFree(helper->jmps);
|
||||
dynaFree(helper->insts);
|
||||
dynaFree(helper->predecessor);
|
||||
if(helper->table64 && (helper->table64!=(uint64_t*)helper->tablestart))
|
||||
dynaFree(helper->table64);
|
||||
if(helper->dynablock && helper->dynablock->actual_block) {
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
helper->dynablock->actual_block = NULL;
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
|
||||
uintptr_t native_pass0(dynarec_native_t* dyn, uintptr_t addr);
|
||||
uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr);
|
||||
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr);
|
||||
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr);
|
||||
uintptr_t native_pass0(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits);
|
||||
uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits);
|
||||
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits);
|
||||
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits);
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
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(sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bits) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
0x0000..0x0007 : dynablock_t* : self
|
||||
0x0008..8+4*n : actual Native instructions, (n is the total number)
|
||||
A .. A+8*n : Table64: n 64bits values
|
||||
B .. B+7 : dynablock_t* : self (as part of JmpNext, that simulate another block)
|
||||
B+8 .. B+15 : 2 Native code for jmpnext (or jmp epilog in case of empty block)
|
||||
B+16 .. B+23 : jmpnext (or jmp_epilog) address
|
||||
B+24 .. B+31 : empty (in case an architecture needs more than 2 opcodes)
|
||||
B+32 .. B+32+sz : instsize (compressed array with each instruction length on x64 and native side)
|
||||
|
||||
*/
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
dynarec_log(LOG_DEBUG, "Canceling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(current_helper) {
|
||||
dynarec_log(LOG_DEBUG, "Canceling dynarec FillBlock at %p as another one is going on\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
// protect the 1st page
|
||||
protectDB(addr, 1);
|
||||
@@ -414,146 +483,161 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_native_t*)calloc(helper.cap, sizeof(instruction_native_t));
|
||||
helper.cap = 128;
|
||||
helper.insts = (instruction_native_t*)dynaCalloc(helper.cap, sizeof(instruction_native_t));
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
uintptr_t end = native_pass0(&helper, addr);
|
||||
// no need for next anymore
|
||||
free(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits);
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock64();
|
||||
return (void*)block;
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
CancelBlock64();
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// protect the block of it goes over the 1st page
|
||||
if((addr&~0xfff)!=(end&~0xfff)) // need to protect some other pages too
|
||||
if((addr&~box64_pagesize)!=(end&~box64_pagesize)) // need to protect some other pages too
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
// compute hash signature
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// Compute flag_need, without with current barriers
|
||||
resetNeed(&helper);
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
updateNeed(&helper, i, 0);
|
||||
// calculate barriers
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x64.jmp) {
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
if(j<start || j>=end) {
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
helper.insts[i].x64.use_flags |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
for(int ii=0; ii<helper.jmp_sz; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
if(j<start || j>=end || j==helper.insts[i].x64.addr) {
|
||||
if(j==helper.insts[i].x64.addr) // if there is a loop on some opcode, make the block "always to tested"
|
||||
helper.always_test = 1;
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
int search = ((j>=helper.insts[0].x64.addr) && j<helper.insts[0].x64.addr+helper.isize)?1:0;
|
||||
int imin = 0;
|
||||
int imax = helper.size-1;
|
||||
int i2 = helper.size/2;
|
||||
// dichotomy search
|
||||
while(search) {
|
||||
if(helper.insts[i2].x64.addr == j) {
|
||||
k = i2;
|
||||
search = 0;
|
||||
} else if(helper.insts[i2].x64.addr>j) {
|
||||
imax = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
} else {
|
||||
imin = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
}
|
||||
if(search && (imax-imin)<2) {
|
||||
search = 0;
|
||||
if(helper.insts[imin].x64.addr==j)
|
||||
k = imin;
|
||||
else if(helper.insts[imax].x64.addr==j)
|
||||
k = imax;
|
||||
}
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
/*for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
// no need for next and jmps anymore
|
||||
dynaFree(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
dynaFree(helper.jmps);
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// fill predecessors with the jump address
|
||||
fillPredecessors(&helper);
|
||||
// check for the optionnal barriers now
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
// out-of-block jump
|
||||
if(helper.insts[i].x64.jmp_insts == -1) {
|
||||
// nothing for now
|
||||
} else {
|
||||
// inside block jump
|
||||
int k = helper.insts[i].x64.jmp_insts;
|
||||
if(k>i) {
|
||||
// jump in the future
|
||||
if(helper.insts[k].pred_sz>1) {
|
||||
// with multiple flow, put a barrier
|
||||
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
} else {
|
||||
// jump back
|
||||
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
/*for(int i=helper.size-1; i>=0; --i) {
|
||||
int k;
|
||||
if(helper.insts[i].x64.jmp
|
||||
&& ((k=helper.insts[i].x64.jmp_insts)>=0)
|
||||
&& helper.insts[k].x64.barrier&BARRIER_FLAGS) {
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x64.need_flags)
|
||||
||(helper.insts[k].x64.set_flags==X_ALL
|
||||
&& helper.insts[k].x64.state_flags==SF_SET)
|
||||
||(helper.insts[k].x64.state_flags==SF_SET_PENDING)) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x64.barrier &= ~BARRIER_FLAGS; // remove flag barrier
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
int k;
|
||||
if(helper.insts[i].x64.jmp
|
||||
&& ((k=helper.insts[i].x64.jmp_insts)>=0)
|
||||
) {
|
||||
if(helper.insts[k].x64.barrier&BARRIER_FLAGS)
|
||||
// jumpto barrier
|
||||
helper.insts[i].x64.use_flags |= X_PEND;
|
||||
if(helper.insts[i].x64.barrier&BARRIER_FLAGS && (helper.insts[k].x64.need_flags | helper.insts[k].x64.use_flags))
|
||||
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
|
||||
else
|
||||
helper.insts[i].x64.use_flags |= (helper.insts[k].x64.need_flags | helper.insts[k].x64.use_flags);
|
||||
}
|
||||
if(helper.insts[i].x64.barrier&BARRIER_FLAGS)
|
||||
// immediate barrier
|
||||
helper.insts[i].x64.use_flags |= X_PEND;
|
||||
}
|
||||
resetNeed(&helper);
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
updateNeed(&helper, i, 0);
|
||||
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
native_pass1(&helper, addr);
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
native_pass1(&helper, addr, alternate, is32bits);
|
||||
|
||||
// pass 2, instruction size
|
||||
native_pass2(&helper, addr);
|
||||
native_pass2(&helper, addr, alternate, is32bits);
|
||||
// keep size of instructions for signal handling
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
size_t native_size = (helper.native_size+7)&~7; // round the size...
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = helper.native_size + helper.table64size*sizeof(uint64_t);
|
||||
void* p = (void*)AllocDynarecMap(block, sz);
|
||||
if(p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock64();
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
void* tablestart = p + native_size;
|
||||
void* next = tablestart + helper.table64size*sizeof(uint64_t);
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
block->actual_block = actual_p;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = helper.native_start + helper.native_size;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x64 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_native = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
helper.tablestart = (uintptr_t)tablestart;
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
helper.table64cap = helper.table64size;
|
||||
dynaFree(helper.table64);
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(box64_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize);
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64");
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
int oldtable64size = helper.table64size;
|
||||
size_t oldnativesize = helper.native_size;
|
||||
size_t oldinstsize = helper.insts_size;
|
||||
helper.native_size = 0;
|
||||
helper.table64size = 0; // reset table64 (but not the cap)
|
||||
native_pass3(&helper, addr);
|
||||
helper.insts_size = 0; // reset
|
||||
native_pass3(&helper, addr, alternate, is32bits);
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
dynaFree(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+3*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
|
||||
// Check if something changed, to abort if it is
|
||||
if((block->hash != hash)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
@@ -566,81 +650,18 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
//TODO: Cancel block and return empty one
|
||||
}
|
||||
// add table64 if needed
|
||||
if(helper.table64size) {
|
||||
memcpy((void*)helper.tablestart, helper.table64, helper.table64size*8);
|
||||
}
|
||||
// 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].x64.size>helper.insts[i].size)?helper.insts[i].x64.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].x64.size, helper.insts[i].size/4);
|
||||
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
}
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
helper.insts = NULL;
|
||||
free(helper.table64);
|
||||
helper.table64 = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->need_test = 0;
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if((block->hash != hash)) {
|
||||
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
CancelBlock64();
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, insts_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_INFO, "Warning, block unprotected while beeing processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size);
|
||||
CancelBlock64();
|
||||
return NULL;
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size);
|
||||
AddHotPage(addr);
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
// 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_x64[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_native[i];
|
||||
son->x64_addr = (void*)helper.sons_x64[i];
|
||||
son->x64_size = end-helper.sons_x64[i];
|
||||
if(!son->x64_size) {printf_log(LOG_NONE, "Warning, son with null x64 size! (@%p / Native=%p)", son->x64_addr, son->block);}
|
||||
son->father = block;
|
||||
son->size = sz + son->block - block->block; // update size count, for debugging
|
||||
//son->done = 1;
|
||||
if(!son->parent)
|
||||
son->parent = block->parent;
|
||||
sons[sons_size] = son;
|
||||
++sons_size;
|
||||
}
|
||||
}
|
||||
if(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
free(helper.sons_x64);
|
||||
helper.sons_x64 = NULL;
|
||||
free(helper.sons_native);
|
||||
helper.sons_native = NULL;
|
||||
current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
|
||||
@@ -0,0 +1,512 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
#include "dynarec_native_functions.h"
|
||||
|
||||
void native_fstp(x64emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
}
|
||||
|
||||
void native_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
(void)emu;
|
||||
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void native_f2xm1(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
}
|
||||
void native_fyl2x(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
}
|
||||
void native_ftan(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void native_fpatan(x64emu_t* emu)
|
||||
{
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void native_fxtract(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
}
|
||||
void native_fprem(x64emu_t* emu)
|
||||
{
|
||||
int e0, e1;
|
||||
int64_t ll;
|
||||
frexp(ST0.d, &e0);
|
||||
frexp(ST1.d, &e1);
|
||||
int32_t tmp32s = e0 - e1;
|
||||
if(tmp32s<64)
|
||||
{
|
||||
ll = (int64_t)floor(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll&1)?1:0;
|
||||
emu->sw.f.F87_C3 = (ll&2)?1:0;
|
||||
emu->sw.f.F87_C0 = (ll&4)?1:0;
|
||||
} else {
|
||||
ll = (int64_t)(floor((ST0.d/ST1.d))/exp2(tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
}
|
||||
void native_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void native_fsincos(x64emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void native_frndint(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void native_fscale(x64emu_t* emu)
|
||||
{
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void native_fsin(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void native_fcos(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
|
||||
void native_fbld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
}
|
||||
|
||||
void native_fild64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).sq = tmp;
|
||||
STll(0).sref = ST0.sq;
|
||||
}
|
||||
|
||||
void native_fbstp(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void native_fistp64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).sref==ST(0).sq) {
|
||||
memcpy(ed, &STll(0).sq, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void native_fistt64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid alignments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void native_fld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
}
|
||||
|
||||
void native_ud(x64emu_t* emu)
|
||||
{
|
||||
if(box64_dynarec_test)
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void native_priv(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void native_int(x64emu_t* emu, int num)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_interruption(emu, num, (void*)R_RIP);
|
||||
}
|
||||
|
||||
void native_singlestep(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGTRAP, (void*)R_RIP, 1);
|
||||
}
|
||||
|
||||
void native_int3(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGTRAP, (void*)R_RIP, 128);
|
||||
}
|
||||
|
||||
void native_div0(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_div0(emu, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void native_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void native_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void native_fprem1(x64emu_t* emu)
|
||||
{
|
||||
int e0, e1;
|
||||
int64_t ll;
|
||||
frexp(ST0.d, &e0);
|
||||
frexp(ST1.d, &e1);
|
||||
int32_t tmp32s = e0 - e1;
|
||||
if(tmp32s<64)
|
||||
{
|
||||
ll = (int64_t)round(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll&1)?1:0;
|
||||
emu->sw.f.F87_C3 = (ll&2)?1:0;
|
||||
emu->sw.f.F87_C0 = (ll&4)?1:0;
|
||||
} else {
|
||||
ll = (int64_t)(trunc((ST0.d/ST1.d))/exp2(tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void native_aesimc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void native_aesmc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void native_aesdlast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
const uint8_t invsubbytes[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
|
||||
|
||||
}
|
||||
static const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
static const uint8_t subbytes[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
};
|
||||
void native_aeselast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A F K P E J O D I N C H M B G L
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
|
||||
//STATE ← SubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
|
||||
}
|
||||
void native_aesd(x64emu_t* emu, int xmm)
|
||||
{
|
||||
native_aesdlast(emu, xmm);
|
||||
native_aesimc(emu, xmm);
|
||||
}
|
||||
void native_aese(x64emu_t* emu, int xmm)
|
||||
{
|
||||
native_aeselast(emu, xmm);
|
||||
native_aesmc(emu, xmm);
|
||||
}
|
||||
void native_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
|
||||
{
|
||||
sse_regs_t *EX = p?((sse_regs_t*)p):&emu->xmm[ex];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
for (int i = 4; i < 8; ++i)
|
||||
GX->ub[i] = subbytes[EX->ub[i]];
|
||||
for (int i = 12; i < 16; ++i)
|
||||
GX->ub[i] = subbytes[EX->ub[i]];
|
||||
GX->ud[0] = GX->ud[1];
|
||||
uint8_t tmp8u = GX->ub[4];
|
||||
GX->ud[1] = GX->ud[1] >> 8;
|
||||
GX->ub[7] = tmp8u;
|
||||
GX->ud[1] ^= u8;
|
||||
GX->ud[2] = GX->ud[3];
|
||||
tmp8u = GX->ub[12];
|
||||
GX->ud[3] = GX->ud[3] >> 8;
|
||||
GX->ub[15] = tmp8u;
|
||||
GX->ud[3] ^= u8;
|
||||
}
|
||||
|
||||
void native_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
|
||||
{
|
||||
sse_regs_t *EX = p?((sse_regs_t*)p):&emu->xmm[ex];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
int g = (u8&1)?1:0;
|
||||
int e = (u8&0b10000)?1:0;
|
||||
__int128 result = 0;
|
||||
__int128 op2 = EX->q[e];
|
||||
for (int i=0; i<64; ++i)
|
||||
if(GX->q[g]&(1LL<<i))
|
||||
result ^= (op2<<i);
|
||||
|
||||
GX->q[0] = result&0xffffffffffffffffLL;
|
||||
GX->q[1] = (result>>64)&0xffffffffffffffffLL;
|
||||
}
|
||||
|
||||
void native_clflush(x64emu_t* emu, void* p)
|
||||
{
|
||||
cleanDBFromAddressRange((uintptr_t)p, 8, 0);
|
||||
}
|
||||
|
||||
static int flagsCacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
|
||||
int jmp = dyn->insts[ninst].x64.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->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
return 1;
|
||||
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_PENDING)
|
||||
return 0;
|
||||
return 1;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending==SF_PENDING || dyn->insts[ninst].f_exit.pending==SF_SET_PENDING)
|
||||
return 0;
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
|
||||
int ret = 0;
|
||||
if (flagsCacheNeedsTransform(dyn, ninst)) ret|=1;
|
||||
OTHER_CACHE()
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isPred(dynarec_native_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_native_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];
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
(void)dyn; (void)addr; (void)ninst;
|
||||
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
// return Ib on a mod/rm opcode without emiting anything
|
||||
uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
return F8;
|
||||
}
|
||||
#undef F8
|
||||
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
|
||||
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = (uintptr_t)getAlternate(*(void**)a1);
|
||||
}
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifndef __DYNAREC_NATIVE_FUNCTIONS_H__
|
||||
#define __DYNAREC_NATIVE_FUNCTIONS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dynarec_arch.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void native_fstp(x64emu_t* emu, void* p);
|
||||
|
||||
void native_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void native_f2xm1(x64emu_t* emu);
|
||||
void native_fyl2x(x64emu_t* emu);
|
||||
void native_ftan(x64emu_t* emu);
|
||||
void native_fpatan(x64emu_t* emu);
|
||||
void native_fxtract(x64emu_t* emu);
|
||||
void native_fprem(x64emu_t* emu);
|
||||
void native_fyl2xp1(x64emu_t* emu);
|
||||
void native_fsincos(x64emu_t* emu);
|
||||
void native_frndint(x64emu_t* emu);
|
||||
void native_fscale(x64emu_t* emu);
|
||||
void native_fsin(x64emu_t* emu);
|
||||
void native_fcos(x64emu_t* emu);
|
||||
void native_fbld(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fild64(x64emu_t* emu, int64_t* ed);
|
||||
void native_fbstp(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fistp64(x64emu_t* emu, int64_t* ed);
|
||||
void native_fistt64(x64emu_t* emu, int64_t* ed);
|
||||
void native_fld(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fsave(x64emu_t* emu, uint8_t* ed);
|
||||
void native_frstor(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fprem1(x64emu_t* emu);
|
||||
|
||||
void native_aesd(x64emu_t* emu, int xmm);
|
||||
void native_aese(x64emu_t* emu, int xmm);
|
||||
void native_aesdlast(x64emu_t* emu, int xmm);
|
||||
void native_aeselast(x64emu_t* emu, int xmm);
|
||||
void native_aesimc(x64emu_t* emu, int xmm);
|
||||
void native_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
void native_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
|
||||
void native_clflush(x64emu_t* emu, void* p);
|
||||
|
||||
void native_ud(x64emu_t* emu);
|
||||
void native_priv(x64emu_t* emu);
|
||||
void native_singlestep(x64emu_t* emu);
|
||||
void native_int3(x64emu_t* emu);
|
||||
void native_int(x64emu_t* emu, int num);
|
||||
void native_div0(x64emu_t* emu);
|
||||
|
||||
// Caches transformation (for loops) // Specific, need to be written par backend
|
||||
int CacheNeedsTransform(dynarec_native_t* dyn, int i1);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_native_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
// return Ib on a mod/rm opcode without emiting anything
|
||||
uint8_t geted_ib(dynarec_native_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_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
ADDITIONNAL_DEFINITION()
|
||||
|
||||
#endif //__DYNAREC_NATIVE_FUNCTIONS_H__
|
||||
Executable → Regular
+162
-97
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -18,6 +17,7 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_helper.h"
|
||||
@@ -26,22 +26,28 @@
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
int j64;
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t init_addr = addr;
|
||||
rex_t rex;
|
||||
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
fpu_reset(dyn);
|
||||
ARCH_INIT();
|
||||
int reset_n = -1;
|
||||
dyn->last_ip = (dyn->insts && dyn->insts[0].pred_sz)?0:ip; // RIP is always set at start of block unless there is a predecessor!
|
||||
dyn->last_ip = (alternate || (dyn->insts && dyn->insts[0].pred_sz))?0:ip; // RIP is always set at start of block unless there is a predecessor!
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with box64_dynarec_bigblock==2, else it needs 3
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
@@ -54,44 +60,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
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(box64_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
|
||||
fpu_reset_cache(dyn, ninst, reset_n);
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
@@ -104,32 +73,38 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
} else if(dyn->insts[ninst].pred_sz!=1)
|
||||
dyn->last_ip = 0; // reset IP if some jump are comming here
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
} else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
|
||||
dyn->last_ip = 0; // reset IP if some jump are coming here
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
NEW_INST;
|
||||
#if STEP == 0
|
||||
if(ninst && dyn->insts[ninst-1].x64.barrier_next) {
|
||||
BARRIER(dyn->insts[ninst-1].x64.barrier_next);
|
||||
}
|
||||
#endif
|
||||
if(!ninst) {
|
||||
GOTEST(x1, x2);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
fpu_reset_scratch(dyn);
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
}
|
||||
if(box64_dynarec_test) {
|
||||
MESSAGE(LOG_DUMP, "TEST INIT ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE(x64test_init, 1, x5);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box64_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
else if(my_context->dec && box64_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE();
|
||||
GO_TRACE(PrintTrace, 1, x5);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
@@ -137,21 +112,24 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
|
||||
rep = 0;
|
||||
uint8_t pk = PK(0);
|
||||
while((pk==0xF2) || (pk==0xF3)) {
|
||||
rep = pk-0xF1;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
while(pk==0x3E) { //Branch Taken Hint ignored
|
||||
while((pk==0xF2) || (pk==0xF3) || (pk==0x3E) || (pk==0x26)) {
|
||||
switch(pk) {
|
||||
case 0xF2: rep = 1; break;
|
||||
case 0xF3: rep = 2; break;
|
||||
case 0x3E:
|
||||
case 0x26: /* ignored */ break;
|
||||
}
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
rex.rex = 0;
|
||||
while(pk>=0x40 && pk<=0x4f) {
|
||||
rex.rex = pk;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
rex.is32bits = is32bits;
|
||||
if(!rex.is32bits)
|
||||
while(pk>=0x40 && pk<=0x4f) {
|
||||
rex.rex = pk;
|
||||
++addr;
|
||||
pk = PK(0);
|
||||
}
|
||||
|
||||
addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
|
||||
|
||||
@@ -171,17 +149,30 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
dyn->last_ip = 0;
|
||||
}
|
||||
}
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
#if STEP != 0
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
while(ii<dyn->size && !dyn->insts[ii].pred_sz)
|
||||
++ii;
|
||||
if(ii<dyn->size && !dyn->insts[ii].pred_sz) {
|
||||
while(ii<dyn->size && (!dyn->insts[ii].pred_sz || (dyn->insts[ii].pred_sz==1 && dyn->insts[ii].pred[0]==ii-1))) {
|
||||
// may need to skip opcodes to advance
|
||||
++ninst;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DEBUG, "Skipping unused opcode\n");
|
||||
INST_NAME("Skipped opcode");
|
||||
INST_EPILOG;
|
||||
addr += dyn->insts[ii].x64.size;
|
||||
++ii;
|
||||
}
|
||||
}
|
||||
if((dyn->insts[ii].x64.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
|
||||
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are available
|
||||
if(reset_n==-1) {
|
||||
reset_n = -2;
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
@@ -189,59 +180,133 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(!ok && !need_epilog && box64_dynarec_bigblock && getProtection(addr+3)&~PROT_CUSTOM)
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog) {
|
||||
// we made it!
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
if(dyn->insts[dyn->forward_ninst].x64.has_callret && !dyn->insts[dyn->forward_ninst].x64.has_next)
|
||||
dyn->insts[dyn->forward_ninst].x64.has_next = 1; // this block actually continue
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
ok = 1; // in case it was 0
|
||||
} else if ((dyn->forward_to < addr) || ok<=0) {
|
||||
// something when wrong! rollback
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
ok = 0;
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
// else just continue
|
||||
} else if(!ok && !need_epilog && box64_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)<15) && is_nops(dyn, addr, next-addr))
|
||||
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
|
||||
{
|
||||
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].x64.jmp == next) {
|
||||
reset_n = ii;
|
||||
ii=ninst;
|
||||
if(dyn->insts[ninst].x64.has_callret && !dyn->insts[ninst].x64.has_next) {
|
||||
dyn->insts[ninst].x64.has_next = 1; // this block actually continue
|
||||
} else {
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
// and pred table is not ready yet
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
}
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
|
||||
} else if(next && (next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
if(next<dyn->forward_to)
|
||||
dyn->forward_to = next;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
} else {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
}
|
||||
if(box64_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) {
|
||||
if(box64_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;}
|
||||
if(ok<0) {
|
||||
ok = 0; need_epilog=1;
|
||||
#if STEP == 0
|
||||
if(ninst) {
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x64.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
dyn->insts[ninst].x64.need_after |= X_PEND;
|
||||
++ninst;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
// stopping too soon
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst+1;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault64((void*)addr) && (box64_dynarec_bigblock<2))
|
||||
if(ok && (((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)addr))
|
||||
|| (addr>=box64_nodynarec_start && addr<box64_nodynarec_end)))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 0
|
||||
if(dyn->forward) {
|
||||
// stopping too soon
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst+1;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
if(!box64_dynarec_dump && addr>=box64_nodynarec_start && addr<box64_nodynarec_end)
|
||||
dynarec_log(LOG_INFO, "Stopping block in no-dynarec zone\n");
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x64.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
#if STEP == 0
|
||||
if(dyn->insts[ninst].x64.set_flags)
|
||||
dyn->insts[ninst].x64.default_need |= X_PEND;
|
||||
else
|
||||
dyn->insts[ninst].x64.use_flags |= X_PEND;
|
||||
dyn->insts[ninst].x64.need_after |= X_PEND;
|
||||
#endif
|
||||
++ninst;
|
||||
NOTEST(x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
NOTEST(x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknown 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;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1416 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user