mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 04:09:46 -10:00
Compare commits
699
Commits
v0.2.2
...
save_memory
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8153391dd7 | ||
|
|
2420f9ffdd | ||
|
|
b9fd1c6213 | ||
|
|
b5e6f92547 | ||
|
|
d2c391406e | ||
|
|
db1df82696 | ||
|
|
67380e2c00 | ||
|
|
b956b29f66 | ||
|
|
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 |
No files matched your search
@@ -92,10 +92,20 @@ jobs:
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Test Box64"
|
||||
if: ${{ matrix.platform == 'X64' }}
|
||||
if: ${{ matrix.platform != 'TEGRAX1' }}
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} != 'X64' ]]; then
|
||||
sudo apt-get -y install qemu-user
|
||||
fi
|
||||
|
||||
cd build
|
||||
ctest -j$(nproc)
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} != 'X64' ]]; then
|
||||
QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
else
|
||||
ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
fi
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v3
|
||||
|
||||
@@ -65,3 +65,6 @@ backup/
|
||||
!/LLVMprivateGenerator/Makefile
|
||||
!/LLVMprivateGenerator/main.cpp
|
||||
!/LLVMprivateGenerator/registered_structs.cpp
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
+135
-41
@@ -30,23 +30,27 @@ if(LARCH64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RV64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC ON CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(PPC64LE)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A OR M1)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A)
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
@@ -66,23 +70,26 @@ endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
option(RV64_DYNAREC "Set to ON to use RISC-V Dynamic Recompilation" ${RV64_DYNAREC})
|
||||
option(PAGE8K "Set to ON if host device have PageSize of 8K (instead of 4K)" ${PAGE8K})
|
||||
option(PAGE16K "Set to ON if host device have PageSize of 16K (instead of 4K)" ${PAGE16K})
|
||||
option(PAGE64K "Set to ON if host device have PageSize of 64K (instead of 4K)" ${PAGE64K})
|
||||
option(STATICBUILD "Set to ON to have a static build (Warning, not working)" ${STATICBUILD})
|
||||
option(NO_LIB_INSTALL "Set ON to not install a few x86_64 libs that are used by many program" ${NO_LIB_INSTALL})
|
||||
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
|
||||
message( FATAL_ERROR "You need a Python interpreter, CMake will exit." )
|
||||
endif()
|
||||
if(${PYTHON_VERSION_MAJOR} LESS 3)
|
||||
message( FATAL_ERROR "You need a Python 3 interpretor, CMake will exit." )
|
||||
message( FATAL_ERROR "You need a Python 3 interpreter, CMake will exit." )
|
||||
endif()
|
||||
else()
|
||||
find_package(Python3)
|
||||
if(NOT Python3_Interpreter_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
|
||||
message( FATAL_ERROR "You need a Python interpreter, CMake will exit." )
|
||||
endif()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
@@ -208,6 +215,12 @@ if(ARM_DYNAREC)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/arm64")
|
||||
set(DYNAREC ON)
|
||||
elseif(RV64_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DRV64)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/rv64")
|
||||
set(DYNAREC ON)
|
||||
else()
|
||||
set(DYNAREC OFF)
|
||||
endif()
|
||||
@@ -254,32 +267,9 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x64int3.c"
|
||||
"${BOX64_ROOT}/src/emu/x87emu_private.c"
|
||||
"${BOX64_ROOT}/src/emu/x64primop.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run0f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run64.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6664.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66d9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66dd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run670f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6766.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund8.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runda.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundb.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundc.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runde.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundf.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf20f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf30f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run_private.c"
|
||||
"${BOX64_ROOT}/src/emu/x64syscall.c"
|
||||
"${BOX64_ROOT}/src/emu/x86syscall.c"
|
||||
"${BOX64_ROOT}/src/emu/x64tls.c"
|
||||
"${BOX64_ROOT}/src/emu/x64trace.c"
|
||||
"${BOX64_ROOT}/src/librarian/librarian.c"
|
||||
@@ -294,6 +284,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX64_ROOT}/src/libtools/signals.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
"${BOX64_ROOT}/src/tools/box64stack.c"
|
||||
"${BOX64_ROOT}/src/tools/bridge.c"
|
||||
"${BOX64_ROOT}/src/tools/callback.c"
|
||||
@@ -306,6 +297,34 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
|
||||
set(INTERPRETER
|
||||
"${BOX64_ROOT}/src/emu/x64run.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run0f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run64.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6664.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66d9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66dd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67_32.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run670f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6766.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund8.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runda.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundb.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundc.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runde.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rundf.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf20f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf30f.c"
|
||||
)
|
||||
|
||||
set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalut.c"
|
||||
@@ -318,6 +337,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairogobject.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrypto.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrypto3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbusglib1.c"
|
||||
@@ -355,6 +375,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcrypt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
@@ -366,6 +387,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibgl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglx.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibibus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
@@ -373,6 +395,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibnuma.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpci.c"
|
||||
@@ -383,6 +406,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsndfile.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibssl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibssl3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibusb1.c"
|
||||
@@ -467,6 +491,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmime3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbbind.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
|
||||
@@ -488,6 +513,10 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedvulkan.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxshmfence.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc67.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n67.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc72.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n72.c"
|
||||
)
|
||||
|
||||
# If BOX64_ROOT contains a ".c", the build breaks...
|
||||
@@ -529,6 +558,8 @@ if(DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
"${BOX64_ROOT}/src/dynarec/dynablock.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native_functions.c"
|
||||
"${BOX64_ROOT}/src/emu/x64test.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -575,9 +606,57 @@ if(ARM_DYNAREC)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(RV64_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/rv64detect.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_logic.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_shift.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00_0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00_1.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00_2.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00_3.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_64.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_65.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_d8.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_d9.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_da.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_db.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_dc.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_dd.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_de.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_df.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_6664.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
|
||||
${DYNAREC_PASS}
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native_pass.c"
|
||||
)
|
||||
@@ -592,6 +671,8 @@ if(DYNAREC)
|
||||
set_target_properties(native_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(native_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_library(test_interpreter OBJECT ${INTERPRETER})
|
||||
set_target_properties(test_interpreter PROPERTIES COMPILE_FLAGS "-DTEST_INTERPRETER")
|
||||
add_dependencies(native_pass0 WRAPPERS)
|
||||
add_dependencies(native_pass1 WRAPPERS)
|
||||
add_dependencies(native_pass2 WRAPPERS)
|
||||
@@ -603,6 +684,7 @@ if(DYNAREC)
|
||||
$<TARGET_OBJECTS:native_pass1>
|
||||
$<TARGET_OBJECTS:native_pass2>
|
||||
$<TARGET_OBJECTS:native_pass3>
|
||||
$<TARGET_OBJECTS:test_interpreter>
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -611,16 +693,18 @@ if(DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
DEPENDS ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_library(interpreter OBJECT ${INTERPRETER})
|
||||
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head.h")
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
@@ -634,6 +718,7 @@ endif()
|
||||
if(DYNAREC)
|
||||
target_link_libraries(${BOX64} dynarec)
|
||||
endif()
|
||||
target_link_libraries(${BOX64} interpreter)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
@@ -657,6 +742,7 @@ endif()
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "riscv64" _riscv64)
|
||||
|
||||
if(_x86_64 OR _aarch64)
|
||||
add_definitions(-DCONFIG_64BIT)
|
||||
@@ -665,13 +751,17 @@ endif()
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX64}
|
||||
RUNTIME DESTINATION bin)
|
||||
configure_file(system/box64.conf.cmake system/box64.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION /etc/)
|
||||
if(NOT NO_CONF_INSTALL)
|
||||
configure_file(system/box64.conf.cmake system/box64.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION /etc/)
|
||||
endif()
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
@@ -705,6 +795,8 @@ set(CPACK_PACKAGE_VERSION_PATCH ${BOX64_REVISION})
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
if(_aarch64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||
elseif(__riscv64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "riscv64")
|
||||
elseif(_x86_64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
|
||||
else()
|
||||
@@ -795,14 +887,14 @@ add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_asm PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
|
||||
add_test(sse_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
|
||||
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
@@ -828,6 +920,8 @@ add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87 PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||

|
||||

|
||||
|
||||
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)
|
||||
[View changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Report an error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
@@ -14,11 +14,11 @@ You can find many Box64 videos on the [MicroLinux](https://www.youtube.com/chann
|
||||
|
||||
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/).
|
||||
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
|
||||
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">
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
@@ -29,7 +29,7 @@ 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.
|
||||
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.
|
||||
|
||||
@@ -37,14 +37,15 @@ Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault sig
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md).
|
||||
> Compilation instructions can be found [here](docs/COMPILE.md)\
|
||||
> Instructions for installing Wine for Box64 can be found [here](docs/X64WINE.md)
|
||||
|
||||
----
|
||||
|
||||
Version history/Change log
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md).
|
||||
The change log is available [here](docs/CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
@@ -114,6 +115,7 @@ 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/)
|
||||
* 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: [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/))
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# box64
|
||||
|
||||

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

|
||||
|
||||
[English](docs/README.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 平台的 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 位本地服务器,但与大多数使用 libcef/chromium 的东西一样,它目前无法在 box64 上正常工作。所以,现在 box64 上暂时不能运行 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
|
||||
* 硬件捐赠:[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,请不要忘记提及!)
|
||||
Vendored
+5
-5
@@ -1,6 +1,6 @@
|
||||
box64 (0.2.2) unstable; urgency=low
|
||||
|
||||
* Added a hacked version for overriden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* 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!)
|
||||
@@ -17,7 +17,7 @@ box64 (0.2.2) unstable; urgency=low
|
||||
* 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 Interpretor), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* 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
|
||||
@@ -27,7 +27,7 @@ box64 (0.2.2) unstable; urgency=low
|
||||
box64 (0.2.0) unstable; urgency=low
|
||||
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overriden malloc/free functions
|
||||
* 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
|
||||
@@ -92,7 +92,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
|
||||
+8
-8
@@ -1,6 +1,6 @@
|
||||
v0.2.2
|
||||
======
|
||||
* Added a hacked version for overriden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* 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
|
||||
@@ -22,7 +22,7 @@ v0.2.2
|
||||
* 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 Interpretor), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* 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
|
||||
@@ -30,7 +30,7 @@ v0.2.2
|
||||
v0.2.0
|
||||
======
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overriden malloc/free functions
|
||||
* 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
|
||||
@@ -80,8 +80,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
|
||||
======
|
||||
@@ -97,7 +97,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)
|
||||
|
||||
@@ -120,7 +120,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
|
||||
@@ -134,7 +134,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
|
||||
======
|
||||
|
||||
+47
-129
@@ -1,45 +1,57 @@
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
#### Debian-based Linux
|
||||
### 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 -O- https://ryanfortner.github.io/box64-debs/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/box64-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box64 -y
|
||||
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-generic-arm -y
|
||||
```
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
#### for RK3399
|
||||
----
|
||||
|
||||
Using a 64bit OS:
|
||||
### The general approach is:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
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 or maybe Termux
|
||||
|
||||
#### 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:
|
||||
```
|
||||
-D RK3399=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for RK3588 / RK3588S
|
||||
|
||||
Using a 64bit OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3588=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 RK3588=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 3
|
||||
@@ -55,16 +67,8 @@ run out of memory at some point and need to run the build again.
|
||||
Still, this can be faster if your build is attended.
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRPI3ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-D RPI3ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make
|
||||
# or e.g. make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 4
|
||||
@@ -72,15 +76,7 @@ sudo systemctl restart systemd-binfmt
|
||||
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
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D RPI4ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for TEGRA X1
|
||||
@@ -88,31 +84,16 @@ 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 ODROID N2/N2+
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DODROIDN2=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 845
|
||||
@@ -120,32 +101,14 @@ sudo systemctl restart systemd-binfmt
|
||||
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 SD845=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
|
||||
----
|
||||
#### 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
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D PHYTIUM=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for M1
|
||||
@@ -153,38 +116,15 @@ 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)`
|
||||
|
||||
You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588 or maybe Termux
|
||||
|
||||
#### 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 RISC-V
|
||||
@@ -192,15 +132,7 @@ sudo systemctl restart systemd-binfmt
|
||||
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 -j`nproc`
|
||||
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
|
||||
@@ -208,15 +140,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
|
||||
@@ -224,22 +148,16 @@ 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
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
-D LX2160A=1 -D 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
|
||||
|
||||
@@ -257,7 +175,7 @@ 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
|
||||
|
||||
@@ -282,4 +200,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`.
|
||||
@@ -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, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠:[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,请不要忘记提及!)
|
||||
+30
-6
@@ -38,7 +38,7 @@ Enables/Disables the logging of `dlsym` errors.
|
||||
#### 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 overwriten
|
||||
End the filename with `+` to have thetrace appended instead of overwritten
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX64_TRACE *
|
||||
@@ -130,9 +130,14 @@ Enables/Disables trace for generated code.
|
||||
* 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)
|
||||
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_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)
|
||||
@@ -178,12 +183,12 @@ Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
* 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)
|
||||
|
||||
#### BOX64_DYNAREC_HOTPAGE *
|
||||
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)
|
||||
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 beeing both executed and writen)
|
||||
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)
|
||||
|
||||
@@ -192,11 +197,26 @@ 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_DYNAREC_AGE *
|
||||
Dynarec will check if black can be freed when that atteins a certain age (in dynablock creation count)
|
||||
* 0 : do not age dynablocks (don't try to free old one)
|
||||
* XXXX: try to free block that are at least XXXX old (default 10240)
|
||||
|
||||
#### BOX64_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
* 0 : Just track the flag (Default)
|
||||
@@ -306,3 +326,7 @@ Those variables are only valid inside a rcfile:
|
||||
#### BOX64_EXIT
|
||||
* 0 : Nothing special
|
||||
* 1 : Just exit, don't try to run the program
|
||||
|
||||
#### 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)
|
||||
+465
@@ -0,0 +1,465 @@
|
||||
=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_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<BOX_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_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_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
|
||||
@@ -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,24 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
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
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r1495.e6e9fae
|
||||
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')
|
||||
@@ -9,30 +9,28 @@ 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}")
|
||||
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%-rpi-git}"
|
||||
cd "${srcdir}/${pkgname%-asahi-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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
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%-rpi-git}/build"
|
||||
cd "${srcdir}/${pkgname%-asahi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
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,24 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
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
|
||||
}
|
||||
@@ -1,38 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-lx2160a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-rpi-git
|
||||
pkgver=r1495.e6e9fae
|
||||
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')
|
||||
@@ -9,30 +9,28 @@ 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}")
|
||||
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%-rpi-git}"
|
||||
cd "${srcdir}/${pkgname%-odroid-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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
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%-rpi-git}/build"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-arm64-git
|
||||
pkgver=r1495.e6e9fae
|
||||
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')
|
||||
@@ -9,30 +9,28 @@ 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}")
|
||||
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%-arm64-git}"
|
||||
cd "${srcdir}/${pkgname%-phytium-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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
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%-arm64-git}/build"
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm64-git}/build"
|
||||
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,38 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -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,38 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box64-tegra-git
|
||||
pkgver=r1495.e6e9fae
|
||||
pkgname=box64-rv64-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
arch=('aarch64')
|
||||
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%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
|
||||
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%-tegra-git}"
|
||||
cd "${srcdir}/${pkgname%-rv64-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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
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%-tegra-git}/build"
|
||||
cd "${srcdir}/${pkgname%-rv64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-tegra-git}/build"
|
||||
cd "${srcdir}/${pkgname%-rv64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=r1495.e6e9fae
|
||||
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')
|
||||
@@ -9,30 +9,28 @@ 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}")
|
||||
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%-rk3399-git}"
|
||||
cd "${srcdir}/${pkgname%-sd845-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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
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%-rk3399-git}/build"
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
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,24 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
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
|
||||
}
|
||||
@@ -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,24 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
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
|
||||
}
|
||||
@@ -1,37 +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 -DCMAKE_INSTALL_PREFIX=/usr
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+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:
|
||||
|
||||
+41
-25
@@ -152,10 +152,10 @@ class FunctionConvention(object):
|
||||
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']),
|
||||
'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', '0', '1']
|
||||
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):
|
||||
@@ -384,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]
|
||||
@@ -825,7 +825,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
allowed_fpr : str = "fd"
|
||||
|
||||
# Sanity checks
|
||||
forbidden_simple: str = "EDKVOSNMHPA"
|
||||
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))
|
||||
@@ -880,6 +880,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_;
|
||||
@@ -908,12 +910,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
|
||||
@@ -933,6 +937,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": """
|
||||
@@ -994,10 +1000,10 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
# Rewrite the wrapper.c file:
|
||||
# i and u should only be 32 bits
|
||||
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
|
||||
'F': ["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*"],
|
||||
# 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", "int64_t", "int64_t", "uint8_t", "uint16_t", "uint64_t", "uint64_t", "float", "double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "void*", "void*"]
|
||||
'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:
|
||||
@@ -1032,11 +1038,11 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"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=(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=(uint64_t)fn({0});", # u should be uint32_t
|
||||
"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
|
||||
@@ -1053,17 +1059,19 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"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=(int64_t)fn({0});", # i should be int32_t
|
||||
"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=(uint64_t)fn({0});", # u should be uint32_t
|
||||
"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
|
||||
@@ -1082,27 +1090,27 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
}
|
||||
|
||||
# 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
|
||||
@@ -1119,6 +1127,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
|
||||
@@ -1146,6 +1156,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
|
||||
@@ -1173,17 +1185,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
|
||||
@@ -1200,6 +1214,8 @@ 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
|
||||
@@ -1438,6 +1454,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.2.0.16") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.2.0.17") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
+72
-16
@@ -76,7 +76,7 @@ int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
uint32_t tid = (uint32_t)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
|
||||
@@ -138,11 +138,24 @@ static void init_mutexes(box64context_t* context)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -191,7 +204,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
initCycleLog(context);
|
||||
|
||||
context->deferedInit = 1;
|
||||
context->deferredInit = 1;
|
||||
context->sel_serial = 1;
|
||||
|
||||
init_custommem_helper(context);
|
||||
@@ -200,8 +213,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
context->globaldefver = NewDefaultVersion();
|
||||
context->weakdefver = NewDefaultVersion();
|
||||
// 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
|
||||
@@ -212,6 +224,8 @@ 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();
|
||||
@@ -229,6 +243,22 @@ 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;
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
return context;
|
||||
@@ -251,8 +281,6 @@ void FreeBox64Context(box64context_t** context)
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib, NULL);
|
||||
FreeDictionnary(&ctx->versym);
|
||||
FreeDefaultVersion(&ctx->globaldefver);
|
||||
FreeDefaultVersion(&ctx->weakdefver);
|
||||
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
@@ -265,11 +293,13 @@ 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)
|
||||
box_free(ctx->deferedInitList);
|
||||
if(ctx->deferredInitList)
|
||||
box_free(ctx->deferredInitList);
|
||||
|
||||
/*box_free(ctx->argv);*/
|
||||
|
||||
@@ -325,7 +355,9 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
#ifndef DYNAREC
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
@@ -339,20 +371,44 @@ void FreeBox64Context(box64context_t** context)
|
||||
}
|
||||
|
||||
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
int idx = ctx->elfsize;
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)box_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 = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_REVISION 2
|
||||
#define BOX64_REVISION 3
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#ifndef __BUILD_INFO_H__
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
void PrintBox64Version();
|
||||
void PrintBox64Version(void);
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
+261
-59
@@ -26,6 +26,7 @@
|
||||
#include "threads.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/dynablock_private.h"
|
||||
#include "dynarec/native_lock.h"
|
||||
#include "dynarec/dynarec_next.h"
|
||||
|
||||
@@ -41,12 +42,17 @@ static uintptr_t box64_jmptbldefault0[1<<JMPTABL_SHIFT0];
|
||||
// lock addresses
|
||||
KHASH_SET_INIT_INT64(lockaddress)
|
||||
static kh_lockaddress_t *lockaddress = NULL;
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
static uint32_t mutex_prot;
|
||||
static uint32_t mutex_blocks;
|
||||
#else
|
||||
static pthread_mutex_t mutex_prot;
|
||||
static pthread_mutex_t mutex_blocks;
|
||||
#endif
|
||||
#else
|
||||
static pthread_mutex_t mutex_prot;
|
||||
static pthread_mutex_t mutex_blocks;
|
||||
#endif
|
||||
#if defined(PAGE64K)
|
||||
#define MEMPROT_SHIFT 16
|
||||
#define MEMPROT_SHIFT2 (16+16)
|
||||
@@ -67,6 +73,7 @@ typedef struct memprot_s
|
||||
uint8_t* prot;
|
||||
uint8_t* hot;
|
||||
} memprot_t;
|
||||
//#define TRACE_MEMSTAT
|
||||
#ifdef TRACE_MEMSTAT
|
||||
static uint64_t memprot_allocated = 0, memprot_max_allocated = 0;
|
||||
#endif
|
||||
@@ -110,14 +117,14 @@ typedef struct blockmark_s {
|
||||
#define PREV_BLOCK(b) (blockmark_t*)(((uintptr_t)(b) - (b)->prev.size) - sizeof(blockmark_t))
|
||||
#define LAST_BLOCK(b, s) (blockmark_t*)(((uintptr_t)(b)+(s))-sizeof(blockmark_t))
|
||||
|
||||
static void printBlock(blockmark_t* b, void* start)
|
||||
void printBlock(blockmark_t* b, void* start)
|
||||
{
|
||||
printf_log(LOG_INFO, "========== Block is:\n");
|
||||
printf_log(LOG_NONE, "========== Block is:\n");
|
||||
do {
|
||||
printf_log(LOG_INFO, "%c%p, fill=%d, size=0x%x (prev=%d/0x%x)\n", b==start?'*':' ', b, b->next.fill, b->next.size, b->prev.fill, b->prev.size);
|
||||
printf_log(LOG_NONE, "%c%p, fill=%d, size=0x%x (prev=%d/0x%x)\n", b==start?'*':' ', b, b->next.fill, b->next.size, b->prev.fill, b->prev.size);
|
||||
b = NEXT_BLOCK(b);
|
||||
} while(b->next.x32);
|
||||
printf_log(LOG_INFO, "===================\n");
|
||||
printf_log(LOG_NONE, "===================\n");
|
||||
}
|
||||
|
||||
// get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size
|
||||
@@ -181,6 +188,8 @@ static size_t getMaxFreeBlock(void* block, size_t block_size, void* start)
|
||||
}
|
||||
}
|
||||
|
||||
#define THRESHOLD (128-2*sizeof(blockmark_t))
|
||||
|
||||
static void* allocBlock(void* block, void *sub, size_t size, void** pstart)
|
||||
{
|
||||
(void)block;
|
||||
@@ -190,25 +199,26 @@ static void* allocBlock(void* block, void *sub, size_t size, void** pstart)
|
||||
|
||||
s->next.fill = 1;
|
||||
// check if a new mark is worth it
|
||||
if(s->next.size>size+2*sizeof(blockmark_t))
|
||||
if(s->next.size>size+2*sizeof(blockmark_t)+THRESHOLD) {
|
||||
size_t old_size = s->next.size;
|
||||
s->next.size = size;
|
||||
blockmark_t *m = NEXT_BLOCK(s); // this is new n
|
||||
m->prev.fill = 1;
|
||||
if(n!=m) {
|
||||
// new mark
|
||||
blockmark_t *m = NEXT_BLOCK(s);
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
m->next.fill = 0;
|
||||
m->next.size = ((uintptr_t)n - (uintptr_t)m) - sizeof(blockmark_t);
|
||||
m->next.size = old_size - (size + sizeof(blockmark_t));
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
n = m;
|
||||
} else {
|
||||
n->prev.fill = 1;
|
||||
}
|
||||
|
||||
if(pstart && sub==*pstart) {
|
||||
// get the next free block
|
||||
m = (blockmark_t*)*pstart;
|
||||
while(m->next.fill)
|
||||
m = NEXT_BLOCK(m);
|
||||
*pstart = (void*)m;
|
||||
while(n->next.fill)
|
||||
n = NEXT_BLOCK(n);
|
||||
*pstart = (void*)n;
|
||||
}
|
||||
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
|
||||
}
|
||||
@@ -222,7 +232,7 @@ static size_t freeBlock(void *block, void* sub, void** pstart)
|
||||
s->next.fill = 0;
|
||||
n->prev.fill = 0;
|
||||
// check if merge with previous
|
||||
if (s->prev.x32 && !s->prev.fill) {
|
||||
if (m!=s && s->prev.x32 && !s->prev.fill) {
|
||||
// remove s...
|
||||
m->next.size += s->next.size + sizeof(blockmark_t);
|
||||
n->prev.size = m->next.size;
|
||||
@@ -235,7 +245,7 @@ static size_t freeBlock(void *block, void* sub, void** pstart)
|
||||
s->next.size += n->next.size + sizeof(blockmark_t);
|
||||
n2->prev.size = s->next.size;
|
||||
}
|
||||
if(pstart && (uintptr_t)*pstart>(uintptr_t)sub) {
|
||||
if(pstart && (uintptr_t)*pstart>(uintptr_t)s) {
|
||||
*pstart = (void*)s;
|
||||
}
|
||||
// return free size at current block (might be bigger)
|
||||
@@ -258,7 +268,7 @@ static int expandBlock(void* block, void* sub, size_t newsize)
|
||||
if((size_t)(s->next.size + n->next.size + sizeof(blockmark_t)) < newsize)
|
||||
return 0; // free space too short
|
||||
// ok, doing the alloc!
|
||||
if((s->next.size+n->next.size+sizeof(blockmark_t))-newsize<2*sizeof(blockmark_t))
|
||||
if((s->next.size+n->next.size+sizeof(blockmark_t))-newsize<THRESHOLD+2*sizeof(blockmark_t))
|
||||
s->next.size += n->next.size+sizeof(blockmark_t);
|
||||
else
|
||||
s->next.size = newsize+sizeof(blockmark_t);
|
||||
@@ -283,7 +293,61 @@ static size_t sizeBlock(void* sub)
|
||||
return s->next.size;
|
||||
}
|
||||
|
||||
#define THRESHOLD (128-2*sizeof(blockmark_t))
|
||||
// return 1 if block is coherent, 0 if not (and printf the issues)
|
||||
int printBlockCoherent(int i)
|
||||
{
|
||||
if(i<0 || i>=n_blocks) {
|
||||
printf_log(LOG_NONE, "Error, %d should be between 0 and %d\n", i, n_blocks);
|
||||
return 0;
|
||||
}
|
||||
int ret = 1;
|
||||
blockmark_t* m = (blockmark_t*)p_blocks[i].block;
|
||||
// check if first is correct
|
||||
blockmark_t* first = getNextFreeBlock(m);
|
||||
if(p_blocks[i].first && p_blocks[i].first!=first) {printf_log(LOG_NONE, "First %p and stored first %p differs for block %d\n", first, p_blocks[i].first, i); ret = 0;}
|
||||
// check if maxfree is correct, with no hint
|
||||
size_t maxfree = getMaxFreeBlock(m, p_blocks[i].size, NULL);
|
||||
if(maxfree != p_blocks[i].maxfree) {printf_log(LOG_NONE, "Maxfree without hint %zd and stored maxfree %zd differs for block %d\n", maxfree, p_blocks[i].maxfree, i); ret = 0;}
|
||||
// check if maxfree from first is correct
|
||||
maxfree = getMaxFreeBlock(m, p_blocks[i].size, p_blocks[i].first);
|
||||
if(maxfree != p_blocks[i].maxfree) {printf_log(LOG_NONE, "Maxfree with hint %zd and stored maxfree %zd differs for block %d\n", maxfree, p_blocks[i].maxfree, i); ret = 0;}
|
||||
// check chain
|
||||
blockmark_t* last = (blockmark_t*)(((uintptr_t)m)+p_blocks[i].size-sizeof(blockmark_t));
|
||||
while(m<last) {
|
||||
blockmark_t* n = NEXT_BLOCK(m);
|
||||
if(!m->next.fill && !n->next.fill && n!=last) {
|
||||
printf_log(LOG_NONE, "Chain contains 2 subsequent free blocks %p (%d) and %p (%d) for block %d\n", m, m->next.size, n, n->next.size, i);
|
||||
ret = 0;
|
||||
}
|
||||
m = n;
|
||||
}
|
||||
if(m!=last) {
|
||||
printf_log(LOG_NONE, "Last block %p is behond expexted block %p for block %d\n", m, last, i);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void testAllBlocks()
|
||||
{
|
||||
size_t total = 0;
|
||||
size_t fragmented_free = 0;
|
||||
size_t max_free = 0;
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
printBlockCoherent(i);
|
||||
total += p_blocks[i].size;
|
||||
if(max_free<p_blocks[i].maxfree)
|
||||
max_free = p_blocks[i].maxfree;
|
||||
blockmark_t* m = (blockmark_t*)p_blocks[i].block;
|
||||
while(m->next.x32) {
|
||||
if(!m->next.fill)
|
||||
fragmented_free += m->next.size;
|
||||
m = NEXT_BLOCK(m);
|
||||
}
|
||||
}
|
||||
printf_log(LOG_NONE, "Total %d blocks, for %zd allocated memory, max_free %zd, toatal fragmented free %zd\n", n_blocks, total, max_free, fragmented_free);
|
||||
}
|
||||
|
||||
static size_t roundSize(size_t size)
|
||||
{
|
||||
@@ -314,9 +378,7 @@ void* customMalloc(size_t size)
|
||||
if(sub) {
|
||||
if(rsize-size<THRESHOLD)
|
||||
size = rsize;
|
||||
void* ret = allocBlock(p_blocks[i].block, sub, size, NULL);
|
||||
if(sub==p_blocks[i].first)
|
||||
p_blocks[i].first = getNextFreeBlock(sub);
|
||||
void* ret = allocBlock(p_blocks[i].block, sub, size, &p_blocks[i].first);
|
||||
if(rsize==p_blocks[i].maxfree)
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
mutex_unlock(&mutex_blocks);
|
||||
@@ -353,8 +415,8 @@ void* customMalloc(size_t size)
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
// alloc 1st block
|
||||
void* ret = allocBlock(p_blocks[i].block, p, size, NULL);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
|
||||
void* ret = allocBlock(p_blocks[i].block, p, size, &p_blocks[i].first);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
@@ -377,7 +439,7 @@ void* customRealloc(void* p, size_t size)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
if(expandBlock(p_blocks[i].block, sub, size)) {
|
||||
if(sub<p_blocks[i].first && p+size<p_blocks[i].first)
|
||||
if(sub<p_blocks[i].first && p+size>=p_blocks[i].first)
|
||||
p_blocks[i].first = getNextFreeBlock(sub);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
mutex_unlock(&mutex_blocks);
|
||||
@@ -405,10 +467,7 @@ void customFree(void* p)
|
||||
if ((addr>(uintptr_t)p_blocks[i].block)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
void* n = NEXT_BLOCK((blockmark_t*)sub);
|
||||
size_t newfree = freeBlock(p_blocks[i].block, sub, NULL);
|
||||
if(sub<=p_blocks[i].first)
|
||||
p_blocks[i].first = getPrevFreeBlock(n);
|
||||
size_t newfree = freeBlock(p_blocks[i].block, sub, &p_blocks[i].first);
|
||||
if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree;
|
||||
mutex_unlock(&mutex_blocks);
|
||||
return;
|
||||
@@ -423,6 +482,7 @@ void customFree(void* p)
|
||||
#define NCHUNK 64
|
||||
typedef struct mmaplist_s {
|
||||
blocklist_t chunks[NCHUNK];
|
||||
size_t minage[NCHUNK];
|
||||
mmaplist_t* next;
|
||||
} mmaplist_t;
|
||||
|
||||
@@ -464,11 +524,13 @@ dynablock_t* FindDynablockFromNativeAddress(void* p)
|
||||
#ifdef TRACE_MEMSTAT
|
||||
static uint64_t dynarec_allocated = 0;
|
||||
#endif
|
||||
uintptr_t AllocDynarecMap(size_t size)
|
||||
uintptr_t AllocDynarecMap(size_t size, size_t age)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
|
||||
static int current = 0;
|
||||
|
||||
size = roundSize(size);
|
||||
|
||||
mmaplist_t* list = mmaplist;
|
||||
@@ -476,8 +538,32 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
list = mmaplist = (mmaplist_t*)box_calloc(1, sizeof(mmaplist_t));
|
||||
// check if there is space in current open ones
|
||||
int i = 0;
|
||||
int current_i = 0;
|
||||
uintptr_t sz = size + 2*sizeof(blockmark_t);
|
||||
while(1) {
|
||||
size_t newage = 0;
|
||||
if(box64_dynarec_age && current==current_i && (!list->minage[i] || list->minage[i]<=age)) {
|
||||
//check age of blocks for cleaning
|
||||
blockmark_t* sub = (blockmark_t*)list->chunks[i].block;
|
||||
uintptr_t end = (uintptr_t)list->chunks[i].block+list->chunks[i].size-sizeof(blockmark_t);
|
||||
while(sub && (uintptr_t)sub<end) {
|
||||
blockmark_t* n = NEXT_BLOCK(sub);
|
||||
dynablock_t* db = NULL;
|
||||
if(n->next.fill)
|
||||
db = *(dynablock_t**)((uintptr_t)n+sizeof(blockmark_t));
|
||||
if(db) {
|
||||
size_t new_age = AgeDynablock(db, age);
|
||||
if(!new_age) // db has been removed
|
||||
n = sub; // go back 1 step
|
||||
else if(new_age<newage || !newage)
|
||||
newage = new_age;
|
||||
}
|
||||
sub = n;
|
||||
}
|
||||
list->minage[i] = newage;
|
||||
}
|
||||
if(current==current_i)
|
||||
current++;
|
||||
if(list->chunks[i].maxfree>=size) {
|
||||
// looks free, try to alloc!
|
||||
size_t rsize = 0;
|
||||
@@ -493,6 +579,8 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
}
|
||||
// check if new
|
||||
if(!list->chunks[i].size) {
|
||||
if(current_i+1==current)
|
||||
current = 0;
|
||||
// alloc a new block, aversized or not, we are at the end of the list
|
||||
size_t allocsize = (sz>MMAPSIZE)?sz:MMAPSIZE;
|
||||
// allign sz with pagesize
|
||||
@@ -518,6 +606,7 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
list->chunks[i].block = p;
|
||||
list->chunks[i].first = p;
|
||||
list->chunks[i].size = allocsize;
|
||||
list->minage[i] = age + box64_dynarec_age;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
@@ -536,6 +625,7 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
}
|
||||
// next chunk...
|
||||
++i;
|
||||
++current_i;
|
||||
if(i==NCHUNK) {
|
||||
i = 0;
|
||||
if(!list->next)
|
||||
@@ -557,10 +647,7 @@ void FreeDynarecMap(uintptr_t addr)
|
||||
if ((addr>(uintptr_t)list->chunks[i].block)
|
||||
&& (addr<((uintptr_t)list->chunks[i].block+list->chunks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
void* n = NEXT_BLOCK((blockmark_t*)sub);
|
||||
size_t newfree = freeBlock(list->chunks[i].block, sub, NULL);
|
||||
if(sub<=list->chunks[i].first)
|
||||
list->chunks[i].first = getPrevFreeBlock(n);
|
||||
size_t newfree = freeBlock(list->chunks[i].block, sub, &list->chunks[i].first);
|
||||
if(list->chunks[i].maxfree < newfree)
|
||||
list->chunks[i].maxfree = newfree;
|
||||
return;
|
||||
@@ -589,6 +676,7 @@ static uintptr_t getDBSize(uintptr_t addr, size_t maxsize, dynablock_t** db)
|
||||
uintptr_t* block = box64_jmptbl3[idx3][idx2][idx1];
|
||||
if(block == box64_jmptbldefault0)
|
||||
return (((addr>>JMPTABL_START1)+1)<<JMPTABL_START1);
|
||||
maxsize+=idx0; // need to adjust maxsize to "end in current block"
|
||||
if (maxsize>JMPTABLE_MASK0)
|
||||
maxsize = JMPTABLE_MASK0;
|
||||
while(block[idx0]==(uintptr_t)native_next) {
|
||||
@@ -600,6 +688,51 @@ static uintptr_t getDBSize(uintptr_t addr, size_t maxsize, dynablock_t** db)
|
||||
return (addr&~JMPTABLE_MASK0)+idx0+1;
|
||||
}
|
||||
|
||||
void freeJmpTable(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2) {
|
||||
return;
|
||||
}
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) {
|
||||
return;
|
||||
}
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) {
|
||||
return;
|
||||
}
|
||||
uintptr_t* tbl0 = box64_jmptbl3[idx3][idx2][idx1];
|
||||
for(int i=0; i<1<<JMPTABL_SHIFT0; ++i)
|
||||
if(tbl0[i]!=(uintptr_t)native_next)
|
||||
return;
|
||||
box64_jmptbl3[idx3][idx2][idx1] = box64_jmptbldefault0;
|
||||
box_free(tbl0);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
jmptbl_allocated -= (1<<JMPTABL_SHIFT0)*sizeof(uintptr_t);
|
||||
#endif
|
||||
uintptr_t** tbl1 = box64_jmptbl3[idx3][idx2];
|
||||
for(int i=0; i<1<<JMPTABL_SHIFT1; ++i)
|
||||
if(tbl1[i]!=box64_jmptbldefault0)
|
||||
return;
|
||||
box64_jmptbl3[idx3][idx2] = box64_jmptbldefault1;
|
||||
box_free(tbl1);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
jmptbl_allocated -= (1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*);
|
||||
#endif
|
||||
uintptr_t*** tbl2 = box64_jmptbl3[idx3];
|
||||
for(int i=0; i<1<<JMPTABL_SHIFT2; ++i)
|
||||
if(tbl2[i]!=box64_jmptbldefault1)
|
||||
return;
|
||||
box64_jmptbl3[idx3] = box64_jmptbldefault2;
|
||||
box_free(tbl2);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
jmptbl_allocated -= (1<<JMPTABL_SHIFT2)*sizeof(uintptr_t**);
|
||||
#endif
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
|
||||
void addDBFromAddressRange(uintptr_t addr, size_t size)
|
||||
@@ -614,14 +747,18 @@ void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?"destroy":"mark");
|
||||
dynablock_t* db = NULL;
|
||||
uintptr_t end = addr+size;
|
||||
uintptr_t old_addr = 0;
|
||||
while (start_addr<end) {
|
||||
start_addr = getDBSize(start_addr, end-start_addr, &db);
|
||||
old_addr = getDBSize(start_addr, end-start_addr, &db);
|
||||
if(db) {
|
||||
if(destroy)
|
||||
FreeRangeDynablock(db, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(db, addr, size);
|
||||
}
|
||||
/*if(destroy && start_addr && ((start_addr&~JMPTABLE_MASK0)!=(old_addr&~JMPTABLE_MASK0)))
|
||||
freeJmpTable(start_addr);*/ // cannot free jmpTable as some dynablock might rely on direct address (for fixed IP jmp/call)
|
||||
start_addr = old_addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,6 +907,28 @@ dynablock_t* getDB(uintptr_t addr)
|
||||
return *(dynablock_t**)(ret - sizeof(void*));
|
||||
}
|
||||
|
||||
int getNeedTest(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = ((addr) )&JMPTABLE_MASK0;
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
dynablock_t* db = *(dynablock_t**)(ret - sizeof(void*));
|
||||
return db?((ret!=(uintptr_t)db->block)?1:0):0;
|
||||
}
|
||||
|
||||
uintptr_t getJumpAddress64(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = ((addr) )&JMPTABLE_MASK0;
|
||||
return (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
}
|
||||
|
||||
// Remove the Write flag from an adress range, so DB can be executed safely
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
@@ -795,14 +954,16 @@ void protectDB(uintptr_t addr, uintptr_t size)
|
||||
uint32_t prot = memprot[i>>16].prot[i&0xffff];
|
||||
uint32_t dyn = prot&PROT_DYN;
|
||||
uint32_t mapped = prot&PROT_MMAP;
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute
|
||||
if((prot&PROT_WRITE)) {
|
||||
if(!dyn) mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i>>16].prot[i&0xffff] = prot|mapped|PROT_DYNAREC; // need to use atomic exchange?
|
||||
} else
|
||||
memprot[i>>16].prot[i&0xffff] = prot|mapped|PROT_DYNAREC_R;
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(!(dyn&PROT_NOPROT)) {
|
||||
if(prot&PROT_WRITE) {
|
||||
if(!dyn) mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i>>16].prot[i&0xffff] = prot|mapped|PROT_DYNAREC; // need to use atomic exchange?
|
||||
} else
|
||||
memprot[i>>16].prot[i&0xffff] = prot|mapped|PROT_DYNAREC_R;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
@@ -824,14 +985,16 @@ void unprotectDB(uintptr_t addr, size_t size, int mark)
|
||||
i=(((i>>16)+1)<<16)-1; // next block
|
||||
} else {
|
||||
uint32_t prot = memprot[i>>16].prot[i&0xffff];
|
||||
if(prot&PROT_DYNAREC) {
|
||||
prot&=~PROT_DYN;
|
||||
if(mark)
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_MMAP);
|
||||
memprot[i>>16].prot[i&0xffff] = prot; // need to use atomic exchange?
|
||||
} else if(prot&PROT_DYNAREC_R)
|
||||
memprot[i>>16].prot[i&0xffff] = prot&~PROT_CUSTOM;
|
||||
if(!(prot&PROT_NOPROT)) {
|
||||
if(prot&PROT_DYNAREC) {
|
||||
prot&=~PROT_DYN;
|
||||
if(mark)
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_MMAP);
|
||||
memprot[i>>16].prot[i&0xffff] = prot; // need to use atomic exchange?
|
||||
} else if(prot&PROT_DYNAREC_R)
|
||||
memprot[i>>16].prot[i&0xffff] = prot&~PROT_CUSTOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
@@ -977,11 +1140,13 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
uint32_t old_prot = memprot[i>>16].prot[i&0xffff];
|
||||
uint32_t dyn=(old_prot&PROT_DYN);
|
||||
uint32_t mapped=(old_prot&PROT_MMAP);
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
} else if(dyn && !(prot&PROT_WRITE)) {
|
||||
dyn = PROT_DYNAREC_R;
|
||||
if(!(dyn&PROT_NOPROT)) {
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
} else if(dyn && !(prot&PROT_WRITE)) {
|
||||
dyn = PROT_DYNAREC_R;
|
||||
}
|
||||
}
|
||||
memprot[i>>16].prot[i&0xffff] = prot|dyn|mapped;
|
||||
}
|
||||
@@ -1017,7 +1182,13 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
|
||||
void setProtection_mmap(uintptr_t addr, size_t size, uint32_t prot)
|
||||
{
|
||||
setProtection(addr, size, prot|PROT_MMAP);
|
||||
if(prot)
|
||||
setProtection(addr, size, prot|PROT_MMAP);
|
||||
else {
|
||||
mutex_lock(&mutex_prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
}
|
||||
|
||||
void refreshProtection(uintptr_t addr)
|
||||
@@ -1026,8 +1197,10 @@ void refreshProtection(uintptr_t addr)
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
if(memprot[idx>>16].prot!=memprot_default) {
|
||||
int prot = memprot[idx>>16].prot[idx&0xffff];
|
||||
int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box64_pagesize, prot&~PROT_CUSTOM);
|
||||
if(!(prot&PROT_DYNAREC)) {
|
||||
int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box64_pagesize, prot&~PROT_CUSTOM);
|
||||
printf_log(LOG_INFO, "refreshProtection(%p): %p/0x%x (ret=%d/%s)\n", (void*)addr, (void*)(idx<<MEMPROT_SHIFT), prot, ret, ret?strerror(errno):"ok");
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
@@ -1279,7 +1452,7 @@ int unlockCustommemMutex()
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
uint32_t tid = (uint32_t)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
|
||||
@@ -1312,7 +1485,7 @@ void relockCustommemMutex(int locks)
|
||||
|
||||
static void init_mutexes(void)
|
||||
{
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
native_lock_store(&mutex_blocks, 0);
|
||||
native_lock_store(&mutex_prot, 0);
|
||||
#else
|
||||
@@ -1332,6 +1505,34 @@ static void atfork_child_custommem(void)
|
||||
init_mutexes();
|
||||
}
|
||||
|
||||
void reserveHighMem()
|
||||
{
|
||||
char* p = getenv("BOX64_RESERVE_HIGH");
|
||||
if(!p || p[0]=='0')
|
||||
return; // don't reserve by default
|
||||
intptr_t cur = 1LL<<47;
|
||||
mapmem_t* m = mapmem;
|
||||
while(m && (m->end<cur)) {
|
||||
m = m->next;
|
||||
}
|
||||
while (m) {
|
||||
uintptr_t addr = 0, end = 0;
|
||||
if(m->begin>cur) {
|
||||
void* ret = mmap64((void*)cur, m->begin-cur, 0, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
|
||||
printf_log(LOG_DEBUG, "Reserve %p-%p => %p (%s)\n", (void*)cur, m->begin, ret, strerror(errno));
|
||||
printf_log(LOG_DEBUG, "mmap %p-%p\n", m->begin, m->end);
|
||||
if(ret!=(void*)-1) {
|
||||
addr = cur;
|
||||
end = m->begin;
|
||||
}
|
||||
}
|
||||
cur = m->end + 1;
|
||||
m = m->next;
|
||||
if(addr)
|
||||
addMapMem(addr, end);
|
||||
}
|
||||
}
|
||||
|
||||
void init_custommem_helper(box64context_t* ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
@@ -1360,9 +1561,10 @@ void init_custommem_helper(box64context_t* ctx)
|
||||
mapmem->begin = 0x0;
|
||||
mapmem->end = (uintptr_t)LOWEST - 1;
|
||||
loadProtectionFromMap();
|
||||
reserveHighMem();
|
||||
// check if PageSize is correctly defined
|
||||
if(box64_pagesize != (1<<MEMPROT_SHIFT)) {
|
||||
printf_log(LOG_NONE, "Error: PageSize configuation is wrong: configured with %d, but got %zd\n", 1<<MEMPROT_SHIFT, box64_pagesize);
|
||||
printf_log(LOG_NONE, "Error: PageSize configuration is wrong: configured with %d, but got %zd\n", 1<<MEMPROT_SHIFT, box64_pagesize);
|
||||
exit(-1); // abort or let it continue?
|
||||
}
|
||||
}
|
||||
@@ -1446,7 +1648,7 @@ void fini_custommem_helper(box64context_t *ctx)
|
||||
box_free(p_blocks[i].block);
|
||||
#endif
|
||||
box_free(p_blocks);
|
||||
#ifndef DYNAREC
|
||||
#ifndef USE_CUSTOM_MUTEX
|
||||
pthread_mutex_destroy(&mutex_prot);
|
||||
pthread_mutex_destroy(&mutex_blocks);
|
||||
#endif
|
||||
|
||||
@@ -130,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
|
||||
@@ -141,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))
|
||||
|
||||
@@ -151,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))
|
||||
@@ -160,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)
|
||||
@@ -176,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)
|
||||
@@ -221,6 +226,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))
|
||||
@@ -232,6 +238,7 @@
|
||||
#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 LDRH_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
|
||||
@@ -249,6 +256,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))
|
||||
@@ -257,6 +299,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))
|
||||
@@ -265,11 +308,13 @@
|
||||
#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))
|
||||
|
||||
@@ -282,6 +327,7 @@
|
||||
#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))
|
||||
@@ -309,6 +355,18 @@
|
||||
// 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 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))
|
||||
@@ -380,9 +438,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))
|
||||
@@ -477,6 +537,7 @@
|
||||
#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)
|
||||
@@ -726,6 +787,15 @@
|
||||
#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))
|
||||
#define VLDR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
@@ -1025,7 +1095,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))
|
||||
@@ -1223,6 +1293,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))
|
||||
@@ -1258,6 +1334,10 @@
|
||||
#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 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))
|
||||
@@ -1638,10 +1718,17 @@
|
||||
#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 MOVI_8(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_16(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1000, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_32(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b0000, ((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))
|
||||
@@ -1711,35 +1798,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))
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
.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
|
||||
@@ -97,13 +99,13 @@ 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
|
||||
cbnz w3, arm64_lock_xchg_dd_0
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
@@ -117,6 +119,26 @@ 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
|
||||
1:
|
||||
|
||||
@@ -28,11 +28,17 @@ extern void arm64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
|
||||
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);
|
||||
extern uintptr_t arm64_lock_xchg_dd(void* p, uintptr_t val);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_d(void* p, uint32_t val);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_h(void* p, uint32_t val);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_b(void* p, uint32_t val);
|
||||
|
||||
// Atomicaly 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);
|
||||
|
||||
|
||||
@@ -160,13 +160,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), "LDRUH %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), "LDRUSB %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), "LDRUSH %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), "LDRUSW %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), "STRUH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x11100101iiiiiiiiiiiinnnnnttttt", &a)) {
|
||||
@@ -903,6 +950,28 @@ 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;
|
||||
}
|
||||
// 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 (not)shifted 16bits & 32bits
|
||||
if(isMask(opcode, "0Q00111100000iiif00001iiiiiddddd", &a)) {
|
||||
const char* Y[] = {"2S", "4S", "4H", "8H"};
|
||||
const char* Vd = Y[(sf<<1)| a.Q];
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// Shift
|
||||
if(isMask(opcode, "0QU011110hhhhrrr000001nnnnnddddd", &a)) {
|
||||
@@ -1039,6 +1108,72 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
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)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
@@ -1048,6 +1183,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 +1206,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)) {
|
||||
@@ -1236,14 +1402,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 +1430,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 +1443,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;
|
||||
}
|
||||
|
||||
@@ -1365,6 +1523,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
// DMB ISH
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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"
|
||||
@@ -42,6 +41,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
@@ -65,7 +65,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(arm_ud, -1);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -74,6 +74,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("SYSCALL");
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
@@ -94,7 +95,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(arm_ud, -1);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -106,7 +107,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(arm_ud, -1);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -118,7 +119,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("PREFETCHW");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PST_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
default: //???
|
||||
@@ -138,8 +139,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -152,8 +153,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 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;
|
||||
@@ -168,7 +169,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 0, ed);
|
||||
}
|
||||
break;
|
||||
@@ -180,7 +181,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -212,7 +213,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
@@ -224,7 +225,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -237,22 +238,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L1_KEEP_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L2_KEEP_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L3_KEEP_U12(ed, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
@@ -279,8 +280,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
@@ -293,8 +294,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 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;
|
||||
@@ -309,8 +310,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 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);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -321,24 +322,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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 = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
}
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
CALL(ReadTSC, xRAX); // will return the u64 in xEAX
|
||||
LSRx(xRDX, xRAX, 32);
|
||||
MOVw_REG(xRAX, xRAX); // wipe upper part
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
LSRx(xRDX, x3, 32);
|
||||
MOVw_REG(xRAX, x3); // wipe upper part
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
@@ -386,8 +381,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
REVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDRxw_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
REVxw(gd, gd);
|
||||
}
|
||||
break;
|
||||
@@ -398,9 +393,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) { // reg <= reg
|
||||
REVxw(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
REVxw(x1, gd);
|
||||
STRxw_U12(x1, ed, fixedaddress);
|
||||
STxw(x1, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -420,7 +415,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q1, 1);
|
||||
u8 = F8;
|
||||
if(u8>15) {
|
||||
VEOR(q0, q0, q0);
|
||||
VEOR(q0, q0, q0);
|
||||
} else if(u8>7) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VEOR(d0, d0, d0);
|
||||
@@ -443,9 +438,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
CSELxw(gd, ed, gd, YES); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0); \
|
||||
Bcond(NO, +8); \
|
||||
LDRxw_U12(gd, ed, fixedaddress); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
if(!rex.w) {MOVw_REG(gd, gd);} \
|
||||
}
|
||||
|
||||
@@ -472,7 +467,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
// EX is memory
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, (0xfff<<3)-8, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0xfff<<3)-8, 7, rex, NULL, 0, 0);
|
||||
LDRx_U12(x1, ed, fixedaddress+0);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 0, 1);
|
||||
@@ -495,13 +490,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
// more precise
|
||||
if(q1==q0)
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
else
|
||||
else
|
||||
v1 = q1;
|
||||
VFRSQRTEQS(v0, q0);
|
||||
VFMULQS(v1, v0, q0);
|
||||
@@ -511,6 +507,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
if(q0 == q1)
|
||||
@@ -597,6 +594,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, v1, q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
}
|
||||
VFMINQS(v0, v0, v1);
|
||||
break;
|
||||
case 0x5E:
|
||||
@@ -611,6 +617,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, v1, q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
}
|
||||
VFMAXQS(v0, v0, v1);
|
||||
break;
|
||||
case 0x60:
|
||||
@@ -675,7 +690,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VMOVeD(q0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(q0, 1, ed);
|
||||
}
|
||||
SQXTUN_8(v0, q0);
|
||||
@@ -711,7 +726,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(v1, 0);
|
||||
VMOVeD(q0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(q0, 1, ed);
|
||||
}
|
||||
SQXTN_16(v0, q0);
|
||||
@@ -731,12 +746,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FMOVSw(v0, ed);
|
||||
}
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
} else {
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
VLD32(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -750,8 +764,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
@@ -818,7 +832,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
i32 = -1;
|
||||
@@ -997,11 +1011,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(ed, ed);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
if(rex.w) {
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
} else {
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
VST32(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -1014,8 +1028,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOV(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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;
|
||||
@@ -1065,16 +1079,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} \
|
||||
BFIx(eb1, x3, eb2, 8); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0); \
|
||||
STRB_U12(x3, ed, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 0); \
|
||||
STB(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
#undef GO
|
||||
|
||||
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
NOTEST(x1);
|
||||
MOVx_REG(x1, xRAX);
|
||||
CALL_(my_cpuid, -1, 0);
|
||||
break;
|
||||
@@ -1088,10 +1103,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
if(rex.w) {
|
||||
@@ -1136,10 +1151,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
@@ -1209,7 +1224,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 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(rex.w?((void*)fpu_fxsave64):((void*)fpu_fxsave32), -1);
|
||||
}
|
||||
@@ -1221,12 +1236,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 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(rex.w?((void*)fpu_fxrstor64):((void*)fpu_fxrstor32), -1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
@@ -1241,18 +1256,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("STMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STRw_U12(x4, ed, fixedaddress);
|
||||
STW(x4, ed, fixedaddress);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
GETED(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_clflush, -1, 0);
|
||||
CALL_(native_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -1302,10 +1317,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
@@ -1347,8 +1362,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDRB_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDB(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xB7:
|
||||
@@ -1360,8 +1375,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UBFXxw(gd, ed, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRH_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDH(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1377,8 +1392,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
@@ -1394,8 +1409,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
@@ -1405,7 +1420,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK3;
|
||||
@@ -1419,8 +1434,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
@@ -1430,7 +1445,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK3;
|
||||
@@ -1444,8 +1459,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
@@ -1454,7 +1469,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK3;
|
||||
@@ -1474,10 +1489,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
@@ -1497,7 +1512,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
EORxw_REG(ed, ed, x4);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -1548,8 +1563,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SBFXxw(gd, wback, wb2, 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDRSBxw_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDSBxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xBF:
|
||||
@@ -1561,8 +1576,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTHxw(gd, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRSHxw_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDSHxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1577,21 +1592,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0: VFCMEQQS(v0, v0, v1); break; // Equal
|
||||
case 1: VFCMGTQS(v0, v1, v0); break; // Less than
|
||||
case 2: VFCMGEQS(v0, v1, v0); break; // Less or equal
|
||||
case 3: VFCMEQQS(v0, v0, v0);
|
||||
case 3: VFCMEQQS(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
}
|
||||
VMVNQ(v0, v0);
|
||||
VMVNQ(v0, v0);
|
||||
break; // NaN (NaN is not equal to himself)
|
||||
case 4: VFCMEQQS(v0, v0, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: VFCMGTQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or equal or unordered
|
||||
case 6: VFCMGEQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
|
||||
case 7: VFCMEQQS(v0, v0, v0);
|
||||
case 7: VFCMEQQS(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
}
|
||||
break; // not NaN
|
||||
@@ -1604,8 +1619,8 @@ uintptr_t dynarec64_0F(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, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
STRxw_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
STxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xC4:
|
||||
@@ -1617,7 +1632,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
VMOVQHfrom(v0, u8, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&3;
|
||||
VLD1_16(v0, u8, wback);
|
||||
}
|
||||
@@ -1631,7 +1646,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = (F8)&3;
|
||||
VMOVHto(gd, v0, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&3;
|
||||
LDRH_U12(gd, wback, u8*2);
|
||||
}
|
||||
@@ -1641,7 +1656,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if(!MODREG) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = -1; // to avoid a warning
|
||||
} else
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
@@ -1723,7 +1738,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
USHL_8(q1, q1, v0); // shift
|
||||
UADDLV_8(q1, q1); // accumalte
|
||||
VMOVBto(gd, q1, 0);
|
||||
break;
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("PSUBUSB Gm, Em");
|
||||
nextop = F8;
|
||||
@@ -1814,8 +1829,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
} else {
|
||||
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
@@ -1832,7 +1847,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q0, 0);
|
||||
SQSUB_16(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xEA:
|
||||
INST_NAME("PMINSW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(q0, 0);
|
||||
SMIN_16(v0, v0, q0);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("POR Gm, Em");
|
||||
nextop = F8;
|
||||
@@ -1854,7 +1875,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(d1, 0);
|
||||
SQADD_16(d0, d0, d1);
|
||||
break;
|
||||
|
||||
case 0xEE:
|
||||
INST_NAME("PMAXSW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(q0, 0);
|
||||
SMAX_16(v0, v0, q0);
|
||||
break;
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gm,Em");
|
||||
nextop = F8;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -23,8 +22,6 @@
|
||||
#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;
|
||||
@@ -35,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);
|
||||
@@ -55,12 +54,7 @@ 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) {
|
||||
|
||||
@@ -93,9 +87,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
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:
|
||||
@@ -111,9 +105,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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:
|
||||
@@ -133,9 +127,9 @@ 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, NULL, 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;
|
||||
@@ -150,9 +144,9 @@ 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, NULL, 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;
|
||||
@@ -167,9 +161,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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;
|
||||
@@ -191,9 +185,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
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:
|
||||
@@ -260,7 +254,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
@@ -293,7 +287,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);
|
||||
@@ -315,26 +309,31 @@ 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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 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);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 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;
|
||||
@@ -535,7 +534,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(x4, wback, x4);
|
||||
ed = x4;
|
||||
}
|
||||
@@ -549,7 +548,7 @@ 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, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRxw_REG(gd, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -564,11 +563,71 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
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 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 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);
|
||||
@@ -581,12 +640,12 @@ 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, NULL, 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);
|
||||
@@ -602,7 +661,7 @@ 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, NULL, 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);
|
||||
@@ -813,9 +872,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:
|
||||
@@ -893,8 +953,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);
|
||||
@@ -917,6 +977,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)
|
||||
@@ -929,7 +990,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)
|
||||
@@ -955,7 +1016,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);
|
||||
@@ -984,7 +1045,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDOx(x6, 0);
|
||||
GETEDOz(x6, 0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
@@ -1006,22 +1067,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1(xRIP);
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETEDOx(x6, 0);
|
||||
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:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -35,6 +34,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int lock;
|
||||
MAYUSE(u8);
|
||||
MAYUSE(u16);
|
||||
@@ -49,14 +49,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// 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
|
||||
if(rex.w && !(opcode==0x0f || opcode==0xf0 || opcode==0x64 || opcode==0x65)) // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode
|
||||
|
||||
switch(opcode) {
|
||||
@@ -87,7 +82,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -294,6 +289,70 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg16 (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
UXTHw(x1, gd);
|
||||
emit_inc16(dyn, ninst, x1, x2, x3);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg16 (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
UXTHw(x1, gd);
|
||||
emit_dec16(dyn, ninst, x1, x2, x3);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("PUSHA 16 (32bits)");
|
||||
MOVw_REG(x1, xRSP);
|
||||
STRH_S9_preindex(xRAX, xRSP, -2);
|
||||
STRH_S9_preindex(xRCX, xRSP, -2);
|
||||
STRH_S9_preindex(xRDX, xRSP, -2);
|
||||
STRH_S9_preindex(xRBX, xRSP, -2);
|
||||
STRH_S9_preindex(x1, xRSP, -2);
|
||||
STRH_S9_preindex(xRBP, xRSP, -2);
|
||||
STRH_S9_preindex(xRSI, xRSP, -2);
|
||||
STRH_S9_preindex(xRDI, xRSP, -2);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x61:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POPA 16 (32bits)");
|
||||
MOVw_REG(x1, xRSP);
|
||||
LDRH_S9_postindex(xRDI, xRSP, 2);
|
||||
LDRH_S9_postindex(xRSI, xRSP, 2);
|
||||
LDRH_S9_postindex(xRBP, xRSP, 2);
|
||||
LDRH_S9_postindex(x1, xRSP, 2);
|
||||
LDRH_S9_postindex(xRBX, xRSP, 2);
|
||||
LDRH_S9_postindex(xRDX, xRSP, 2);
|
||||
LDRH_S9_postindex(xRCX, xRSP, 2);
|
||||
LDRH_S9_postindex(xRAX, xRSP, 2);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _FS, ok, need_epilog);
|
||||
break;
|
||||
@@ -424,7 +483,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -445,7 +504,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
TSTx_mask(ed, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
@@ -462,7 +521,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
@@ -473,8 +532,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
STRH_U12(gd, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
STH(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
@@ -488,12 +547,25 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
LDH(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
case 0x8C:
|
||||
INST_NAME("MOV EW, Seg");
|
||||
nextop=F8;
|
||||
u8 = (nextop&0x38)>>3;
|
||||
LDRw_U12(x3, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
UXTHw(xRAX+(nextop&7)+(rex.b<<3), x3);
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
STH(x3, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
@@ -522,16 +594,22 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
LDRH_U12(x2, x1, 0);
|
||||
BFIx(xRAX, x2, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
u64 = F64;
|
||||
MOV64x(x1, u64);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -563,6 +641,46 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA7:
|
||||
switch(rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
LDRH_S9_postindex(x2, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CMPSw_REG(x1, x2);
|
||||
B_MARK3((rep==1)?cEQ:cNE);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRH_S9_postindex(x1, xRSI, -2);
|
||||
LDRH_S9_postindex(x2, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CMPSw_REG(x1, x2);
|
||||
B_MARK3((rep==1)?cEQ:cNE);
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
LDRH_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -595,6 +713,67 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAD:
|
||||
if(rep) {
|
||||
INST_NAME("REP LODSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(xRAX, xRSI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRH_S9_postindex(xRAX, xRSI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(xRAX, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAF:
|
||||
switch(rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
UXTHw(x1, xRAX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x2, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CMPSw_REG(x1, x2);
|
||||
B_MARK3((rep==1)?cEQ:cNE);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRH_S9_postindex(x2, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CMPSw_REG(x1, x2);
|
||||
B_MARK3((rep==1)?cEQ:cNE);
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, 2);
|
||||
UXTHw(x1, xRAX);
|
||||
LDRH_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
@@ -707,10 +886,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x1, u16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, &lock, 0, 2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
STRH_U12(x1, ed, fixedaddress);
|
||||
STH(x1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
@@ -821,7 +1000,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
@@ -885,6 +1064,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETSEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
@@ -896,7 +1076,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -918,6 +1098,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
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,8 +21,6 @@
|
||||
#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 seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
@@ -34,14 +31,10 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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");
|
||||
@@ -66,8 +59,8 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn); \
|
||||
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);
|
||||
@@ -83,7 +76,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
@@ -109,7 +102,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
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 {
|
||||
@@ -135,7 +128,7 @@ 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, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
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 {
|
||||
|
||||
@@ -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,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
@@ -44,12 +44,8 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0/66 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
case 0x09:
|
||||
@@ -64,7 +60,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
@@ -93,7 +89,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
B_MARK(cNE);
|
||||
BFIx(ed, gd, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
// Aligned version
|
||||
@@ -123,7 +119,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("LOCK XADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -137,7 +133,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_add16(dyn, ninst, x5, gd, x3, x4);
|
||||
BFIx(ed, x5, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
ADDxw_REG(x4, x1, x5);
|
||||
@@ -177,7 +173,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
@@ -188,7 +184,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
@@ -209,7 +205,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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;
|
||||
@@ -231,7 +227,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_adc16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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;
|
||||
@@ -253,7 +249,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_sbb16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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;
|
||||
@@ -274,7 +270,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_and16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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;
|
||||
@@ -295,7 +291,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_sub16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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);
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
@@ -306,7 +302,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
@@ -327,7 +323,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_xor16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
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;
|
||||
@@ -369,7 +365,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_inc16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x4);
|
||||
@@ -388,7 +384,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_dec16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x4);
|
||||
|
||||
@@ -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,8 +29,9 @@ 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, wb1, wb2, gb1, gb2;
|
||||
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;
|
||||
@@ -55,12 +47,14 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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;
|
||||
@@ -186,8 +180,8 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
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);
|
||||
@@ -210,8 +204,8 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -229,8 +223,8 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -239,6 +233,40 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
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 = 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;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -563,6 +591,54 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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;
|
||||
@@ -640,7 +716,40 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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)>>2);
|
||||
gb1 = xRAX+(gd&3);
|
||||
}
|
||||
if(gb2) {
|
||||
gd = x4;
|
||||
UBFXw(gd, gb1, gb2*8, 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;
|
||||
@@ -648,8 +757,8 @@ 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, &lock, 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;
|
||||
@@ -661,9 +770,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
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);
|
||||
LDRxw_U12(gd, ed, fixedaddress);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -674,8 +783,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, NULL, 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);
|
||||
}
|
||||
@@ -763,10 +871,10 @@ uintptr_t dynarec64_67(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 = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 4);
|
||||
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);
|
||||
STRxw_U12(x3, ed, fixedaddress);
|
||||
STxw(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
@@ -914,9 +1022,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);
|
||||
@@ -939,6 +1047,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)
|
||||
@@ -951,7 +1060,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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -185,8 +185,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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, NULL, 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, NULL, 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, NULL, 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 {
|
||||
@@ -240,8 +240,8 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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, NULL, 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, NULL, 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, NULL, 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"
|
||||
@@ -33,6 +32,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
@@ -180,21 +180,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1);
|
||||
CALL(native_f2xm1, -1);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1);
|
||||
CALL(native_fyl2x, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1);
|
||||
CALL(native_ftan, -1);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
@@ -207,7 +207,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1);
|
||||
CALL(native_fpatan, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
@@ -215,14 +215,14 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1);
|
||||
CALL(native_fxtract, -1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1);
|
||||
CALL(native_fprem1, -1);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -245,14 +245,14 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1);
|
||||
CALL(native_fprem, -1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1);
|
||||
CALL(native_fyl2xp1, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xFA:
|
||||
@@ -269,7 +269,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fsincos, -1);
|
||||
CALL(native_fsincos, -1);
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
@@ -277,7 +277,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
CALL(native_frndint, -1);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
@@ -294,19 +294,19 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fscale, -1);
|
||||
CALL(native_fscale, -1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fsin, -1);
|
||||
CALL(native_fsin, -1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fcos, -1);
|
||||
CALL(native_fcos, -1);
|
||||
break;
|
||||
|
||||
|
||||
@@ -328,8 +328,8 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v1, ed, fixedaddress);
|
||||
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, v1);
|
||||
}
|
||||
@@ -343,24 +343,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, NULL, 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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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);
|
||||
}
|
||||
VSTR32_U12(v1, ed, fixedaddress);
|
||||
VST32(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 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);
|
||||
}
|
||||
@@ -376,7 +376,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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);
|
||||
}
|
||||
@@ -385,7 +385,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, NULL, 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));
|
||||
|
||||
@@ -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;
|
||||
@@ -189,15 +189,15 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v1, ed, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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;
|
||||
@@ -211,11 +211,11 @@ 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);
|
||||
@@ -224,7 +224,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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;
|
||||
@@ -238,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);
|
||||
@@ -251,7 +251,7 @@ 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
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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;
|
||||
@@ -265,11 +265,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);
|
||||
@@ -277,7 +277,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 0, 0);
|
||||
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);
|
||||
@@ -291,20 +291,19 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else
|
||||
rex.rex = 0;
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 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(box64_x87_no80bits) {
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1);
|
||||
CALL(native_fld, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -312,20 +311,20 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSTP tbyte");
|
||||
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, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v1, wback, fixedaddress);
|
||||
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, 0, 0, rex, NULL, 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_fstp, -1);
|
||||
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, 0, 0, rex, NULL, 0, 0);
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
@@ -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, 7, rex, NULL, 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, 7, rex, NULL, 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, 7, rex, NULL, 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,8 +207,8 @@ 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, 7, rex, NULL, 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);
|
||||
@@ -217,32 +217,32 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 7, rex, NULL, 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, 7, rex, NULL, 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, 7, rex, NULL, 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, 7, rex, NULL, 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,6 +30,7 @@ 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;
|
||||
@@ -161,13 +161,13 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 0, 0);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
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_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// those are ARM 8.5 opcode!
|
||||
@@ -180,11 +180,11 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MSR_fpsr(x5);
|
||||
FRINTRRD(s0, v1, 3);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
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
|
||||
STRw_U12(x5, ed, fixedaddress);
|
||||
STx(x5, ed, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
@@ -192,36 +192,36 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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, NULL, 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);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
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, NULL, 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:
|
||||
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, NULL, 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, NULL, 0, 0);
|
||||
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) {
|
||||
@@ -234,7 +234,7 @@ 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
|
||||
STH(x3, ed, fixedaddress); // store whole sw flags
|
||||
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_DE(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);
|
||||
@@ -191,8 +191,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -202,8 +202,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -213,8 +213,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -225,8 +225,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -238,8 +238,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -249,8 +249,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -260,8 +260,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
@@ -271,8 +271,8 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLDR16_U12(v2, wback, fixedaddress);
|
||||
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);
|
||||
|
||||
@@ -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,7 @@ 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;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
@@ -59,7 +59,8 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
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:
|
||||
@@ -151,8 +152,8 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 0, 0);
|
||||
LDRSHw_U12(x1, wback, fixedaddress);
|
||||
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 +163,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, NULL, 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 +173,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,13 +185,16 @@ 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);
|
||||
break;
|
||||
@@ -197,7 +202,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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 +211,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 +225,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 +242,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, NULL, 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 +251,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,13 +264,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_do_pop(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -269,50 +281,100 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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, NULL, 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_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, NULL, 0, 0);
|
||||
LDRx_U12(x1, wback, fixedaddress);
|
||||
SCVTFDx(v1, x1);
|
||||
v1 = x87_do_push(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");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, NULL, 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);
|
||||
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, NULL, 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);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STRx_U12(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
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_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
@@ -432,7 +430,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);
|
||||
|
||||
@@ -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"
|
||||
@@ -327,7 +325,7 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
if(c==1) {
|
||||
LSRxw(s3, s1, rex.w?62:30);
|
||||
EORxw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
@@ -46,12 +46,8 @@ uintptr_t dynarec64_F0(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 0x00:
|
||||
@@ -65,15 +61,15 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x3);
|
||||
BFIx(wback, x1, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
@@ -92,7 +88,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
@@ -113,15 +109,15 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x3);
|
||||
BFIx(wback, x1, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x5);
|
||||
@@ -140,7 +136,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_or32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
@@ -187,7 +183,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
}
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
ADDx_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
MARKLOCK;
|
||||
@@ -219,11 +215,11 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2)*8;
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
}
|
||||
UBFXx(x2, wback, wb2, 8);
|
||||
wb1 = 0;
|
||||
ed = x2;
|
||||
@@ -236,7 +232,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(xRAX, x2, 0, 8);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x2, wback);
|
||||
CMPSxw_REG(x6, x2);
|
||||
@@ -246,7 +242,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
MARK;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, x6, x2, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x6, x2, x3, x4, x5);}
|
||||
BFIx(xRAX, x2, 0, 8);
|
||||
}
|
||||
SMDMB();
|
||||
@@ -275,7 +271,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(xRAX, x1);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK3(cNE);
|
||||
// Aligned version
|
||||
@@ -343,7 +339,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
}
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
ADDx_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
MARKLOCK;
|
||||
@@ -378,7 +374,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(gd, x1);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
@@ -415,7 +411,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
MARKLOCK;
|
||||
LDAXPxw(x2, x3, wback);
|
||||
@@ -444,7 +440,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("LOCK AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -455,7 +451,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_and32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_and32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
@@ -464,7 +460,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("LOCK SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -475,7 +471,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
@@ -502,7 +498,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -522,7 +518,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -543,7 +539,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -564,7 +560,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -584,7 +580,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -604,7 +600,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -624,7 +620,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
wb1 = 0;
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MARKLOCK;
|
||||
@@ -669,7 +665,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_add32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
@@ -680,7 +676,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
@@ -699,7 +695,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_or32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
@@ -719,7 +715,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
@@ -739,7 +735,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
@@ -758,7 +754,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_and32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
@@ -777,7 +773,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_sub32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
@@ -788,7 +784,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
@@ -807,7 +803,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x5, i64);
|
||||
emit_xor32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
@@ -833,7 +829,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
|
||||
case 0x86:
|
||||
INST_NAME("LOCK XCHG Eb, Gb");
|
||||
// Do the swap
|
||||
@@ -856,7 +852,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
SMDMB();
|
||||
GETGB(x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
// do the swap with exclusive locking
|
||||
LDAXRB(x1, ed);
|
||||
@@ -879,7 +875,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
GETGD;
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
@@ -895,7 +891,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xF6:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -917,7 +913,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
EBBACK;
|
||||
} else {
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
MVNw_REG(x1, x1);
|
||||
@@ -930,7 +926,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xFE:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7)
|
||||
@@ -944,7 +940,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_inc8(dyn, ninst, x1, x2, x4);
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_inc8(dyn, ninst, x1, x3, x4);
|
||||
@@ -962,7 +958,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_dec8(dyn, ninst, x1, x2, x4);
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_dec8(dyn, ninst, x1, x3, x4);
|
||||
@@ -987,7 +983,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
@@ -1016,7 +1012,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
@@ -1041,7 +1037,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
}
|
||||
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"
|
||||
@@ -36,6 +35,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
int q0;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
@@ -57,8 +57,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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:
|
||||
@@ -71,8 +71,8 @@ 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, NULL, 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;
|
||||
@@ -87,8 +87,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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;
|
||||
@@ -154,6 +154,42 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38: // these are some more SSSE4.2+ opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("(unsupported) CRC32 Gd, Eb)");
|
||||
nextop = F8;
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("(unsupported) CRC32 Gd, Ed)");
|
||||
nextop = F8;
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
@@ -261,7 +297,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;
|
||||
@@ -299,7 +335,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;
|
||||
@@ -334,9 +370,9 @@ 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, NULL, 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;
|
||||
@@ -365,7 +401,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("ADDSUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
@@ -385,13 +421,39 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xE6:
|
||||
INST_NAME("CVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 0);
|
||||
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:
|
||||
@@ -405,8 +467,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 7, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 7, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
@@ -35,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);
|
||||
@@ -58,8 +58,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -71,8 +71,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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, NULL, 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;
|
||||
@@ -83,9 +83,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
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);
|
||||
@@ -98,9 +98,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
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);
|
||||
@@ -143,7 +143,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -168,7 +168,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -239,9 +239,27 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x5B:
|
||||
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:
|
||||
@@ -305,8 +323,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
@@ -341,8 +359,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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);
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
@@ -353,12 +371,48 @@ 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, NULL, 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;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
@@ -421,8 +475,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOV(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 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);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -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,332 +26,6 @@
|
||||
#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_priv(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGSEGV, (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]];
|
||||
|
||||
}
|
||||
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 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
|
||||
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);
|
||||
}
|
||||
void arm_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 arm_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 arm_clflush(x64emu_t* emu, void* p)
|
||||
{
|
||||
cleanDBFromAddressRange((uintptr_t)p, 8, 0);
|
||||
}
|
||||
|
||||
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
@@ -386,7 +58,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
|
||||
@@ -434,7 +106,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...
|
||||
@@ -448,7 +121,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...
|
||||
@@ -466,6 +140,17 @@ int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int 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)
|
||||
@@ -474,6 +159,14 @@ int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int 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)
|
||||
@@ -482,6 +175,14 @@ int neoncache_get_current_st_f(dynarec_arm_t* dyn, int 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)
|
||||
@@ -491,7 +192,7 @@ static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
} 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;
|
||||
@@ -510,7 +211,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;
|
||||
@@ -545,7 +246,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;
|
||||
@@ -566,7 +267,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;
|
||||
@@ -599,31 +300,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;
|
||||
}
|
||||
@@ -631,7 +324,7 @@ int isCacheEmpty(dynarec_arm_t* dyn, int ninst) {
|
||||
|
||||
}
|
||||
|
||||
static int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(i2<0)
|
||||
return 1;
|
||||
@@ -646,7 +339,9 @@ static 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;
|
||||
}
|
||||
@@ -678,48 +373,6 @@ static int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flagsCacheNeedsTransform(dynarec_arm_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->f.pending!=SF_SET)
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) {
|
||||
if(dyn->f.pending!=SF_PENDING) {*/
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
case SF_SET:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET && dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int ret = 0;
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=1;
|
||||
if (flagsCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neoncacheUnwind(neoncache_t* cache)
|
||||
{
|
||||
if(cache->swapped) {
|
||||
@@ -727,7 +380,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
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)
|
||||
@@ -751,7 +404,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
|
||||
@@ -796,6 +449,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;
|
||||
@@ -813,7 +467,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)
|
||||
@@ -853,64 +506,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)
|
||||
{
|
||||
@@ -918,6 +515,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;
|
||||
@@ -927,20 +525,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));
|
||||
}
|
||||
@@ -1,46 +1,7 @@
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
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_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
void arm_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
|
||||
void arm_clflush(x64emu_t* emu, void* p);
|
||||
|
||||
void arm_ud(x64emu_t* emu);
|
||||
void arm_priv(x64emu_t* emu);
|
||||
#include "../dynarec_native_functions.h"
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn);
|
||||
@@ -60,38 +21,32 @@ 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*
|
||||
|
||||
// FPU Cache transformation (for loops)
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
// FPU Cache transformation (for loops) // Specific, need to be written par 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__
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../dynablock_private.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
@@ -26,12 +25,19 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, int* l, int s);
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int *l, int s, int delta)
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, rex_t rex, int *l, int s, int delta)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
|
||||
|
||||
if(rex.is32bits)
|
||||
return geted_32(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, l, s);
|
||||
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(unscaled)
|
||||
*unscaled = 0;
|
||||
if(lock==2)
|
||||
*l = 0;
|
||||
uint8_t ret = x2;
|
||||
@@ -49,11 +55,16 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if((sib&0x7)==5) {
|
||||
int64_t tmp = F32S;
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && ((tmp<absmin) || (tmp>absmax) || (tmp&mask))) {
|
||||
if(tmp && (!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256))) {
|
||||
MOV64x(scratch, tmp);
|
||||
ADDx_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
LSLx(ret, xRAX+sib_reg, (sib>>6));
|
||||
if(sib>>6) {
|
||||
LSLx(ret, xRAX+sib_reg, (sib>>6));
|
||||
} else
|
||||
ret = xRAX+sib_reg;
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
*fixaddress = tmp;
|
||||
}
|
||||
} else {
|
||||
@@ -71,14 +82,22 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
int64_t tmp = F32S64;
|
||||
if((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask)) {
|
||||
GETIP(addr+delta);
|
||||
ret = xRIP;
|
||||
*fixaddress = tmp;
|
||||
} else if(tmp<0x1000) {
|
||||
} else if(unscaled && (tmp>-256) && (tmp<256)) {
|
||||
GETIP(addr+delta);
|
||||
ret = xRIP;
|
||||
*fixaddress = tmp;
|
||||
*unscaled = 1;
|
||||
} else if(tmp>0 && tmp<0x1000) {
|
||||
GETIP(addr+delta);
|
||||
ADDx_U12(ret, xRIP, tmp);
|
||||
} else if(tmp<0 && tmp>-0x1000) {
|
||||
GETIP(addr+delta);
|
||||
SUBx_U12(ret, xRIP, -tmp);
|
||||
} else if(tmp+addr+delta<0x1000000000000LL) { // 3 opcodes to load immediate is cheap enough
|
||||
MOV64x(ret, tmp+addr+delta);
|
||||
} else {
|
||||
@@ -103,10 +122,12 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
if(nextop&0x80)
|
||||
i64 = F32S;
|
||||
else
|
||||
else
|
||||
i64 = F8S;
|
||||
if(i64==0 || ((i64>=absmin) && (i64<=absmax) && !(i64&mask))) {
|
||||
if(i64==0 || ((i64>=absmin) && (i64<=absmax) && !(i64&mask)) || (unscaled && (i64>-256) && (i64<256))) {
|
||||
*fixaddress = i64;
|
||||
if(unscaled && (i64>-256) && (i64<256))
|
||||
*unscaled = 1;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(ret, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
@@ -165,12 +186,149 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
return addr;
|
||||
}
|
||||
|
||||
static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, int* l, int s)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(unscaled)
|
||||
*unscaled = 0;
|
||||
if(lock==2)
|
||||
*l = 0;
|
||||
uint8_t ret = x2;
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
if(hint>0) ret = hint;
|
||||
if(hint>0 && hint<xRAX) scratch = hint;
|
||||
int absmin = 0;
|
||||
if(s) absmin=-absmax;
|
||||
MAYUSE(scratch);
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
int64_t tmp = F32S;
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && (!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256))) {
|
||||
MOV32w(scratch, tmp);
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
LSLw(ret, xRAX+sib_reg, (sib>>6));
|
||||
*fixaddress = tmp;
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
}
|
||||
} else {
|
||||
switch(lock) {
|
||||
case 1: addLockAddress((int32_t)tmp); break;
|
||||
case 2: if(isLockAddress((int32_t)tmp)) *l=1; break;
|
||||
}
|
||||
MOV32w(ret, tmp);
|
||||
}
|
||||
} else {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x7), xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x7);
|
||||
}
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32;
|
||||
MOV32w(ret, tmp);
|
||||
switch(lock) {
|
||||
case 1: addLockAddress(tmp); break;
|
||||
case 2: if(isLockAddress(tmp)) *l=1; break;
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&7);
|
||||
if(ret==hint) {
|
||||
MOVw_REG(hint, ret); //to clear upper part
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int64_t i32;
|
||||
uint8_t sib = 0;
|
||||
int sib_reg = 0;
|
||||
if((nextop&7)==4) {
|
||||
sib = F8;
|
||||
sib_reg = (sib>>3)&7;
|
||||
}
|
||||
if(nextop&0x80)
|
||||
i32 = F32S;
|
||||
else
|
||||
i32 = F8S;
|
||||
if(i32==0 || ((i32>=absmin) && (i32<=absmax) && !(i32&mask)) || (unscaled && (i32>-256) && (i32<256))) {
|
||||
*fixaddress = i32;
|
||||
if(unscaled && (i32>-256) && (i32<256))
|
||||
*unscaled = 1;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x07), xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x07);
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&0x07);
|
||||
}
|
||||
} else {
|
||||
int64_t sub = (i32<0)?1:0;
|
||||
if(sub) i32 = -i32;
|
||||
if(i32<0x1000) {
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(scratch, xRAX+(sib&0x07), xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
scratch = xRAX+(sib&0x07);
|
||||
}
|
||||
} else
|
||||
scratch = xRAX+(nextop&0x07);
|
||||
if(sub) {
|
||||
SUBw_U12(ret, scratch, i32);
|
||||
} else {
|
||||
ADDw_U12(ret, scratch, i32);
|
||||
}
|
||||
} else {
|
||||
MOV32w(scratch, i32);
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
if(sub) {
|
||||
SUBw_REG(scratch, xRAX+(sib&0x07), scratch);
|
||||
} else {
|
||||
ADDw_REG(scratch, scratch, xRAX+(sib&0x07));
|
||||
}
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(sib&0x07));
|
||||
if(sub) {
|
||||
SUBw_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
ADDw_REG(ret, tmp, scratch);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(nextop&0x07));
|
||||
if(sub) {
|
||||
SUBw_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
ADDw_REG(ret, tmp, scratch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*ed = ret;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta)
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
|
||||
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(unscaled)
|
||||
*unscaled = 0;
|
||||
if(lock==2)
|
||||
*l = 0;
|
||||
uint8_t ret = x2;
|
||||
@@ -188,12 +346,14 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if((sib&0x7)==5) {
|
||||
int64_t tmp = F32S;
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && ((tmp<absmin) || (tmp>absmax) || (tmp&mask))) {
|
||||
if(tmp && (!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256))) {
|
||||
MOV64x(scratch, tmp);
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
LSLw(ret, xRAX+sib_reg, (sib>>6));
|
||||
*fixaddress = tmp;
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
}
|
||||
} else {
|
||||
switch(lock) {
|
||||
@@ -234,10 +394,12 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
}
|
||||
if(nextop&0x80)
|
||||
i64 = F32S;
|
||||
else
|
||||
else
|
||||
i64 = F8S;
|
||||
if(i64==0 || ((i64>=absmin) && (i64<=absmax) && !(i64&mask))) {
|
||||
if(i64==0 || ((i64>=absmin) && (i64<=absmax) && !(i64&mask)) || (unscaled && (i64>-256) && (i64<256))) {
|
||||
*fixaddress = i64;
|
||||
if(unscaled && (i64>-256) && (i64<256))
|
||||
*unscaled = 1;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
@@ -298,10 +460,12 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, r3 as scratch also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, int s)
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, int s)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
|
||||
if(unscaled)
|
||||
*unscaled = 0;
|
||||
uint8_t ret = x2;
|
||||
uint8_t scratch = x3;
|
||||
*fixaddress = 0;
|
||||
@@ -322,7 +486,11 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
case 1: offset = F8S; break;
|
||||
case 2: offset = F16S; break;
|
||||
}
|
||||
if(offset && (offset>absmax || offset<absmin || (offset&mask))) {
|
||||
if(offset && (offset>=absmax && offset<=absmin && !(offset&mask))) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
if(offset && (unscaled && offset>-256 && offset<256)) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
@@ -376,6 +544,16 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void exit_block(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
ADR_S20(x5, (intptr_t)dyn->enter - (uintptr_t)dyn->block);
|
||||
LDAXRw(x4, x5);
|
||||
SUBw_U12(x4, x4, 1);
|
||||
STLXRw(x3, x4, x5);
|
||||
CBNZw(x3, 4-4*4);
|
||||
}
|
||||
#define EXIT_SIZE (4*5)
|
||||
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ip); MAYUSE(ninst);
|
||||
@@ -388,8 +566,11 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
} else {
|
||||
GETIP_(ip);
|
||||
}
|
||||
NOTEST(x2);
|
||||
TABLE64(x2, (uintptr_t)arm64_epilog);
|
||||
SMEND();
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -402,6 +583,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
if(reg!=xRIP) {
|
||||
MOVx_REG(xRIP, reg);
|
||||
}
|
||||
NOTEST(x2);
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
TABLE64(x3, tbl);
|
||||
@@ -414,6 +596,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x3, x2);
|
||||
} else {
|
||||
NOTEST(x2);
|
||||
uintptr_t p = getJumpTableAddress64(ip);
|
||||
MAYUSE(p);
|
||||
TABLE64(x3, p);
|
||||
@@ -425,30 +608,35 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
}
|
||||
CLEARIP();
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
#endif
|
||||
SMEND();
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BLR(x2); // save LR...
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Ret to epilog\n");
|
||||
POP1(xRIP);
|
||||
MOVx_REG(x1, xRIP);
|
||||
POP1z(xRIP);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_offset(x2, x6, xSP, 0);
|
||||
CBZx(x6, 5*4);
|
||||
CBZx(x6, 5*4+(box64_dynarec_age?EXIT_SIZE:0));
|
||||
ADDx_U12(xSP, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
CBNZx(x6, 2*4+(box64_dynarec_age?EXIT_SIZE:0));
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BLR(x2);
|
||||
// not the correct return address, regular jump
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
NOTEST(x2);
|
||||
MOV64x(x2, tbl);
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
@@ -458,34 +646,39 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BLR(x2); // save LR
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Retn to epilog\n");
|
||||
POP1(xRIP);
|
||||
POP1z(xRIP);
|
||||
if(n>0xfff) {
|
||||
MOV32w(w1, n);
|
||||
ADDx_REG(xRSP, xRSP, x1);
|
||||
ADDz_REG(xRSP, xRSP, x1);
|
||||
} else {
|
||||
ADDx_U12(xRSP, xRSP, n);
|
||||
ADDz_U12(xRSP, xRSP, n);
|
||||
}
|
||||
MOVx_REG(x1, xRIP);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_offset(x2, x6, xSP, 0);
|
||||
CBZx(x6, 5*4);
|
||||
CBZx(x6, 5*4+(box64_dynarec_age?EXIT_SIZE:0));
|
||||
ADDx_U12(xSP, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
CBNZx(x6, 2*4+(box64_dynarec_age?EXIT_SIZE:0));
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BLR(x2);
|
||||
// not the correct return address, regular jump
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
NOTEST(x2);
|
||||
MOV64x(x2, tbl);
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
@@ -495,6 +688,8 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BLR(x2); // save LR
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -505,29 +700,42 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "IRet to epilog\n");
|
||||
// POP IP
|
||||
POP1(xRIP);
|
||||
// POP CS
|
||||
POP1(x2);
|
||||
NOTEST(x2);
|
||||
if(is64bits) {
|
||||
POP1(xRIP);
|
||||
POP1(x2);
|
||||
POP1(xFlags);
|
||||
} else {
|
||||
POP1_32(xRIP);
|
||||
POP1_32(x2);
|
||||
POP1_32(xFlags);
|
||||
}
|
||||
// x2 is CS
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
MOVZw(x1, 0);
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
|
||||
// POP EFLAGS
|
||||
POP1(xFlags);
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
|
||||
// clean EFLAGS
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
ANDx_REG(xFlags, xFlags, x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); // xFlags | 0b10
|
||||
SET_DFNONE(x1);
|
||||
// POP RSP
|
||||
POP1(x3);
|
||||
if(is64bits) {
|
||||
POP1(x3); //rsp
|
||||
POP1(x2); //ss
|
||||
} else {
|
||||
POP1_32(x3); //rsp
|
||||
POP1_32(x2); //ss
|
||||
}
|
||||
// POP SS
|
||||
POP1(x2);
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
|
||||
// set new RSP
|
||||
MOVx_REG(xRSP, x3);
|
||||
// Ret....
|
||||
MOV64x(x2, (uintptr_t)arm64_epilog); // epilog on purpose, CS might have changed!
|
||||
SMEND();
|
||||
if(box64_dynarec_age)
|
||||
exit_block(dyn, ninst);
|
||||
BR(x2);
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -662,7 +870,9 @@ static void x87_reset(dynarec_arm_t* dyn)
|
||||
dyn->n.swapped = 0;
|
||||
dyn->n.barrier = 0;
|
||||
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)
|
||||
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_I64)
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
@@ -723,7 +933,9 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
dyn->n.stack_push+=1;
|
||||
// move all regs in cache, and find a free one
|
||||
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].t == NEON_CACHE_ST_D)
|
||||
||(dyn->n.neoncache[j].t == NEON_CACHE_ST_F)
|
||||
||(dyn->n.neoncache[j].t == NEON_CACHE_ST_I64))
|
||||
++dyn->n.neoncache[j].n;
|
||||
int ret = -1;
|
||||
for(int i=0; i<8; ++i)
|
||||
@@ -732,13 +944,7 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
else if(ret==-1) {
|
||||
dyn->n.x87cache[i] = 0;
|
||||
ret=dyn->n.x87reg[i]=fpu_get_reg_x87(dyn, t, 0);
|
||||
#if STEP == 1
|
||||
// need to check if reg is compatible with float
|
||||
if((ret>15) && (t == NEON_CACHE_ST_F))
|
||||
dyn->n.neoncache[ret].t = NEON_CACHE_ST_D;
|
||||
#else
|
||||
dyn->n.neoncache[ret].t = X87_ST0;
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -752,7 +958,9 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
dyn->n.stack_push+=1;
|
||||
// move all regs in cache
|
||||
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].t == NEON_CACHE_ST_D)
|
||||
||(dyn->n.neoncache[j].t == NEON_CACHE_ST_F)
|
||||
||(dyn->n.neoncache[j].t == NEON_CACHE_ST_I64))
|
||||
++dyn->n.neoncache[j].n;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1)
|
||||
@@ -874,10 +1082,29 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
MESSAGE(LOG_DUMP, "\t---Purge x87 Cache and Synch Stackcount\n");
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
// Synch top & stack counter
|
||||
int a = dyn->n.x87stack;
|
||||
if(a) {
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADDw_U12(s2, s2, a);
|
||||
} else {
|
||||
SUBw_U12(s2, s2, -a);
|
||||
}
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
if(a>0) {
|
||||
SUBw_U12(s2, s2, a);
|
||||
} else {
|
||||
ADDw_U12(s2, s2, -a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
}
|
||||
int ret = 0;
|
||||
for (int i=0; (i<8) && (!ret); ++i)
|
||||
if(dyn->n.x87cache[i] != -1)
|
||||
@@ -887,7 +1114,9 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
if(!a) {
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
}
|
||||
// loop all cache entries
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
@@ -896,7 +1125,31 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[i], s1, s3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void x87_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
// go back with the top & stack counter
|
||||
int a = dyn->n.x87stack;
|
||||
if(a) {
|
||||
// Sub x87stack to emu fpu_stack
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
SUBw_U12(s2, s2, a);
|
||||
} else {
|
||||
ADDw_U12(s2, s2, -a);
|
||||
}
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Add x87stack to top, with and 7
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
if(a>0) {
|
||||
ADDw_U12(s2, s2, a);
|
||||
} else {
|
||||
SUBw_U12(s2, s2, -a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
}
|
||||
}
|
||||
|
||||
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
|
||||
{
|
||||
@@ -904,7 +1157,9 @@ int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
|
||||
for (int i=0; i<8; ++i) {
|
||||
if(dyn->n.x87cache[i]==st) {
|
||||
#if STEP == 1
|
||||
if(t==NEON_CACHE_ST_D && (dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_F))
|
||||
if(t==NEON_CACHE_ST_D && (dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_F || dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_I64))
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
else if(t==NEON_CACHE_ST_F && (dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_I64))
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
return i;
|
||||
@@ -950,7 +1205,9 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
|
||||
int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
for(int ii=0; ii<24; ++ii)
|
||||
if((dyn->n.neoncache[ii].t == NEON_CACHE_ST_F || dyn->n.neoncache[ii].t == NEON_CACHE_ST_D)
|
||||
if((dyn->n.neoncache[ii].t == NEON_CACHE_ST_F
|
||||
|| dyn->n.neoncache[ii].t == NEON_CACHE_ST_D
|
||||
|| dyn->n.neoncache[ii].t == NEON_CACHE_ST_I64)
|
||||
&& dyn->n.neoncache[ii].n==st)
|
||||
return ii;
|
||||
assert(0);
|
||||
@@ -988,6 +1245,9 @@ void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(31, dyn->n.x87reg[ret]);
|
||||
VSTR64_REG_LSL3(31, s1, s2);
|
||||
} else if(dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_I64) {
|
||||
SCVTFDD(31, dyn->n.x87reg[ret]);
|
||||
VSTR64_REG_LSL3(31, s1, s2);
|
||||
} else {
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[ret], s1, s2);
|
||||
}
|
||||
@@ -1005,7 +1265,7 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tForget x87 Cache for ST%d\n", st);
|
||||
#if STEP == 1
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_F)
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_F || dyn->n.neoncache[dyn->n.x87reg[ret]].t==NEON_CACHE_ST_I64)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
// prepare offset to fpu => s1
|
||||
@@ -1036,7 +1296,7 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
// refresh the value
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
#if STEP == 1
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_F)
|
||||
if(dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_F || dyn->n.neoncache[dyn->n.x87reg[i]].t==NEON_CACHE_ST_I64)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
@@ -1197,7 +1457,7 @@ void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge MMX Cache\n");
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
|
||||
static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
@@ -1205,7 +1465,6 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
VLDR64_U12(dyn->n.mmxcache[i], xEmu, offsetof(x64emu_t, mmx[i]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// SSE / SSE2 helpers
|
||||
@@ -1297,7 +1556,7 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge SSE Cache\n");
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
|
||||
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
for (int i=0; i<16; ++i)
|
||||
@@ -1305,7 +1564,6 @@ static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
{
|
||||
@@ -1364,10 +1622,20 @@ static int findCacheSlot(dynarec_arm_t* dyn, int ninst, int t, int n, neoncache_
|
||||
case NEON_CACHE_ST_F:
|
||||
if (t==NEON_CACHE_ST_D)
|
||||
return i;
|
||||
if (t==NEON_CACHE_ST_I64)
|
||||
return i;
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
if (t==NEON_CACHE_ST_F)
|
||||
return i;
|
||||
if (t==NEON_CACHE_ST_I64)
|
||||
return i;
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
if (t==NEON_CACHE_ST_F)
|
||||
return i;
|
||||
if (t==NEON_CACHE_ST_D)
|
||||
return i;
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
if(t==NEON_CACHE_XMMW)
|
||||
@@ -1392,7 +1660,7 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
quad =1;
|
||||
if(cache->neoncache[j].t==NEON_CACHE_XMMR || cache->neoncache[j].t==NEON_CACHE_XMMW)
|
||||
quad =1;
|
||||
|
||||
|
||||
if(!cache->neoncache[i].v) {
|
||||
// a mov is enough, no need to swap
|
||||
MESSAGE(LOG_DUMP, "\t - Moving %d <- %d\n", i, j);
|
||||
@@ -1407,7 +1675,7 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
}
|
||||
// SWAP
|
||||
neon_cache_t tmp;
|
||||
MESSAGE(LOG_DUMP, "\t - Swaping %d <-> %d\n", i, j);
|
||||
MESSAGE(LOG_DUMP, "\t - Swapping %d <-> %d\n", i, j);
|
||||
// There is no VSWP in Arm64 NEON to swap 2 register contents!
|
||||
// so use a scratch...
|
||||
#define SCRATCH 31
|
||||
@@ -1452,12 +1720,13 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
VLDR64_U12(i, xEmu, offsetof(x64emu_t, mmx[i]));
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
case NEON_CACHE_ST_F:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
case NEON_CACHE_ST_I64:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
if((*s3_top) == 0xffff) {
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, top));
|
||||
*s3_top = 0;
|
||||
@@ -1478,12 +1747,15 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
if(t==NEON_CACHE_ST_F) {
|
||||
FCVT_S_D(i, i);
|
||||
}
|
||||
break;
|
||||
if(t==NEON_CACHE_ST_I64) {
|
||||
VFCVTZSQD(i, i);
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_NONE:
|
||||
case NEON_CACHE_SCR:
|
||||
default: /* nothing done */
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring %s\n", getCacheName(t, n));
|
||||
break;
|
||||
break;
|
||||
}
|
||||
cache->neoncache[i].n = n;
|
||||
cache->neoncache[i].t = t;
|
||||
@@ -1500,12 +1772,13 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR64_U12(i, xEmu, offsetof(x64emu_t, mmx[n]));
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
case NEON_CACHE_ST_F:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
case NEON_CACHE_ST_I64:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
if((*s3_top)==0xffff) {
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, top));
|
||||
*s3_top = 0;
|
||||
@@ -1524,14 +1797,16 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
*s2_val = 0;
|
||||
if(t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(i, i);
|
||||
} else if (t==NEON_CACHE_ST_I64) {
|
||||
SCVTFDD(i, i);
|
||||
}
|
||||
VSTR64_U12(i, s2, offsetof(x64emu_t, x87));
|
||||
break;
|
||||
break;
|
||||
case NEON_CACHE_NONE:
|
||||
case NEON_CACHE_SCR:
|
||||
default: /* nothing done */
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring %s\n", getCacheName(t, n));
|
||||
break;
|
||||
break;
|
||||
}
|
||||
cache->neoncache[i].v = 0;
|
||||
}
|
||||
@@ -1653,6 +1928,23 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
FCVT_D_S(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_D && cache_i2.neoncache[i].t == NEON_CACHE_ST_I64) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
VFCVTZSQD(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_I64;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_F && cache_i2.neoncache[i].t == NEON_CACHE_ST_I64) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
VFCVTZSQS(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_I64 && cache_i2.neoncache[i].t == NEON_CACHE_ST_F) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
SCVTFDD(i, i);
|
||||
FCVT_S_D(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_F;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_I64 && cache_i2.neoncache[i].t == NEON_CACHE_ST_D) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
SCVTFDD(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{ cache.neoncache[i].t = NEON_CACHE_XMMW; }
|
||||
else if(cache.neoncache[i].t == NEON_CACHE_XMMW && cache_i2.neoncache[i].t == NEON_CACHE_XMMR) {
|
||||
@@ -1680,18 +1972,18 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
int go = 0;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: break;
|
||||
case SF_SET:
|
||||
if(dyn->f.pending!=SF_SET && dyn->f.pending!=SF_SET_PENDING)
|
||||
go = 1;
|
||||
case SF_SET:
|
||||
if(dyn->f.pending!=SF_SET && dyn->f.pending!=SF_SET_PENDING)
|
||||
go = 1;
|
||||
break;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
break;
|
||||
case SF_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
@@ -1704,32 +1996,34 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
if(go) {
|
||||
if(dyn->f.pending!=SF_PENDING) {
|
||||
LDRw_U12(s1, xEmu, offsetof(x64emu_t, df));
|
||||
j64 = (GETMARK3)-(dyn->native_size);
|
||||
j64 = (GETMARKF2)-(dyn->native_size);
|
||||
CBZw(s1, j64);
|
||||
}
|
||||
CALL_(UpdateFlags, -1, 0);
|
||||
MARK3;
|
||||
MARKF2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3) {
|
||||
if(cacheupd&1)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
if(cacheupd&2)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
if(cacheupd&1)
|
||||
flagsCacheTransform(dyn, ninst, s1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_reflectcache(dyn, ninst, s1, s2, s3);
|
||||
if(trace_emm)
|
||||
mmx_reflectcache(dyn, ninst, s1);
|
||||
if(trace_xmm)
|
||||
sse_reflectcache(dyn, ninst, s1);
|
||||
mmx_reflectcache(dyn, ninst, s1);
|
||||
sse_reflectcache(dyn, ninst, s1);
|
||||
}
|
||||
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
// need to undo some things on the x87 tracking
|
||||
x87_unreflectcache(dyn, ninst, s1, s2, s3);
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
@@ -1753,3 +2047,67 @@ void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
MVNw_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
|
||||
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
// propagate ST stack state, especial stack pop that are deferred
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
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
|
||||
|| dyn->n.neoncache[j].t == NEON_CACHE_ST_I64)) {
|
||||
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;
|
||||
}
|
||||
@@ -67,8 +67,8 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD() \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(x1, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDxw(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDx(D) if(MODREG) { \
|
||||
@@ -76,8 +76,17 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
LDRx_U12(x1, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
LDx(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDz(D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
LDz(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDw(D) if((nextop&0xC0)==0xC0) { \
|
||||
@@ -85,8 +94,8 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL,0, D); \
|
||||
LDRw_U12(x1, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL,0, D); \
|
||||
LDW(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETSEDw(D) if((nextop&0xC0)==0xC0) { \
|
||||
@@ -96,8 +105,8 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
LDRSW_U12(x1, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
LDSW(x1, wback, fixedaddress); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
#define GETED32(D) if(MODREG) { \
|
||||
@@ -105,8 +114,8 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(x1, wback, fixedaddress); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDxw(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETSED32w(D) if((nextop&0xC0)==0xC0) { \
|
||||
@@ -116,8 +125,8 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
LDRSW_U12(x1, wback, fixedaddress); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
LDSW(x1, wback, fixedaddress); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
//GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI
|
||||
@@ -126,18 +135,18 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDxw(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
#define GETED32H(hint, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDRxw_U12(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
LDxw(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
//GETEDW can use hint for wback and ret for ed. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDW(hint, ret, D) if(MODREG) { \
|
||||
@@ -146,9 +155,9 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
ed = ret; \
|
||||
LDRxw_U12(ed, wback, fixedaddress); \
|
||||
LDxw(ed, wback, fixedaddress); \
|
||||
}
|
||||
#define GETED32W(hint, ret, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
@@ -156,23 +165,23 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, D); \
|
||||
ed = ret; \
|
||||
LDRxw_U12(ed, wback, fixedaddress); \
|
||||
LDxw(ed, wback, fixedaddress); \
|
||||
}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACK if(wback) {STRxw_U12(ed, wback, fixedaddress); SMWRITE();}
|
||||
#define WBACK if(wback) {STxw(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKx if(wback) {STRx_U12(ed, wback, fixedaddress); SMWRITE();}
|
||||
#define WBACKx if(wback) {STx(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKw if(wback) {STRw_U12(ed, wback, fixedaddress); SMWRITE();}
|
||||
#define WBACKw if(wback) {STW(ed, wback, fixedaddress); SMWRITE();}
|
||||
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDO(O, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
LDRxw_REG(x1, wback, O); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -183,10 +192,20 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
LDRx_REG(x1, wback, O); \
|
||||
ed = x1; \
|
||||
}
|
||||
//GETEDOz can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDOz(O, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
LDRz_REG(x1, wback, O); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETSEDOw(O, D) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
SXTWx(x1, ed); \
|
||||
@@ -194,7 +213,7 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
LDRSW_REG(x1, wback, O); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
@@ -214,8 +233,8 @@
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDRH_U12(i, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDH(i, wback, fixedaddress);\
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
@@ -227,8 +246,8 @@
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDRH_U12(i, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDH(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
@@ -240,15 +259,15 @@
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDRSHx_U12(i, wback, fixedaddress);\
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
LDSHw(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
// Write ed back to original register / memory
|
||||
#define EWBACK if(wb1) {STRH_U12(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, 0, 16);}
|
||||
#define EWBACK EWBACKW(ed)
|
||||
// Write w back to original register / memory
|
||||
#define EWBACKW(w) if(wb1) {STRH_U12(w, wback, fixedaddress); SMWRITE();} else {BFIx(wback, w, 0, 16);}
|
||||
#define EWBACKW(w) if(wb1) {STH(w, wback, fixedaddress); SMWRITE();} else {BFIx(wback, w, 0, 16);}
|
||||
// Write back gd in correct register
|
||||
#define GWBACK BFIx((xRAX+((nextop&0x38)>>3)+(rex.r<<3)), gd, 0, 16);
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
@@ -266,8 +285,8 @@
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDB(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
@@ -286,10 +305,10 @@
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
|
||||
ADDx_REG(x3, wback, i); \
|
||||
if(wback!=x3) wback = x3; \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
LDB(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
@@ -308,8 +327,8 @@
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDRSBx_U12(i, wback, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDSBx(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
@@ -328,13 +347,13 @@
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDB(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STRB_U12(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
|
||||
#define EBBACK if(wb1) {STB(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
|
||||
//GETGB will use i for gd
|
||||
#define GETGB(i) if(rex.rex) { \
|
||||
gb1 = xRAX+((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
@@ -379,15 +398,15 @@
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
VLD128(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Put Back EX if it was a memory and not an emm register
|
||||
#define PUTEX(a) \
|
||||
if(!MODREG) { \
|
||||
VSTR128_U12(a, ed, fixedaddress); \
|
||||
VST128(a, ed, fixedaddress); \
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
@@ -399,8 +418,8 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
VLD64(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Get Ex as a single, not a quad (warning, x1 get used)
|
||||
@@ -410,8 +429,8 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
VLDR32_U12(a, ed, fixedaddress); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
VLD32(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Get GM, might use x1, x2 and x3
|
||||
@@ -425,15 +444,15 @@
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7)); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
VLD64(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
// Put Back EM if it was a memory and not an emm register
|
||||
#define PUTEM(a) \
|
||||
if(!MODREG) { \
|
||||
VSTR64_U12(a, ed, fixedaddress); \
|
||||
VST64(a, ed, fixedaddress); \
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
@@ -455,17 +474,19 @@
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x7, ret, 0, 0)
|
||||
|
||||
#define MARK dyn->insts[ninst].mark = dyn->native_size
|
||||
#define GETMARK dyn->insts[ninst].mark
|
||||
#define MARK2 dyn->insts[ninst].mark2 = dyn->native_size
|
||||
#define GETMARK2 dyn->insts[ninst].mark2
|
||||
#define MARK3 dyn->insts[ninst].mark3 = dyn->native_size
|
||||
#define GETMARK3 dyn->insts[ninst].mark3
|
||||
#define MARKF dyn->insts[ninst].markf = dyn->native_size
|
||||
#define GETMARKF dyn->insts[ninst].markf
|
||||
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
|
||||
#define GETMARKSEG dyn->insts[ninst].markseg
|
||||
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
|
||||
#define MARK dyn->insts[ninst].mark = dyn->native_size
|
||||
#define GETMARK dyn->insts[ninst].mark
|
||||
#define MARK2 dyn->insts[ninst].mark2 = dyn->native_size
|
||||
#define GETMARK2 dyn->insts[ninst].mark2
|
||||
#define MARK3 dyn->insts[ninst].mark3 = dyn->native_size
|
||||
#define GETMARK3 dyn->insts[ninst].mark3
|
||||
#define MARKF dyn->insts[ninst].markf = dyn->native_size
|
||||
#define GETMARKF dyn->insts[ninst].markf
|
||||
#define MARKF2 dyn->insts[ninst].markf2 = dyn->native_size
|
||||
#define GETMARKF2 dyn->insts[ninst].markf2
|
||||
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
|
||||
#define GETMARKSEG dyn->insts[ninst].markseg
|
||||
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
|
||||
#define GETMARKLOCK dyn->insts[ninst].marklock
|
||||
|
||||
// Branch to MARK if cond (use j64)
|
||||
@@ -504,6 +525,10 @@
|
||||
#define B_MARK2_nocond \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
B(j64)
|
||||
// Branch to MARK2 if reg is 0 (use j64)
|
||||
#define CBZx_MARK2(reg) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
CBZx(reg, j64)
|
||||
// Branch to MARK2 if reg is not 0 (use j64)
|
||||
#define CBNZx_MARK2(reg) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
@@ -717,7 +742,7 @@
|
||||
LDP_REGS(R12, R13); \
|
||||
LDP_REGS(R14, R15)
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->f.dfnone) {MOVZw(S, d_none); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=1;}
|
||||
#define SET_DFNONE(S) if(!dyn->f.dfnone) {STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=1;}
|
||||
#define SET_DF(S, N) if((N)!=d_none) {MOVZw(S, (N)); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
@@ -759,17 +784,17 @@
|
||||
} else dyn->f.pending = SF_SET
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A, C)
|
||||
#define JUMP(A, C)
|
||||
#endif
|
||||
#ifndef BARRIER
|
||||
#define BARRIER(A)
|
||||
#define BARRIER(A)
|
||||
#endif
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.gen_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.gen_flags)
|
||||
@@ -786,6 +811,10 @@
|
||||
#define FTABLE64(A, V)
|
||||
#endif
|
||||
|
||||
#define ARCH_INIT() \
|
||||
dyn->doublepush = 0; \
|
||||
dyn->doublepop = 0;
|
||||
|
||||
#if STEP < 2
|
||||
#define GETIP(A)
|
||||
#define GETIP_(A)
|
||||
@@ -828,7 +857,7 @@
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
void arm64_epilog();
|
||||
void arm64_epilog(void);
|
||||
void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
@@ -969,30 +998,31 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_reset_cache STEPNAME(fpu_reset_cache)
|
||||
#define fpu_propagate_stack STEPNAME(fpu_propagate_stack)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, int s);
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, int s);
|
||||
|
||||
|
||||
// generic x64 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
|
||||
@@ -1116,16 +1146,19 @@ int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
|
||||
#if STEP == 0
|
||||
#define ST_IS_F(A) 0
|
||||
#define ST_IS_I64(A) 0
|
||||
#define X87_COMBINE(A, B) NEON_CACHE_ST_D
|
||||
#define X87_ST0 NEON_CACHE_ST_D
|
||||
#define X87_ST(A) NEON_CACHE_ST_D
|
||||
#elif STEP == 1
|
||||
#define ST_IS_F(A) (neoncache_get_current_st(dyn, ninst, A)==NEON_CACHE_ST_F)
|
||||
#define ST_IS_I64(A) (neoncache_get_current_st(dyn, ninst, A)==NEON_CACHE_ST_I64)
|
||||
#define X87_COMBINE(A, B) neoncache_combine_st(dyn, ninst, A, B)
|
||||
#define X87_ST0 neoncache_get_current_st(dyn, ninst, 0)
|
||||
#define X87_ST(A) neoncache_get_current_st(dyn, ninst, A)
|
||||
#else
|
||||
#define ST_IS_F(A) (neoncache_get_st(dyn, ninst, A)==NEON_CACHE_ST_F)
|
||||
#define ST_IS_I64(A) (neoncache_get_st(dyn, ninst, A)==NEON_CACHE_ST_I64)
|
||||
#if STEP == 3
|
||||
#define X87_COMBINE(A, B) neoncache_st_coherency(dyn, ninst, A, B)
|
||||
#else
|
||||
@@ -1154,15 +1187,18 @@ void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
// reset the cache with n
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n);
|
||||
// propagate stack state
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
// purge MMX cache
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
|
||||
// purge x87 cache
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07);
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07);
|
||||
|
||||
@@ -1202,7 +1238,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
#if STEP < 3
|
||||
#define MAYUSE(A) (void)A
|
||||
#else
|
||||
#define MAYUSE(A)
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#define GOCOND(B, T1, T2) \
|
||||
@@ -1295,4 +1331,27 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
, cNE, cEQ, X_SF|X_OF|X_ZF) \
|
||||
break
|
||||
|
||||
#define NOTEST(s1) \
|
||||
if(box64_dynarec_test) { \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.test)); \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.clean));\
|
||||
}
|
||||
#define SKIPTEST(s1) \
|
||||
if(box64_dynarec_test) { \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.clean));\
|
||||
}
|
||||
#define GOTEST(s1, s2) \
|
||||
if(box64_dynarec_test) { \
|
||||
MOV32w(s2, 1); \
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, test.test)); \
|
||||
}
|
||||
|
||||
#define GETREX() \
|
||||
rex.rex = 0; \
|
||||
if(!rex.is32bits) \
|
||||
while(opcode>=0x40 && opcode<=0x4f) { \
|
||||
rex.rex = opcode; \
|
||||
opcode = F8; \
|
||||
}
|
||||
|
||||
#endif //__DYNAREC_ARM64_HELPER_H__
|
||||
@@ -8,4 +8,17 @@ void CreateJmpNext(void* addr, void* next)
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
LDRx_literal(x2, (intptr_t)next - (intptr_t)addr);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
int CreateEnter(void* addr, void* enter)
|
||||
{
|
||||
if(enter) {
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
ADR_S20(x2, (intptr_t)enter - (intptr_t)addr);
|
||||
LDAXRw(x1, x2);
|
||||
ADDw_U12(x1, x1, 1);
|
||||
STLXRw(x3, x1, x2);
|
||||
CBNZw(x3, 4-4*4);
|
||||
}
|
||||
return 4*5;
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define ENTER()
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
@@ -22,7 +24,7 @@
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_native_t*)customRealloc(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; \
|
||||
} \
|
||||
@@ -40,9 +42,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), \
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define ENTER()
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define NEW_INST \
|
||||
|
||||
@@ -2,19 +2,17 @@
|
||||
#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)?dyn->insts[ninst].x64.size:dyn->insts[ninst].size)/15; \
|
||||
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 ENTER() dyn->block_prolog = CreateEnter(NULL, NULL)
|
||||
#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(isInstClean(dyn, ninst) && dyn->last_ip!=ip) \
|
||||
dyn->last_ip = 0; \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>dyn->insts[ninst-1].size)?dyn->insts[ninst-1].x64.size:dyn->insts[ninst-1].size)/15; \
|
||||
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);}
|
||||
@@ -3,68 +3,21 @@
|
||||
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) \
|
||||
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 ENTER() dyn->block += CreateEnter(dyn->block, dyn->enter)
|
||||
#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)) { \
|
||||
if(dyn->last_ip!=ip) dyn->last_ip = 0; \
|
||||
} \
|
||||
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), %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_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);}
|
||||
@@ -9,13 +9,14 @@ 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 {
|
||||
@@ -57,19 +58,19 @@ 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
|
||||
@@ -87,7 +88,8 @@ typedef struct dynarec_arm_s {
|
||||
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 block_prolog; // size in byte of block prolog (not part of 1st instruction)
|
||||
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
|
||||
@@ -95,6 +97,7 @@ typedef struct dynarec_arm_s {
|
||||
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
|
||||
@@ -110,6 +113,10 @@ typedef struct dynarec_arm_s {
|
||||
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;
|
||||
int* enter;
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
@@ -117,16 +124,17 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
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 etable64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
int CreateEnter(void* addr, void* enter);
|
||||
|
||||
#define GO_TRACE() \
|
||||
GETIP_(ip); \
|
||||
#define GO_TRACE(A, B) \
|
||||
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_
|
||||
+157
-47
@@ -1,6 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -9,7 +8,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"
|
||||
@@ -37,6 +35,39 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
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);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
// remove jumptable
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
@@ -50,6 +81,8 @@ void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
@@ -57,14 +90,65 @@ void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
}
|
||||
}
|
||||
|
||||
size_t AgeDynablock(dynablock_t* db, size_t age)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "AgeDynablock %p %p-%p, age=%zu, db:age/romove=%zu/%d\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, age, db->age, db->try_remove);
|
||||
if(db->age>age || !db->done || db->gone)
|
||||
return db->age;
|
||||
dynablock_t* actual = getDB((uintptr_t)db->x64_addr);
|
||||
if(actual != db) {
|
||||
printf_log(LOG_INFO, "Warning, AgeDynablock with a rogue db %p instead of %p for %p\n", db, actual, db->x64_addr);
|
||||
return age + box64_dynarec_age;
|
||||
}
|
||||
int need_test = getNeedTest((uintptr_t)db->x64_addr);
|
||||
if(db->try_remove) {
|
||||
if(need_test && !*db->active_count) {
|
||||
db = InvalidDynablock(db, 0);
|
||||
FreeInvalidDynablock(db, 0);
|
||||
return 0;
|
||||
} else {
|
||||
db->try_remove = 0;
|
||||
db->age = age + box64_dynarec_age; // re-arm the wait
|
||||
}
|
||||
} else {
|
||||
if(need_test || (getProtection((uintptr_t)db->x64_addr)&PROT_NOPROT) || db->always_test || !db->active_count || *db->active_count) {
|
||||
// don't mess with this kind of dynablock...
|
||||
db->age = age+box64_dynarec_age*2;
|
||||
} else if(setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) {
|
||||
dynarec_log(LOG_DEBUG, "Marking block %p at %p for later removal\n", db, db->x64_addr);
|
||||
db->age = age+box64_dynarec_age;
|
||||
db->try_remove = 1;
|
||||
} else {
|
||||
db->age = age+box64_dynarec_age*2; // failed to swap, try again later
|
||||
}
|
||||
}
|
||||
return db->age;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
db->need_test = 1;
|
||||
setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block);
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
db->try_remove = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +162,7 @@ static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->need_test)
|
||||
if(getNeedTest((uintptr_t)db->x64_addr))
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
@@ -90,9 +174,8 @@ void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
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(!MarkedDynablock(db))
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
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)
|
||||
@@ -133,18 +216,20 @@ void cancelFillBlock()
|
||||
{
|
||||
longjmp(&dynarec_jmpbuf, 1);
|
||||
}
|
||||
|
||||
extern size_t box64_counter;
|
||||
/*
|
||||
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, int need_lock)
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits)
|
||||
{
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
if(block || !create) {
|
||||
if(block) block->age = box64_counter+box64_dynarec_age;
|
||||
return block;
|
||||
}
|
||||
|
||||
if(need_lock) {
|
||||
if(box64_dynarec_wait) {
|
||||
@@ -153,13 +238,11 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
if(need_lock)
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
@@ -168,25 +251,27 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
block->x64_addr = (void*)addr;
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
FreeDynablock(block, 0);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock64(block, filladdr);
|
||||
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);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && (block->x64_size || (!block->x64_size && !block->done))) {
|
||||
if(block) {
|
||||
int blocksz = block->x64_size;
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// fill-in jumptable
|
||||
if(!addJumpTableIfDefault64(block->x64_addr, block->block)) {
|
||||
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
|
||||
@@ -200,15 +285,20 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create)
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) {
|
||||
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(!db->try_remove && 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
|
||||
if(hash==db->hash) { // seems ok, run it without reprotecting it
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
return db;
|
||||
}
|
||||
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!
|
||||
@@ -220,52 +310,72 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create)
|
||||
}
|
||||
}
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) {
|
||||
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
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!
|
||||
FreeDynablock(db, 0);
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, 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 {
|
||||
db->need_test = 0;
|
||||
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
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
} else
|
||||
db->try_remove = 0;
|
||||
}
|
||||
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, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
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!
|
||||
FreeDynablock(db, 0);
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, 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 {
|
||||
db->need_test = 0;
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(db->x64_addr, db->block);
|
||||
if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
} else
|
||||
db->try_remove = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -9,17 +9,21 @@ typedef struct instsize_s {
|
||||
typedef struct dynablock_s {
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
int size;
|
||||
struct dynablock_s* previous; // a previous block that might need to be freed
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
int size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
uint8_t always_test;
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
instsize_t* instsize;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
size_t age; //age of the block
|
||||
int try_remove; // block marked as try removed
|
||||
int isize;
|
||||
uint32_t* active_count; // is this block currently being executed, or NULL if not tracked
|
||||
} dynablock_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+62
-72
@@ -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"
|
||||
@@ -31,6 +29,7 @@ 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);
|
||||
@@ -38,27 +37,28 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
}
|
||||
#endif
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1);
|
||||
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);
|
||||
if(box64_log<LOG_DEBUG) dynarec_log(LOG_INFO, "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);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=box64_dynarec_log) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
//tableupdate(native_epilog, addr, table);
|
||||
return native_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
@@ -81,19 +81,21 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
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!
|
||||
}
|
||||
struct __jmp_buf_tag jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
struct __jmp_buf_tag *old_jmpbuf = emu->jmpbuf;
|
||||
emu->jmpbuf = jmpbuf;
|
||||
|
||||
if((skip = sigsetjmp(emu->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall, fs=0x%x\n", emu->segs[_FS]);
|
||||
addr = R_RIP; // not sure if it should still be inside DynaCall!
|
||||
#ifdef DYNAREC
|
||||
if(box64_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
x64test_check(emu, R_RIP);
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box64_dynarec)
|
||||
@@ -111,14 +113,18 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
while(!emu->quit) {
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1);
|
||||
int is32bits = (emu->segs[_CS]==0x23);
|
||||
dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
if(!block || !block->block || !block->done) {
|
||||
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|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpreter @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
if(box64_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions (hash=0x%x) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->hash, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
@@ -128,16 +134,6 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
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...
|
||||
@@ -156,29 +152,28 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
}
|
||||
#endif
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
}
|
||||
|
||||
int 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]);
|
||||
struct __jmp_buf_tag jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
struct __jmp_buf_tag *old_jmpbuf = emu->jmpbuf;
|
||||
emu->jmpbuf = jmpbuf;
|
||||
|
||||
if((skip=sigsetjmp(emu->jmpbuf, 1))) {
|
||||
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
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
@@ -186,14 +181,18 @@ int DynaRun(x64emu_t* emu)
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
while(!emu->quit) {
|
||||
dynablock_t* block = DBGetBlock(emu, R_RIP, 1);
|
||||
int is32bits = (emu->segs[_CS]==0x23);
|
||||
dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
if(!block || !block->block || !block->done) {
|
||||
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);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, 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);
|
||||
}
|
||||
@@ -202,20 +201,11 @@ int DynaRun(x64emu_t* emu)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+101
-77
@@ -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"
|
||||
@@ -25,6 +23,8 @@
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_next.h"
|
||||
|
||||
size_t box64_counter = 0;
|
||||
|
||||
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') {
|
||||
@@ -75,7 +75,7 @@ void add_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 64;
|
||||
dyn->next = (uintptr_t*)customRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
dyn->next = (uintptr_t*)dynaRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -84,11 +84,13 @@ uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
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
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[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;
|
||||
}
|
||||
@@ -265,7 +267,7 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
|
||||
}
|
||||
|
||||
// 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;
|
||||
@@ -276,10 +278,14 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
|
||||
if(idx==-1) {
|
||||
if(dyn->table64size == dyn->table64cap) {
|
||||
dyn->table64cap+=16;
|
||||
dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
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;
|
||||
@@ -304,7 +310,8 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)customMalloc(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) {
|
||||
@@ -321,11 +328,10 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
dyn->insts[j].pred[dyn->insts[j].pred_sz++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// updateNeed goes backward, from last intruction to top
|
||||
static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
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;
|
||||
@@ -379,33 +385,31 @@ void CancelBlock64(int need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_native_t* helper = (dynarec_native_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(!helper) {
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return;
|
||||
if(helper) {
|
||||
dynaFree(helper->next);
|
||||
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;
|
||||
}
|
||||
}
|
||||
customFree(helper->next);
|
||||
customFree(helper->insts);
|
||||
customFree(helper->predecessor);
|
||||
customFree(helper->table64);
|
||||
if(helper->dynablock && helper->dynablock->actual_block)
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
else if(helper->dynablock && helper->block)
|
||||
FreeDynarecMap((uintptr_t)helper->block-sizeof(void*));
|
||||
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* 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* actual_p = (void*)AllocDynarecMap(sz, box64_counter);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
@@ -416,16 +420,16 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
block->age = box64_counter + box64_dynarec_age;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
|
||||
block->need_test = 0;
|
||||
// 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) {
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bits) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
@@ -460,18 +464,19 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 128;
|
||||
helper.insts = (instruction_native_t*)customCalloc(helper.cap, sizeof(instruction_native_t));
|
||||
++box64_counter;
|
||||
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);
|
||||
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits);
|
||||
// no need for next anymore
|
||||
customFree(helper.next);
|
||||
dynaFree(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr);;
|
||||
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);
|
||||
@@ -489,6 +494,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
if(helper.insts[i].x64.jmp) {
|
||||
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 {
|
||||
@@ -511,79 +518,76 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
native_pass1(&helper, addr);
|
||||
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+helper.block_prolog+7)&~7; // round the size...
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = sizeof(void*) + helper.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 = actual_p + sizeof(void*);
|
||||
void* next = p + helper.native_size + helper.table64size*sizeof(uint64_t);
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
size_t sz = sizeof(void*) // dynablock_t*
|
||||
+ native_size // block (arm insts)
|
||||
+ helper.table64size*sizeof(uint64_t) // table64
|
||||
+ 4*sizeof(void*) // jmpnext code
|
||||
+ (box64_dynarec_age?sizeof(void*):0) // enter_count
|
||||
+ insts_rsize; // instsize
|
||||
|
||||
void* actual_p = (void*)AllocDynarecMap(sz, box64_counter);
|
||||
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*) + (box64_dynarec_age?sizeof(void*):0);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
block->actual_block = actual_p;
|
||||
block->active_count = box64_dynarec_age?(next + 4*sizeof(void*)):NULL;
|
||||
block->age = box64_counter + box64_dynarec_age;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = helper.native_start + helper.native_size;
|
||||
helper.insts_size = 0; // reset
|
||||
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;
|
||||
helper.enter = block->active_count;
|
||||
// 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);
|
||||
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;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, "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);
|
||||
}
|
||||
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
|
||||
customFree(helper.insts);
|
||||
instruction_native_t* pass2_insts = helper.insts;
|
||||
helper.insts = NULL;
|
||||
customFree(helper.table64);
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
customFree(helper.predecessor);
|
||||
dynaFree(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+2*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+2*sizeof(void*));
|
||||
block->need_test = 0;
|
||||
*(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...
|
||||
@@ -591,15 +595,35 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
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_DEBUG, "Warning, a block changed while beeing processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, 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;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size-1; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
for(; dump<(uint8_t*)pass2_insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", pass2_insts[i].size2, pass2_insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
dynaFree(pass2_insts);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
dynaFree(pass2_insts);
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, ists_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_DEBUG, "Warning, block unprotected while beeing processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size);
|
||||
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->need_test = 1;
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
current_helper = NULL;
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
#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)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp32s>>2)&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 aligments 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_singlestep(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGTRAP, (void*)R_RIP, 1);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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_C1 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((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 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->f.pending!=SF_SET)
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) {
|
||||
if(dyn->f.pending!=SF_PENDING) {*/
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
case SF_SET:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET && dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CacheNeedsTransform(dynarec_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;
|
||||
}
|
||||
#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,65 @@
|
||||
#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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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__
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -27,7 +26,7 @@
|
||||
#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;
|
||||
@@ -45,11 +44,15 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
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 bligblocks==2, else it needs 3
|
||||
// ok, go now
|
||||
INIT;
|
||||
if(box64_dynarec_age) {
|
||||
ENTER();
|
||||
}
|
||||
while(ok) {
|
||||
ip = addr;
|
||||
if (reset_n!=-1) {
|
||||
@@ -60,44 +63,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");
|
||||
@@ -110,36 +76,33 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
} else if(ninst && (dyn->insts[ninst].pred_sz!=1 || dyn->insts[ninst].pred[0]!=ninst-1))
|
||||
} 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 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;
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
NEW_INST;
|
||||
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);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box64_dynarec_trace) {
|
||||
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);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
@@ -157,11 +120,13 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t 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);
|
||||
|
||||
@@ -189,8 +154,18 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
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 {
|
||||
@@ -241,16 +216,30 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
}
|
||||
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)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
if(!((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)next))) {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && (((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)addr))
|
||||
@@ -259,6 +248,18 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
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);
|
||||
@@ -272,12 +273,14 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -4,17 +4,24 @@
|
||||
#ifdef ARM64
|
||||
void arm64_next(void) EXPORTDYN;
|
||||
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm64_epilog() EXPORTDYN;
|
||||
void arm64_epilog(void) EXPORTDYN;
|
||||
#define native_next arm64_next
|
||||
#define native_prolog arm64_prolog
|
||||
#define native_epilog arm64_epilog
|
||||
#elif defined(LA464)
|
||||
void la464_next(void) EXPORTDYN;
|
||||
void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void la464_epilog() EXPORTDYN;
|
||||
void la464_epilog(void) EXPORTDYN;
|
||||
#define native_next la464_next
|
||||
#define native_prolog la464_prolog
|
||||
#define native_epilog la464_epilog
|
||||
#elif defined(RV64)
|
||||
void rv64_next(void) EXPORTDYN;
|
||||
void rv64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void rv64_epilog(void) EXPORTDYN;
|
||||
#define native_next rv64_next
|
||||
#define native_prolog rv64_prolog
|
||||
#define native_epilog rv64_epilog
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
#define native_lock_write_dd(A, B) arm64_lock_write_dd(A, B)
|
||||
#define native_lock_read_dq(A, B, C) arm64_lock_read_dq(A, B, C)
|
||||
#define native_lock_write_dq(A, B, C) arm64_lock_write_dq(A, B, C)
|
||||
#define native_lock_xchg(A, B) arm64_lock_xchg(A, B)
|
||||
#define native_lock_xchg_dd(A, B) arm64_lock_xchg_dd(A, B)
|
||||
#define native_lock_xchg_d(A, B) arm64_lock_xchg_d(A, B)
|
||||
#define native_lock_xchg_h(A, B) arm64_lock_xchg_h(A, B)
|
||||
#define native_lock_xchg_b(A, B) arm64_lock_xchg_b(A, B)
|
||||
#define native_lock_storeifref(A, B, C) arm64_lock_storeifref(A, B, C)
|
||||
#define native_lock_storeifref_d(A, B, C) arm64_lock_storeifref_d(A, B, C)
|
||||
#define native_lock_storeifref2_d(A, B, C) arm64_lock_storeifref2_d(A, B, C)
|
||||
@@ -27,6 +29,46 @@
|
||||
#define native_lock_decifnot0(A) arm64_lock_decifnot0(A)
|
||||
#define native_lock_store(A, B) arm64_lock_store(A, B)
|
||||
|
||||
#elif defined(RV64)
|
||||
#include "rv64/rv64_lock.h"
|
||||
|
||||
#define USE_CAS
|
||||
// RV64 is quite strict (or at least strongly recommand) on what you can do between an LD.A and an SD.A
|
||||
// That basicaly forbid to call a function, so there cannot be READ / WRITE separated
|
||||
// And so need to use a Compare and Swap mecanism instead
|
||||
|
||||
// no byte or 2-bytes atomic access on RISC-V
|
||||
#define native_lock_xchg_dd(A, B) rv64_lock_xchg_dd(A, B)
|
||||
#define native_lock_xchg_d(A, B) rv64_lock_xchg_d(A, B)
|
||||
#define native_lock_storeifref(A, B, C) rv64_lock_storeifref(A, B, C)
|
||||
#define native_lock_storeifref_d(A, B, C) rv64_lock_storeifref_d(A, B, C)
|
||||
#define native_lock_storeifref2_d(A, B, C) rv64_lock_storeifref2_d(A, B, C)
|
||||
#define native_lock_storeifnull(A, B) rv64_lock_storeifnull(A, B)
|
||||
#define native_lock_storeifnull_d(A, B) rv64_lock_storeifnull_d(A, B)
|
||||
#define native_lock_decifnot0b(A) rv64_lock_decifnot0b(A)
|
||||
#define native_lock_storeb(A, B) rv64_lock_storeb(A, B)
|
||||
#define native_lock_incif0(A) rv64_lock_incif0(A)
|
||||
#define native_lock_decifnot0(A) rv64_lock_decifnot0(A)
|
||||
#define native_lock_store(A, B) rv64_lock_store(A, B)
|
||||
#define native_lock_cas_d(A, B, C) rv64_lock_cas_d(A, B, C)
|
||||
#define native_lock_cas_dd(A, B, C) rv64_lock_cas_dd(A, B, C)
|
||||
|
||||
#define native_lock_xchg_b(A, B) rv64_lock_xchg_b(A, B)
|
||||
#define native_lock_cas_b(A, B, C) rv64_lock_cas_b(A, B, C)
|
||||
#define native_lock_cas_h(A, B, C) rv64_lock_cas_h(A, B, C)
|
||||
|
||||
#define native_lock_read_b(A) tmpcas=*(uint8_t*)(A)
|
||||
#define native_lock_write_b(A, B) rv64_lock_cas_b(A, tmpcas, B)
|
||||
#define native_lock_read_h(A) tmpcas=*(uint16_t*)(A)
|
||||
#define native_lock_write_h(A, B) rv64_lock_cas_h(A, tmpcas, B)
|
||||
#define native_lock_read_d(A) tmpcas=*(uint32_t*)(A)
|
||||
#define native_lock_write_d(A, B) rv64_lock_cas_d(A, tmpcas, B)
|
||||
#define native_lock_read_dd(A) tmpcas=*(uint64_t*)(A)
|
||||
#define native_lock_write_dd(A, B) rv64_lock_cas_dd(A, tmpcas, B)
|
||||
// there is no atomic move on 16bytes, so faking it
|
||||
#define native_lock_read_dq(A, B, C) *A=tmpcas=((uint64_t*)(C))[0]; *B=((uint64_t*)(C))[1];
|
||||
#define native_lock_write_dq(A, B, C) rv64_lock_cas_dq(C, A, tmpcas, B);
|
||||
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <assert.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 "bridge.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
int isSimpleWrapper(wrapper_t fun);
|
||||
|
||||
uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode;
|
||||
|
||||
opcode = PK(0);
|
||||
switch(opcode) {
|
||||
case 0x00 ... 0x3f: addr = dynarec64_00_0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog); break;
|
||||
case 0x40 ... 0x7f: addr = dynarec64_00_1(dyn, addr, ip, ninst, rex, rep, ok, need_epilog); break;
|
||||
case 0x80 ... 0xbf: addr = dynarec64_00_2(dyn, addr, ip, ninst, rex, rep, ok, need_epilog); break;
|
||||
case 0xc0 ... 0xff: addr = dynarec64_00_3(dyn, addr, ip, ninst, rex, rep, ok, need_epilog); break;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <assert.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 "bridge.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
int isSimpleWrapper(wrapper_t fun);
|
||||
|
||||
uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode;
|
||||
uint8_t gd, ed;
|
||||
int8_t i8;
|
||||
int32_t i32, tmp;
|
||||
int64_t i64, j64;
|
||||
uint8_t u8;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
int cacheupd = 0;
|
||||
|
||||
opcode = F8;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
INST_NAME("ADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x02:
|
||||
INST_NAME("ADD Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_add8(dyn, ninst, x2, x1, x4, x5);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("ADD AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_add8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
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, x6);
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("OR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(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;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_or8(dyn, ninst, x2, x1, x4, x5);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(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;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_or8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
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:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
addr = dynarec64_0F(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
break;
|
||||
case 1:
|
||||
addr = dynarec64_F20F(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
break;
|
||||
case 2:
|
||||
addr = dynarec64_F30F(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x18:
|
||||
INST_NAME("SBB Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x1A:
|
||||
INST_NAME("SBB Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("SBB AL, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x3, x4, x5, x6);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
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, x5);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_and8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK(x4, 0);
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(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;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_and8(dyn, ninst, x2, x1, x4, x5);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(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;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_and8c(dyn, ninst, x1, u8, x3, x4);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
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;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sub8(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("SUB Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sub8(dyn, ninst, x2, x1, x4, x5, x6);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("SUB AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x3, x4, x5);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_sub32c(dyn, ninst, rex, xRAX, i64, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x30:
|
||||
INST_NAME("XOR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_xor8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
if(ed!=gd) {
|
||||
WBACK;
|
||||
}
|
||||
break;
|
||||
case 0x32:
|
||||
INST_NAME("XOR Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_xor8(dyn, ninst, x2, x1, x4, x5);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(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;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_xor8c(dyn, ninst, x1, u8, x3, x4);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
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;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_cmp32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3A:
|
||||
INST_NAME("CMP Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_cmp8(dyn, ninst, x2, x1, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3C:
|
||||
INST_NAME("CMP AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
if(u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} 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, x6);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, xRAX, x3, x4);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <assert.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 "bridge.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
int isSimpleWrapper(wrapper_t fun);
|
||||
|
||||
uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode;
|
||||
uint8_t gd, ed;
|
||||
int8_t i8;
|
||||
int32_t i32, tmp;
|
||||
int64_t i64, j64;
|
||||
uint8_t u8;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
int cacheupd = 0;
|
||||
|
||||
opcode = F8;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
emit_inc32(dyn, ninst, rex, gd, x1, x2, x3, x4);
|
||||
break;
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
emit_dec32(dyn, ninst, rex, gd, x1, x2, x3, x4);
|
||||
break;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
INST_NAME("PUSH reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
PUSH1z(gd);
|
||||
break;
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
INST_NAME("POP reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
POP1z(gd);
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("PUSHAD");
|
||||
AND(x1, xRSP, xMASK);
|
||||
PUSH1_32(xRAX);
|
||||
PUSH1_32(xRCX);
|
||||
PUSH1_32(xRDX);
|
||||
PUSH1_32(xRBX);
|
||||
PUSH1_32(x1);
|
||||
PUSH1_32(xRBP);
|
||||
PUSH1_32(xRSI);
|
||||
PUSH1_32(xRDI);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x61:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POPAD");
|
||||
POP1_32(xRDI);
|
||||
POP1_32(xRSI);
|
||||
POP1_32(xRBP);
|
||||
POP1_32(x1);
|
||||
POP1_32(xRBX);
|
||||
POP1_32(xRDX);
|
||||
POP1_32(xRCX);
|
||||
POP1_32(xRAX);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x63:
|
||||
if(rex.is32bits) {
|
||||
// this is ARPL opcode
|
||||
DEFAULT;
|
||||
} else {
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
ADDIW(gd, xRAX+(nextop&7)+(rex.b<<3), 0);
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LW(gd, ed, fixedaddress);
|
||||
}
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
AND(gd, xRAX+(nextop&7)+(rex.b<<3), xMASK);
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LWU(gd, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
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_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x67:
|
||||
addr = dynarec64_67(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x68:
|
||||
INST_NAME("PUSH Id");
|
||||
i64 = F32S;
|
||||
if(PK(0)==0xC3) {
|
||||
MESSAGE(LOG_DUMP, "PUSH then RET, using indirect\n");
|
||||
TABLE64(x3, addr-4);
|
||||
LW(x1, x3, 0);
|
||||
PUSH1z(x1);
|
||||
} else {
|
||||
MOV64z(x3, i64);
|
||||
PUSH1z(x3);
|
||||
}
|
||||
break;
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x4, i64);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
MULH(x3, ed, x4);
|
||||
MUL(gd, ed, x4);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
MUL(gd, ed, x4);
|
||||
UFLAG_RES(gd);
|
||||
SRLI(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
i64 = F8S;
|
||||
MOV64z(x3, i64);
|
||||
PUSH1z(x3);
|
||||
break;
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gd, Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(1);
|
||||
i64 = F8S;
|
||||
MOV64xw(x4, i64);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
MULH(x3, ed, x4);
|
||||
MUL(gd, ed, x4);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MUL(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
MUL(gd, ed, x4);
|
||||
UFLAG_RES(gd);
|
||||
SRLI(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
} else {
|
||||
MULW(gd, ed, x4);
|
||||
}
|
||||
ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
i8 = F8S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
B##NO##_safe(x1, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
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 { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
B(i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
B##YES##_safe(x1, i32); \
|
||||
}
|
||||
|
||||
GOCOND(0x70, "J", "ib");
|
||||
|
||||
#undef GO
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,847 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <assert.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 "bridge.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
int isSimpleWrapper(wrapper_t fun);
|
||||
|
||||
uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode;
|
||||
uint8_t gd, ed;
|
||||
int8_t i8;
|
||||
int32_t i32, tmp;
|
||||
int64_t i64, j64;
|
||||
uint8_t u8;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
int cacheupd = 0;
|
||||
|
||||
opcode = F8;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x80:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // ADD
|
||||
INST_NAME("ADD Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 1: // OR
|
||||
INST_NAME("OR Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 2: // ADC
|
||||
INST_NAME("ADC Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 3: // SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 4: // AND
|
||||
INST_NAME("AND Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 5: // SUB
|
||||
INST_NAME("SUB Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 6: // XOR
|
||||
INST_NAME("XOR Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 7: // CMP
|
||||
INST_NAME("CMP Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
ADDI(x2, xZR, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
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);
|
||||
GETED((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
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);
|
||||
GETED((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);
|
||||
GETED((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, x9);
|
||||
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);
|
||||
GETED((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x6);
|
||||
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);
|
||||
GETED((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);
|
||||
GETED((opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
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);
|
||||
GETED((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);
|
||||
GETED((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, x6);
|
||||
} else {
|
||||
if(!rex.w && MODREG) {
|
||||
AND(x1, ed, xMASK);
|
||||
ed = x1;
|
||||
}
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x84:
|
||||
INST_NAME("TEST Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop=F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
break;
|
||||
case 0x86:
|
||||
INST_NAME("(LOCK)XCHG Eb, Gb");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
GETGB(x1);
|
||||
GETEB(x2, 0);
|
||||
MV(x4, gd);
|
||||
MV(gd, ed);
|
||||
MV(ed, x4);
|
||||
GBBACK(x4);
|
||||
EBBACK(x4, 0);
|
||||
} else {
|
||||
GETGB(x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
LBU(x1, ed, 0);
|
||||
SB(gd, ed, 0);
|
||||
SMDMB();
|
||||
gd = x1;
|
||||
GBBACK(x3);
|
||||
}
|
||||
break;
|
||||
case 0x87:
|
||||
INST_NAME("(LOCK)XCHG Ed, Gd");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
GETGD;
|
||||
GETED(0);
|
||||
MVxw(x1, gd);
|
||||
MVxw(gd, ed);
|
||||
MVxw(ed, x1);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
ANDI(x3, ed, (1<<(2+rex.w))-1);
|
||||
BNE_MARK(x3, xZR);
|
||||
MARKLOCK;
|
||||
LRxw(x1, ed, 1, 0);
|
||||
SCxw(x3, gd, ed, 0, 1);
|
||||
BNE_MARKLOCK(x3, xZR);
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
LDxw(x1, ed, 0);
|
||||
SDxw(gd, ed, 0);
|
||||
MARK2;
|
||||
SMDMB();
|
||||
MVxw(gd, x1);
|
||||
}
|
||||
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)>>2);
|
||||
gb1 = xRAX+(gd&3);
|
||||
}
|
||||
gd = x4;
|
||||
if(gb2) {
|
||||
SRLI(x4, gb1, 8);
|
||||
gb1 = x4;
|
||||
}
|
||||
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
|
||||
}
|
||||
ANDI(gd, gb1, 0xff);
|
||||
if(eb2) {
|
||||
MOV64x(x1, 0xffffffffffff00ffLL);
|
||||
AND(x1, eb1, x1);
|
||||
SLLI(gd, gd, 8);
|
||||
OR(eb1, x1, gd);
|
||||
} else {
|
||||
ANDI(x1, eb1, ~0xff);
|
||||
OR(eb1, x1, gd);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SB(gb1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MVxw(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SDxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8A:
|
||||
INST_NAME("MOV Gb, Eb");
|
||||
nextop = F8;
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3);
|
||||
if(rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = xRAX + gd;
|
||||
} else {
|
||||
gb2 = ((gd&4)>>2);
|
||||
gb1 = xRAX+(gd&3);
|
||||
}
|
||||
gd = x4;
|
||||
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
|
||||
}
|
||||
if(eb2) {
|
||||
SRLI(x1, eb1, 8);
|
||||
ANDI(x1, x1, 0xff);
|
||||
} else {
|
||||
ANDI(x1, eb1, 0xff);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LBU(x1, ed, fixedaddress);
|
||||
}
|
||||
if(gb2) {
|
||||
MOV64x(x4, ~0xff00);
|
||||
AND(gb1, gb1, x4);
|
||||
SLLI(x1, x1, 8);
|
||||
} else {
|
||||
ANDI(gb1, gb1, ~0xff);
|
||||
}
|
||||
OR(gb1, gb1, x1);
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
MVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x8C:
|
||||
INST_NAME("MOV Ed, Seg");
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
LHU(xRAX+(nextop&7)+(rex.b<<3), xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
|
||||
SH(x3, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
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, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
MV(gd, ed);
|
||||
if(!rex.w || rex.is32bits) {
|
||||
ZEROUP(gd); // truncate the higher 32bits as asked
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg,Ew");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
LHU(x1, ed, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
SW(ed, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
|
||||
SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[(nextop&0x38)>>3]));
|
||||
break;
|
||||
case 0x8F:
|
||||
INST_NAME("POP Ed");
|
||||
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, x3, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
if(ed==xRSP) {
|
||||
SDz(x2, ed, fixedaddress);
|
||||
} else {
|
||||
// complicated to just allow a segfault that can be recovered correctly
|
||||
ADDIz(xRSP, xRSP, rex.is32bits?-4:-8);
|
||||
SDz(x2, ed, fixedaddress);
|
||||
ADDIz(xRSP, xRSP, rex.is32bits?4:8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
if(gd==xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
INST_NAME("XCHG EAX, Reg");
|
||||
MVxw(x2, xRAX);
|
||||
MVxw(xRAX, gd);
|
||||
MVxw(gd, x2);
|
||||
}
|
||||
break;
|
||||
case 0x98:
|
||||
INST_NAME("CWDE");
|
||||
if(rex.w) {
|
||||
SEXT_W(xRAX, xRAX);
|
||||
} else {
|
||||
SLLI(xRAX, xRAX, 16);
|
||||
SRAIW(xRAX, xRAX, 16);
|
||||
ZEROUP(xRAX);
|
||||
}
|
||||
break;
|
||||
case 0x99:
|
||||
INST_NAME("CDQ");
|
||||
if(rex.w) {
|
||||
SRAI(xRDX, xRAX, 63);
|
||||
} else {
|
||||
SLLI(xRDX, xRAX, 32);
|
||||
SRAI(xRDX, xRDX, 63);
|
||||
ZEROUP(xRDX);
|
||||
}
|
||||
break;
|
||||
case 0x9B:
|
||||
INST_NAME("FWAIT");
|
||||
break;
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
NOTEST(x1);
|
||||
READFLAGS(X_ALL);
|
||||
FLAGS_ADJUST_TO11(x3, xFlags, x2);
|
||||
PUSH1z(x3);
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
POP1z(xFlags);
|
||||
FLAGS_ADJUST_FROM11(xFlags, x2);
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
AND(xFlags, xFlags, x1);
|
||||
ORI(xFlags, xFlags, 0x2);
|
||||
SET_DFNONE();
|
||||
if(box64_wine) { // should this be done all the time?
|
||||
ANDI(x1, xFlags, 1 << F_TF);
|
||||
CBZ_NEXT(x1);
|
||||
MOV64x(xRIP, addr);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_singlestep, -1);
|
||||
ANDI(xFlags, xFlags, ~(1 << F_TF));
|
||||
}
|
||||
break;
|
||||
case 0x9F:
|
||||
INST_NAME("LAHF");
|
||||
READFLAGS(X_CF|X_PF|X_AF|X_ZF|X_SF);
|
||||
ANDI(x1, xFlags, 0xFF);
|
||||
SLLI(x1, x1, 8);
|
||||
MOV64x(x2, 0xffffffffffff00ffLL);
|
||||
AND(xRAX, xRAX, x2);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0xA0:
|
||||
INST_NAME("MOV AL,Ob");
|
||||
if(rex.is32bits) u64 = F32; else u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
LBU(x1, x1, 0);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
if(rex.is32bits) u64 = F32; else u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
LDxw(xRAX, x1, 0);
|
||||
break;
|
||||
case 0xA2:
|
||||
INST_NAME("MOV Ob,AL");
|
||||
if(rex.is32bits) u64 = F32; else u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
SB(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
if(rex.is32bits) u64 = F32; else u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
SDxw(xRAX, x1, 0);
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xA4:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LBU(x1, xRSI, 0);
|
||||
SB(x1, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, 1);
|
||||
ADDI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LBU(x1, xRSI, 0);
|
||||
LBU(x1, xRDI, 0);
|
||||
SUBI(xRSI, xRSI, 1);
|
||||
SUBI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
GETDIR(x3, x1, 1);
|
||||
LBU(x1, xRSI, 0);
|
||||
SB(x1, xRDI, 0);
|
||||
ADD(xRSI, xRSI, x3);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA5:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSD");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LDxw(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, rex.w?8:4);
|
||||
SDxw(x1, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDxw(x1, xRSI, 0);
|
||||
SUBI(xRSI, xRSI, rex.w?8:4);
|
||||
SDxw(x1, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSD");
|
||||
GETDIR(x3, x1, rex.w?8:4);
|
||||
LDxw(x1, xRSI, 0);
|
||||
SDxw(x1, xRDI, 0);
|
||||
ADD(xRSI, xRSI, x3);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA6:
|
||||
switch(rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ CMPSB");} else {INST_NAME("REPZ CMPSB");}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LBU(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, 1);
|
||||
LBU(x2, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNEZ_MARK(xRCX);
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LBU(x1, xRSI, 0);
|
||||
SUBI(xRSI, xRSI, 1);
|
||||
LBU(x2, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNEZ_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSB");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, x1, 1);
|
||||
LBU(x1, xRSI, 0);
|
||||
LBU(x2, xRDI, 0);
|
||||
ADD(xRSI, xRSI, x3);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xA8:
|
||||
INST_NAME("TEST AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0xA9:
|
||||
INST_NAME("TEST EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_test32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0xAA:
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSB");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
SB(xRAX, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, 1);
|
||||
ADDI(xRCX, xRCX, -1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
SB(xRAX, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, -1);
|
||||
ADDI(xRCX, xRCX, -1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSB");
|
||||
GETDIR(x3, x1, 1);
|
||||
SB(xRAX, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xAB:
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSD");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
SDxw(xRAX, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
SDxw(xRAX, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSD");
|
||||
GETDIR(x3, x1, rex.w?8:4);
|
||||
SDxw(xRAX, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
switch (rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (rep==1) {INST_NAME("REPNZ SCASB");} else {INST_NAME("REPZ SCASB");}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
ANDI(x2, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x2);
|
||||
MARK; // Part with DF==0
|
||||
LBU(x2, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNE_MARK(xRCX, xZR);
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LBU(x2, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNE_MARK2(xRCX, xZR);
|
||||
MARK3; // end
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASB");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, x1, 1);
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
LBU(x2, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
switch (rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (rep==1) {INST_NAME("REPNZ SCASD");} else {INST_NAME("REPZ SCASD");}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZ_NEXT(xRCX);
|
||||
if (rex.w) {MV(x1, xRAX);} else {AND(x1, xRAX, xMASK);}
|
||||
ANDI(x2, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x2);
|
||||
MARK; // Part with DF==0
|
||||
LDxw(x2, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNE_MARK(xRCX, xZR);
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDxw(x2, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNE_MARK2(xRCX, xZR);
|
||||
MARK3; // end
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASD");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, x1, rex.w?8:4);
|
||||
AND(x1, xRAX, xMASK);
|
||||
LDxw(x2, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xB0:
|
||||
case 0xB1:
|
||||
case 0xB2:
|
||||
case 0xB3:
|
||||
INST_NAME("MOV xL, Ib");
|
||||
u8 = F8;
|
||||
if(rex.rex)
|
||||
gb1 = xRAX+(opcode&7)+(rex.b<<3);
|
||||
else
|
||||
gb1 = xRAX+(opcode&3);
|
||||
ANDI(gb1, gb1, ~0xff);
|
||||
ORI(gb1, gb1, u8);
|
||||
break;
|
||||
case 0xB4:
|
||||
case 0xB5:
|
||||
case 0xB6:
|
||||
case 0xB7:
|
||||
INST_NAME("MOV xH, Ib");
|
||||
u8 = F8;
|
||||
if(rex.rex) {
|
||||
gb1 = xRAX+(opcode&7)+(rex.b<<3);
|
||||
ANDI(gb1, gb1, ~0xff);
|
||||
ORI(gb1, gb1, u8);
|
||||
} else {
|
||||
MOV32w(x1, u8);
|
||||
gb1 = xRAX+(opcode&3);
|
||||
MOV64x(x2, 0xffffffffffff00ffLL);
|
||||
AND(gb1, gb1, x2);
|
||||
SLLI(x1, x1, 8);
|
||||
OR(gb1, gb1, x1);
|
||||
}
|
||||
break;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg, Id");
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
u64 = F64;
|
||||
MOV64x(gd, u64);
|
||||
} else {
|
||||
u32 = F32;
|
||||
MOV32w(gd, u32);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,496 @@
|
||||
#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 "custommem.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_64(dynarec_rv64_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;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t u8;
|
||||
uint8_t gd, ed, eb1, eb2, gb1, gb2;
|
||||
uint8_t gback, wback, wb1, wb2, wb;
|
||||
int64_t i64, j64;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0, x5);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x11:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVUPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
if(!MODREG) {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
ADD(x4, x4, wback);
|
||||
wback = x4;
|
||||
}
|
||||
LD(x3, gback, gdoffset+0);
|
||||
LD(x5, gback, gdoffset+8);
|
||||
SD(x3, wback, fixedaddress+0);
|
||||
SD(x5, wback, fixedaddress+8);
|
||||
if(!MODREG)
|
||||
SMWRITE2();
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
FMVD(d0, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD(x4, x4, ed);
|
||||
ed = x4;
|
||||
FSD(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
FMVS(q0, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD(x4, x4, ed);
|
||||
ed = x4;
|
||||
FSW(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
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, x5);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0, x5);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, seg, ok, need_epilog);
|
||||
break;
|
||||
case 0x80:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // ADD
|
||||
INST_NAME("ADD Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 1: // OR
|
||||
INST_NAME("OR Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 2: // ADC
|
||||
INST_NAME("ADC Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 3: // SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 4: // AND
|
||||
INST_NAME("AND Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 5: // SUB
|
||||
INST_NAME("SUB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 6: // XOR
|
||||
INST_NAME("XOR Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 7: // CMP
|
||||
INST_NAME("CMP Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
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);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x9);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1: // OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
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);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
SD(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, x9);
|
||||
LD(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
WBACKO(x6);
|
||||
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);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x9);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 4: // AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 5: // SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x9);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 6: // XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 7: // CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode==0x81)?4:1, x5);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x88:
|
||||
INST_NAME("MOV Seg:Eb, Gb");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3);
|
||||
if(rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = xRAX + gd;
|
||||
} else {
|
||||
gb2 = ((gd&4)>>2);
|
||||
gb1 = xRAX+(gd&3);
|
||||
}
|
||||
gd = x5;
|
||||
if(gb2) {
|
||||
SRLI(x5, gb1, 8);
|
||||
gb1 = x5;
|
||||
}
|
||||
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
|
||||
}
|
||||
ANDI(gd, gb1, 0xff);
|
||||
if(eb2) {
|
||||
MOV64x(x1, 0xffffffffffff00ffLL);
|
||||
ANDI(x1, eb1, x1);
|
||||
SLLI(gd, gd, 8);
|
||||
OR(eb1, x1, gd);
|
||||
} else {
|
||||
ANDI(x1, eb1, ~0xff);
|
||||
OR(eb1, x1, gd);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD(x4, ed, x4);
|
||||
SB(gb1, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MVxw(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD(x4, ed, x4);
|
||||
SDxw(gd, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD(x4, ed, x4);
|
||||
LDxw(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,FS:Od");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
// TODO: could be optimized.
|
||||
MOV64z(x1, u64);
|
||||
ADD(x1, x1, x4);
|
||||
LDxw(xRAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Od,EAX");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
// TODO: could be optimized.
|
||||
MOV64z(x1, u64);
|
||||
ADD(x1, x1, x4);
|
||||
SDxw(xRAX, x1, 0);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= u8
|
||||
u8 = F8;
|
||||
if(!rex.rex) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
} else {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0;
|
||||
}
|
||||
|
||||
if (eb2) {
|
||||
// load a mask to x3 (ffffffffffff00ff)
|
||||
LUI(x3, 0xffff0);
|
||||
ORI(x3, x3, 0xff);
|
||||
// apply mask
|
||||
AND(eb1, eb1, x3);
|
||||
if(u8) {
|
||||
if((u8<<8)<2048) {
|
||||
ADDI(x4, xZR, u8<<8);
|
||||
} else {
|
||||
ADDI(x4, xZR, u8);
|
||||
SLLI(x4, x4, 8);
|
||||
}
|
||||
OR(eb1, eb1, x4);
|
||||
}
|
||||
} else {
|
||||
ANDI(eb1, eb1, 0xf00); // mask ffffffffffffff00
|
||||
ORI(eb1, eb1, u8);
|
||||
}
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
ADDI(x3, xZR, u8);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
ADD(x4, wback, x4);
|
||||
SB(ed, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Seg:Ed, Id");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 4);
|
||||
i64 = F32S;
|
||||
if(i64) {
|
||||
MOV64xw(x3, i64);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
ADD(x4, wback, x4);
|
||||
SDxw(ed, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,922 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint64_t u64;
|
||||
int32_t i32;
|
||||
int64_t j64;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int lock;
|
||||
MAYUSE(u8);
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u64);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(lock);
|
||||
|
||||
while((opcode==0x2E) || (opcode==0x36) || (opcode==0x66)) // ignoring CS:, SS: or multiple 0x66
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
if(rex.w && !(opcode==0x0f || opcode==0xf0 || opcode==0x64 || opcode==0x65)) // rex.w cancels "66", but not for 66 0f type of prefix
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode
|
||||
|
||||
switch(opcode) {
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
ZEXTH(x1 , xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(xRAX, xRAX, x3);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
ZEXTH(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(xRAX, xRAX, x3);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0x0F:
|
||||
addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
ZEXTH(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(xRAX, xRAX, x3);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x2, x1, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
ZEXTH(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
LUI(x2, 0xffff0);
|
||||
AND(xRAX, xRAX, x2);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
ZEXTH(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
LUI(x5, 0xffff0);
|
||||
AND(xRAX, xRAX, x5);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
ZEXTH(x1, xRAX);
|
||||
if(i32) {
|
||||
MOV32w(x2, i32);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg16 (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
ZEXTH(x1, gd);
|
||||
emit_inc16(dyn, ninst, x1, x2, x3, x4);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(gd, gd, x3);
|
||||
OR(gd, gd, x1);
|
||||
ZEROUP(gd);
|
||||
break;
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg16 (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
ZEXTH(x1, gd);
|
||||
emit_dec16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(gd, gd, x3);
|
||||
OR(gd, gd, x1);
|
||||
ZEROUP(gd);
|
||||
break;
|
||||
case 0x64:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _FS, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _GS, ok, need_epilog);
|
||||
break;
|
||||
case 0x66:
|
||||
addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x69:
|
||||
case 0x6B:
|
||||
if(opcode==0x69) {
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
} else {
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, (opcode==0x69)?2:1);
|
||||
if(opcode==0x69) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MULW(x2, x2, x1);
|
||||
ZEXTH(x2, x2);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
case 0x73:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
case 0x76:
|
||||
case 0x77:
|
||||
case 0x78:
|
||||
case 0x79:
|
||||
case 0x7a:
|
||||
case 0x7b:
|
||||
case 0x7c:
|
||||
case 0x7d:
|
||||
case 0x7e:
|
||||
case 0x7f:
|
||||
// just use regular conditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: // OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: // ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: // SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: // AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: // SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: // XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: // CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOV64x(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
// we don't use GETGW above, so we need let gd & 0xffff.
|
||||
LUI(x1, 0xffff0);
|
||||
AND(ed, ed, x1);
|
||||
ZEXTH(x2, gd);
|
||||
OR(ed, ed, x2);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 0, 0);
|
||||
SH(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
LUI(x1, 0xffff0);
|
||||
AND(gd, gd, x1);
|
||||
ZEXTH(x2, ed);
|
||||
OR(gd, gd, x2);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LHU(x1, ed, fixedaddress);
|
||||
LUI(x4, 0xffff0);
|
||||
AND(gd, gd, x4);
|
||||
OR(gd, gd, x1);
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
if(gd==xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
INST_NAME("XCHG AX, Reg");
|
||||
LUI(x4, 0xffff0);
|
||||
// x2 <- rax
|
||||
MV(x2, xRAX);
|
||||
// rax[15:0] <- gd[15:0]
|
||||
ZEXTH(x3, gd);
|
||||
AND(xRAX, xRAX, x4);
|
||||
OR(xRAX, xRAX, x3);
|
||||
// gd[15:0] <- x2[15:0]
|
||||
ZEXTH(x2, x2);
|
||||
AND(gd, gd, x4);
|
||||
OR(gd, gd, x2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x98:
|
||||
INST_NAME("CBW");
|
||||
SLLI(x1, xRAX, 56);
|
||||
SRAI(x1, x1, 56);
|
||||
LUI(x2, 0xffff0);
|
||||
AND(xRAX, xRAX, x2);
|
||||
NOT(x2, x2);
|
||||
AND(x1, x1, x2);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0xA5:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LH(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, 2);
|
||||
SH(x1, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LH(x1, xRSI, 0);
|
||||
SUBI(xRSI, xRSI, 2);
|
||||
SH(x1, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSD");
|
||||
GETDIR(x3, x1, 2);
|
||||
LH(x1, xRSI, 0);
|
||||
SH(x1, xRDI, 0);
|
||||
ADD(xRSI, xRSI, x3);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
SLLIW(x1, xRAX, 16);
|
||||
SRLIW(x1, x1, 16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0xAB:
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
SH(xRAX, xRDI, 0);
|
||||
ADDI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
SH(xRAX, xRDI, 0);
|
||||
SUBI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
GETDIR(x3, x1, 2);
|
||||
SH(xRAX, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAF:
|
||||
switch (rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZ_NEXT(xRCX);
|
||||
GETDIR(x3, x1, rex.w?8:2);
|
||||
if (rex.w) {
|
||||
MARK;
|
||||
LD(x2, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
ADDI(xRCX, xRCX, -1);
|
||||
if (rep==1) {BEQ_MARK3(xRAX, x2);} else {BNE_MARK3(xRAX, x2);}
|
||||
BNE_MARK(xRCX, xZR);
|
||||
MARK3;
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
ZEXTH(x1, xRAX);
|
||||
MARK;
|
||||
LHU(x2, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
ADDI(xRCX, xRCX, -1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
BNE_MARK(xRCX, xZR);
|
||||
MARK3;
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, x1, rex.w?8:2);
|
||||
if (rex.w) {
|
||||
LD(x2, xRDI, 0);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
ZEXTH(x1, xRAX);
|
||||
LHU(x2, xRDI, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
}
|
||||
ADD(xRDI, xRDI, x3);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg, Iw");
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
u64 = F64;
|
||||
MOV64x(gd, u64);
|
||||
} else {
|
||||
u16 = F16;
|
||||
MOV64x(x1, ~0xffff);
|
||||
AND(gd, gd, x1);
|
||||
if(u16<2048) {
|
||||
ORI(gd, gd, u16);
|
||||
} else {
|
||||
MOV32w(x1, u16);
|
||||
OR(gd, gd, x1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
if(MODREG) {
|
||||
SLLI(ed, ed, 48+(u8&0x1f));
|
||||
SRLI(ed, ed, 48);
|
||||
} else {
|
||||
SLLI(ed, ed, u8&0x1f);
|
||||
}
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
SRLI(ed, ed, u8&0x1f);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
GETSEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF {MOV32w(x2, (u8&0x1f));}
|
||||
UFLAG_OP12(ed, x2)
|
||||
SRAI(ed, ed, u8&0x1f);
|
||||
if(MODREG) {
|
||||
ZEXTH(ed, ed);
|
||||
}
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ADDI(x1, xZR, -1);
|
||||
SRLI(x1, x1, 48);
|
||||
AND(ed, ed, x1);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
ORI(ed, ed, x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
SH(x1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0xD1:
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
SRL(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
SLL(ed, ed, x4);
|
||||
ZEXTH(ed, ed);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4);
|
||||
SRA(ed, ed, x4);
|
||||
ZEXTH(ed, ed);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1:
|
||||
INST_NAME("TEST Ew, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
NOT(ed, ed); // No flags affected
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
ZEXTH(x2, xRAX);
|
||||
SLLI(x3, xRDX, 48);
|
||||
SRLI(x3, x3, 32);
|
||||
OR(x2, x2, x3);
|
||||
DIVUW(x3, x2, ed);
|
||||
REMUW(x4, x2, ed);
|
||||
MOV64x(x5, ~0xffff);
|
||||
AND(xRAX, xRAX, x5);
|
||||
AND(xRDX, xRDX, x5);
|
||||
NOT(x5, x5);
|
||||
AND(x3, x3, x5);
|
||||
AND(x4, x4, x5);
|
||||
OR(xRAX, xRAX, x3);
|
||||
OR(xRDX, xRDX, x4);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETSEW(x1, 0);
|
||||
ZEXTH(x2, xRAX);
|
||||
SLLI(x3, xRDX, 48);
|
||||
SRLI(x3, x3, 32);
|
||||
OR(x2, x2, x3);
|
||||
DIVW(x3, x2, ed);
|
||||
REMW(x4, x2, ed);
|
||||
MOV64x(x5, ~0xffff);
|
||||
AND(xRAX, xRAX, x5);
|
||||
AND(xRDX, xRDX, x5);
|
||||
NOT(x5, x5);
|
||||
AND(x3, x3, x5);
|
||||
AND(x4, x4, x5);
|
||||
OR(xRAX, xRAX, x3);
|
||||
OR(xRDX, xRDX, x4);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,77 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_6664(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* 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);
|
||||
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
MV(gd, ed);
|
||||
} else {
|
||||
if(ed!=gd) {
|
||||
LUI(x1, 0xffff0);
|
||||
AND(gd, gd, x1);
|
||||
ZEXTH(x1, ed);
|
||||
OR(gd, gd, x1);
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD(x4, ed, x4);
|
||||
if(rex.w) {
|
||||
LD(gd, x4, fixedaddress);
|
||||
} else {
|
||||
LHU(x1, x4, fixedaddress);
|
||||
SRLI(gd, gd, 16);
|
||||
SLLI(gd, gd, 16);
|
||||
OR(gd, gd, x1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66F0(dynarec_rv64_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 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
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);
|
||||
ZEXTH(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4, x2);
|
||||
SRLI(ed, ed, 16);
|
||||
SLLI(ed, ed, 16);
|
||||
OR(ed, ed, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
|
||||
ANDI(x3, wback, 0b10);
|
||||
BNEZ_MARK(x3);
|
||||
|
||||
// lower 16 bits
|
||||
MARKLOCK;
|
||||
LR_W(x1, wback, 1, 1);
|
||||
SRLIW(x3, x1, 16);
|
||||
SLLIW(x3, x3, 16);
|
||||
ADD(x4, x1, x5);
|
||||
SLLIW(x4, x4, 16);
|
||||
SRLIW(x4, x4, 16);
|
||||
OR(x4, x4, x3);
|
||||
SC_W(x3, x4, wback, 1, 1);
|
||||
BNEZ_MARKLOCK(x3);
|
||||
IFX(X_ALL|X_PEND) {
|
||||
SLLIW(x1, x1, 16);
|
||||
SRLIW(x1, x1, 16);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
|
||||
MARK;
|
||||
// upper 16 bits
|
||||
XORI(wback, wback, 0b10);
|
||||
MARK2;
|
||||
LR_W(x1, wback, 1, 1);
|
||||
SLLIW(x3, x1, 16);
|
||||
SRLIW(x3, x3, 16);
|
||||
SRLIW(x1, x1, 16);
|
||||
ADD(x4, x1, x5);
|
||||
SLLIW(x4, x4, 16);
|
||||
OR(x4, x4, x3);
|
||||
SC_W(x3, x4, wback, 1, 1);
|
||||
BNEZ_MARK2(x3);
|
||||
|
||||
MARK3;
|
||||
// final
|
||||
IFX(X_ALL|X_PEND) {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4, x6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,574 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <assert.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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_rv64_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;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
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, x5);
|
||||
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(x4);
|
||||
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, x5);
|
||||
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, x6);
|
||||
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(x4);
|
||||
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 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 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
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;
|
||||
GETGXSS(s0);
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
} else {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLW(v0, ed, fixedaddress);
|
||||
}
|
||||
CLEAR_FLAGS();
|
||||
// if isnan(s0) || isnan(v0)
|
||||
IFX(X_ZF | X_PF | X_CF) {
|
||||
FEQS(x3, s0, s0);
|
||||
FEQS(x2, v0, v0);
|
||||
AND(x2, x2, x3);
|
||||
BNE_MARK(x2, xZR);
|
||||
ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX(X_CF) {
|
||||
FLTS(x2, s0, v0);
|
||||
BEQ_MARK2(x2, xZR);
|
||||
ORI(xFlags, xFlags, 1<<F_CF);
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX(X_ZF) {
|
||||
FEQS(x2, s0, v0);
|
||||
CBZ_NEXT(x2);
|
||||
ORI(xFlags, xFlags, 1<<F_ZF);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
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, x5, x6);
|
||||
WBACK;
|
||||
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, x5, x6);
|
||||
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, x5, x6);
|
||||
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, x5);
|
||||
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, x5);
|
||||
GBBACK(x4);
|
||||
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, x5);
|
||||
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, x5);
|
||||
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(x4);
|
||||
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 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 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, x5);
|
||||
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, x5);
|
||||
GBBACK(x5);
|
||||
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, x5);
|
||||
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, x6);
|
||||
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(x4);
|
||||
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 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, x6);
|
||||
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, x6);
|
||||
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, x6);
|
||||
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, x6);
|
||||
break;
|
||||
case 0x3C:
|
||||
INST_NAME("CMP AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
if(u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} 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, x6);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, xRAX, x3, x4);
|
||||
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, x6);
|
||||
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, x5, x6);
|
||||
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, x5);
|
||||
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, x6);
|
||||
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, x6);
|
||||
} 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)>>2);
|
||||
gb1 = xRAX+(gd&3);
|
||||
}
|
||||
gd = x4;
|
||||
if(gb2) {
|
||||
SRLI(x4, gb1, 8);
|
||||
gb1 = x4;
|
||||
}
|
||||
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
|
||||
}
|
||||
ANDI(gd, gb1, 0xff);
|
||||
if(eb2) {
|
||||
MOV64x(x1, 0xffffffffffff00ffLL);
|
||||
AND(x1, eb1, x1);
|
||||
SLLI(gd, gd, 8);
|
||||
OR(eb1, x1, gd);
|
||||
} else {
|
||||
ANDI(x1, eb1, ~0xff);
|
||||
OR(eb1, x1, gd);
|
||||
}
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SB(gb1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MVxw(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SDxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
MVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
}
|
||||
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 = geted32(dyn, addr, ninst, nextop, &ed, gd, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
if(ed!=gd) {
|
||||
AND(gd, ed, xMASK);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_D8(dynarec_rv64_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 ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0 ... 0xC7:
|
||||
|
||||
case 0xC8 ... 0xCF:
|
||||
|
||||
case 0xD0 ... 0xD7:
|
||||
|
||||
case 0xD8 ... 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x1, 0b1110100011111111); // mask off c0,c1,c2,c3
|
||||
AND(x3, x3, x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FEQS(x5, v1, v1);
|
||||
FEQS(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQS(x5, v1, v2);
|
||||
BNEZ(x5, 28); // equal
|
||||
FLTS(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
SLLI(x1, x3, 8);
|
||||
J(20); // end
|
||||
// undefined/NaN
|
||||
LUI(x1, 1);
|
||||
ADDI(x1, x1, 0b010100000000);
|
||||
J(8); // end
|
||||
// equal
|
||||
LUI(x1, 1);
|
||||
// end
|
||||
} else {
|
||||
FEQD(x5, v1, v1);
|
||||
FEQD(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQD(x5, v1, v2);
|
||||
BNEZ(x5, 28); // equal
|
||||
FLTD(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
SLLI(x1, x3, 8);
|
||||
J(20); // end
|
||||
// undefined/NaN
|
||||
LUI(x1, 1);
|
||||
ADDI(x1, x1, 0b010100000000);
|
||||
J(8); // end
|
||||
// equal
|
||||
LUI(x1, 1);
|
||||
// end
|
||||
}
|
||||
OR(x3, x3, x1);
|
||||
SH(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0 ... 0xE7:
|
||||
INST_NAME("FSUB 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)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xE8 ... 0xEF:
|
||||
|
||||
case 0xF0 ... 0xF7:
|
||||
INST_NAME("FDIV 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)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xF8 ... 0xFF:
|
||||
DEFAULT;
|
||||
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, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLW(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
FCVTDS(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
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, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLW(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
FCVTDS(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
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, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLW(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVTDS(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
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, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLW(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
FCVTDS(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_D9(dynarec_rv64_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 ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v0, v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v2 = x87_do_push(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)) {
|
||||
FMVS(v2, v1);
|
||||
} else {
|
||||
FMVD(v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("FXCH ST0");
|
||||
break;
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
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;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("FNOP");
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
INST_NAME("FSTPNCE ST0, ST0");
|
||||
x87_do_pop(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_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
INST_NAME("FCHS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
FNEGS(v1, v1);
|
||||
} else {
|
||||
FNEGD(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
FABSS(v1, v1);
|
||||
} else {
|
||||
FABSD(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
INST_NAME("FTST");
|
||||
DEFAULT
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1); // should be possible inline, but is it worth it?
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32w(x1, 0x3f800000);
|
||||
FMVWX(v1, x1);
|
||||
} else {
|
||||
MOV64x(x1, 0x3FF0000000000000);
|
||||
FMVDX(v1, x1);
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
FTABLE64(v1, L2T);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
FTABLE64(v1, L2E);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
FTABLE64(v1, PI);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
FTABLE64(v1, LG2);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
FTABLE64(v1, LN2);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMVWX(v1, xZR);
|
||||
} else {
|
||||
FMVDX(v1, xZR);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_f2xm1, -1);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fyl2x, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_ftan, -1);
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32w(x1, 0x3f800000);
|
||||
FMVWX(v1, x1);
|
||||
} else {
|
||||
MOV64x(x1, 0x3FF0000000000000);
|
||||
FMVDX(v1, x1);
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fpatan, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fxtract, -1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fprem1, -1);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
LW(x2, xEmu, offsetof(x64emu_t, top));
|
||||
SUBI(x2, x2, 1);
|
||||
ANDI(x2, x2, 7);
|
||||
SW(x2, xEmu, offsetof(x64emu_t, top));
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
LW(x2, xEmu, offsetof(x64emu_t, top));
|
||||
ADDI(x2, x2, 1);
|
||||
ANDI(x2, x2, 7);
|
||||
SW(x2, xEmu, offsetof(x64emu_t, top));
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fprem, -1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fyl2xp1, -1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
FSQRTS(v1, v1);
|
||||
} else {
|
||||
FSQRTD(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fsincos, -1);
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
v0 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2);
|
||||
|
||||
if(ST_IS_F(0)) {
|
||||
FEQS(x2, v0, v0);
|
||||
BNEZ_MARK(x2);
|
||||
B_NEXT_nocond;
|
||||
MARK; // v0 is not nan
|
||||
FABSS(v1, v0);
|
||||
MOV64x(x3, 1ULL << __FLT_MANT_DIG__);
|
||||
FCVTSL(v2, x3, RD_RTZ);
|
||||
FLTS(x3, v1, v2);
|
||||
BNEZ_MARK2(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK2;
|
||||
FCVTLS(x3, v0, RD_DYN);
|
||||
FCVTSL(v1, x3, RD_DYN);
|
||||
FSGNJS(v0, v1, v0);
|
||||
} else {
|
||||
FEQD(x2, v0, v0);
|
||||
BNEZ_MARK(x2);
|
||||
B_NEXT_nocond;
|
||||
MARK; // v0 is not nan
|
||||
FABSD(v1, v0);
|
||||
MOV64x(x3, 1ULL << __DBL_MANT_DIG__);
|
||||
FCVTDL(v2, x3, RD_RTZ);
|
||||
FLTD(x3, v1, v2);
|
||||
BNEZ_MARK2(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK2;
|
||||
FCVTLD(x3, v0, RD_DYN);
|
||||
FCVTDL(v1, x3, RD_DYN);
|
||||
FSGNJD(v0, v1, v0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fscale, -1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_fsin, -1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_fcos, -1);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
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?EXT_CACHE_ST_D:EXT_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLW(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVTDS(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVTSD(s0, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FSW(s0, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVTSD(v1, v1);
|
||||
}
|
||||
FSW(v1, ed, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MV(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
SH(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
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, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MV(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LH(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DB(dynarec_rv64_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 ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
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:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVNB ST0, STx");
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
ANDI(x1, xFlags, 1<<F_CF);
|
||||
CBNZ_NEXT(x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FMVS(v1, v2);
|
||||
} else {
|
||||
FMVD(v1, v2); // F_CF==0
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVNE ST0, STx");
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
ANDI(x1, xFlags, 1<<F_ZF);
|
||||
CBNZ_NEXT(x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FMVS(v1, v2);
|
||||
} else {
|
||||
FMVD(v1, v2); // F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVNBE ST0, STx");
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
ANDI(x1, xFlags, (1<<F_CF)|(1<<F_ZF));
|
||||
CBNZ_NEXT(x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FMVS(v1, v2);
|
||||
} else {
|
||||
FMVD(v1, v2); // F_CF==0 & F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVNU ST0, STx");
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
ANDI(x1, xFlags, 1<<F_PF);
|
||||
CBNZ_NEXT(x1);
|
||||
if(ST_IS_F(0)) {
|
||||
FMVS(v1, v2);
|
||||
} else {
|
||||
FMVD(v1, v2); // F_PF==0
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FDISI8087_NOP"); // so.. NOP?
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LH(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
ANDI(x2, x2, ~(0xff)); // IE .. PE, SF, ES
|
||||
MOV32w(x1, ~(1<<15)); // B
|
||||
AND(x2, x2, x1);
|
||||
SH(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("FNINIT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
CALL(reset_fpu, -1);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
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));
|
||||
IFX(F_ZF | F_PF | F_CF) {
|
||||
if(ST_IS_F(0)) {
|
||||
FEQS(x5, v1, v1);
|
||||
FEQS(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQS(x5, v1, v2);
|
||||
BNEZ(x5, 24); // equal
|
||||
FLTS(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
OR(xFlags, xFlags, x3); // CF is the least significant bit
|
||||
J(16); // end
|
||||
// NaN
|
||||
ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
|
||||
J(8); // end
|
||||
// equal
|
||||
ORI(xFlags, xFlags, 1<<F_ZF);
|
||||
// end
|
||||
} else {
|
||||
FEQD(x5, v1, v1);
|
||||
FEQD(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQD(x5, v1, v2);
|
||||
BNEZ(x5, 24); // equal
|
||||
FLTD(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
OR(xFlags, xFlags, x3); // CF is the least significant bit
|
||||
J(16); // end
|
||||
// NaN
|
||||
ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
|
||||
J(8); // end
|
||||
// equal
|
||||
ORI(xFlags, xFlags, 1<<F_ZF);
|
||||
// end
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LW(x1, ed, fixedaddress);
|
||||
FCVTDW(v1, x1, RD_RNE); // i32 -> double
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FSFLAGSI(0); // reset all bits
|
||||
}
|
||||
FCVTWD(x4, v1, RD_DYN);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FRFLAGS(x5); // get back FPSR to check the IOC bit
|
||||
ANDI(x5, x5, 1<<FR_NV);
|
||||
BEQ_MARK2(x5, xZR);
|
||||
MOV32w(x4, 0x80000000);
|
||||
}
|
||||
MARK2;
|
||||
SW(x4, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 8, 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
|
||||
LD(x5, ed, fixedaddress+0);
|
||||
LH(x6, ed, fixedaddress+8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
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, x2, &fixedaddress, rex, NULL, 8, 0);
|
||||
SD(x5, ed, fixedaddress+0);
|
||||
SH(x6, ed, fixedaddress+8);
|
||||
} else {
|
||||
if(box64_x87_no80bits) {
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
FLD(v1, ed, fixedaddress);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MV(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(native_fld, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
if(box64_x87_no80bits) {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FSD(v1, wback, fixedaddress);
|
||||
} else {
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MV(x1, ed);
|
||||
}
|
||||
CALL(native_fstp, -1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DC(dynarec_rv64_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 ... 0xC7:
|
||||
INST_NAME("FADD STx, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xC8 ... 0xCF:
|
||||
INST_NAME("FMUL STx, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xD0 ... 0xD7:
|
||||
INST_NAME("FCOM ST0, STx"); //yep
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xD8 ... 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xE0 ... 0xE7:
|
||||
INST_NAME("FSUBR STx, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
break;
|
||||
case 0xE8 ... 0xEF:
|
||||
INST_NAME("FSUB STx, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xF0 ... 0xF7:
|
||||
INST_NAME("FDIVR STx, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xF8 ... 0xFF:
|
||||
INST_NAME("FDIV STx, ST0");
|
||||
DEFAULT;
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLD(v2, wback, fixedaddress);
|
||||
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x1, 0b1110100011111111); // mask off c0,c1,c2,c3
|
||||
AND(x3, x3, x1);
|
||||
FEQD(x5, v1, v1);
|
||||
FEQD(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQD(x5, v1, v2);
|
||||
BNEZ(x5, 28); // equal
|
||||
FLTD(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
SLLI(x1, x3, 8);
|
||||
J(20); // end
|
||||
// undefined/NaN
|
||||
LUI(x1, 1);
|
||||
ADDI(x1, x1, 0b010100000000);
|
||||
J(8); // end
|
||||
// equal
|
||||
LUI(x1, 1);
|
||||
// end
|
||||
OR(x3, x3, x1);
|
||||
SH(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLD(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DD(dynarec_rv64_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 ed, wback;
|
||||
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:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOV32w(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FST ST0, STx");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
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);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FUCOM ST0, STx");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMP ST0, STx");
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLD(v1, wback, fixedaddress);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FSD(v1, wback, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FSD(v1, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x6, &fixedaddress, rex, NULL, 0, 0);
|
||||
LWU(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
if(dyn->e.x87stack) {
|
||||
// update top
|
||||
ADDI(x2, x2, -dyn->e.x87stack);
|
||||
ANDI(x2, x2, 7);
|
||||
}
|
||||
MOV32w(x5, ~0x3800);
|
||||
AND(x3, x3, x5); // mask out TOP
|
||||
SLLI(x2, x2, 11); // shift TOP to bit 11
|
||||
OR(x3, x3, x2); // inject TOP
|
||||
SH(x3, ed, fixedaddress); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_DE(dynarec_rv64_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 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_do_pop(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_do_pop(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
|
||||
DEFAULT;
|
||||
break;
|
||||
case 0xD9:
|
||||
// INST_NAME("FCOMPP ST0, STx");
|
||||
DEFAULT;
|
||||
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_do_pop(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_do_pop(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_do_pop(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_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_DF(dynarec_rv64_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 ed, wback, u8;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0 ... 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LHU(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x3, 0b1100011111111111); // mask
|
||||
AND(x1, x1, x3);
|
||||
SLLI(x2, x2, 11);
|
||||
OR(x1, x1, x2); // inject top
|
||||
SH(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
SRLI(xRAX, xRAX, 16);
|
||||
SLLI(xRAX, xRAX, 16);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0xE8 ... 0xF7:
|
||||
if (nextop < 0xF0) {
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
} else {
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
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));
|
||||
CLEAR_FLAGS();
|
||||
IFX(F_ZF | F_PF | F_CF) {
|
||||
if(ST_IS_F(0)) {
|
||||
FEQS(x5, v1, v1);
|
||||
FEQS(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQS(x5, v1, v2);
|
||||
BNEZ(x5, 24); // equal
|
||||
FLTS(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
OR(xFlags, xFlags, x3); // CF is the least significant bit
|
||||
J(16); // end
|
||||
// NaN
|
||||
ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
|
||||
J(8); // end
|
||||
// equal
|
||||
ORI(xFlags, xFlags, 1<<F_ZF);
|
||||
// end
|
||||
} else {
|
||||
FEQD(x5, v1, v1);
|
||||
FEQD(x4, v2, v2);
|
||||
AND(x5, x5, x4);
|
||||
BEQZ(x5, 24); // undefined/NaN
|
||||
FEQD(x5, v1, v2);
|
||||
BNEZ(x5, 24); // equal
|
||||
FLTD(x3, v1, v2); // x3 = (v1<v2)?1:0
|
||||
OR(xFlags, xFlags, x3); // CF is the least significant bit
|
||||
J(16); // end
|
||||
// NaN
|
||||
ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
|
||||
J(8); // end
|
||||
// equal
|
||||
ORI(xFlags, xFlags, 1<<F_ZF);
|
||||
// end
|
||||
}
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8 ... 0xDF:
|
||||
case 0xE1 ... 0xE7:
|
||||
case 0xF8 ... 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x4, &fixedaddress, rex, NULL, 1, 0);
|
||||
LH(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCVTSL(v1, x1, RD_RNE);
|
||||
} else {
|
||||
FCVTDL(v1, x1, RD_RNE);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x4, &fixedaddress, rex, NULL, 1, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FSFLAGSI(0); // reset all bits
|
||||
}
|
||||
FCVTWD(x4, v1, RD_RTZ);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FRFLAGS(x5); // get back FPSR to check the IOC bit
|
||||
ANDI(x5, x5, 1<<FR_NV);
|
||||
BNEZ_MARK(x5);
|
||||
SLLIW(x5, x4, 16);
|
||||
SRAIW(x5, x5, 16);
|
||||
BEQ_MARK2(x5, x4);
|
||||
MARK;
|
||||
MOV32w(x4, 0x8000);
|
||||
}
|
||||
MARK2;
|
||||
SH(x4, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FSFLAGSI(0); // reset all bits
|
||||
}
|
||||
FCVTWD(x4, v1, RD_DYN);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FRFLAGS(x5); // get back FPSR to check the IOC bit
|
||||
ANDI(x5, x5, 1<<FR_NV);
|
||||
BNEZ_MARK(x5);
|
||||
SLLIW(x5, x4, 16);
|
||||
SRAIW(x5, x5, 16);
|
||||
BEQ_MARK2(x5, x4);
|
||||
MARK;
|
||||
MOV32w(x4, 0x8000);
|
||||
}
|
||||
MARK2;
|
||||
SH(x4, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
v1 = x87_do_push(dyn, ninst, x1, EXT_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD(x1, wback, fixedaddress);
|
||||
if (rex.is32bits) {
|
||||
// need to also feed the STll stuff...
|
||||
ADDI(x4, xEmu, offsetof(x64emu_t, fpu_ll));
|
||||
LWU(x5, xEmu, offsetof(x64emu_t, top));
|
||||
int a = 0 - dyn->e.x87stack;
|
||||
if(a) {
|
||||
ADDIW(x5, x5, a);
|
||||
ANDI(x5, x5, 0x7);
|
||||
}
|
||||
SLLI(x5, x5, 4); // fpu_ll is 2 i64
|
||||
ADD(x5, x5, x4);
|
||||
SD(x1, x5, 8); // ll
|
||||
}
|
||||
FCVTDL(v1, x1, RD_RTZ);
|
||||
if(rex.is32bits) {
|
||||
FSD(v1, x5, 0); // ref
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
|
||||
if(rex.is32bits) {
|
||||
// need to check STll first...
|
||||
ADDI(x4, xEmu, offsetof(x64emu_t, fpu_ll));
|
||||
LWU(x5, xEmu, offsetof(x64emu_t, top));
|
||||
int a = 0 - dyn->e.x87stack;
|
||||
if(a) {
|
||||
ADDIW(x5, x5, a);
|
||||
ANDI(x5, x5, 0x7);
|
||||
}
|
||||
SLLI(x5, x5, 4); // fpu_ll is 2 i64
|
||||
ADD(x5, x5, x4);
|
||||
FMVXD(x3, v1);
|
||||
LD(x6, x5, 0); // ref
|
||||
BNE_MARK(x6, x3);
|
||||
LD(x6, x5, 8); // ll
|
||||
SD(x6, wback, fixedaddress);
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
}
|
||||
|
||||
if(!box64_dynarec_fastround) {
|
||||
FSFLAGSI(0); // reset all bits
|
||||
}
|
||||
FCVTLD(x4, v1, RD_DYN);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FRFLAGS(x5); // get back FPSR to check the IOC bit
|
||||
ANDI(x5, x5, 1<<FR_NV);
|
||||
BEQ_MARK2(x5, xZR);
|
||||
MOV64x(x4, 0x8000000000000000LL);
|
||||
}
|
||||
MARK2;
|
||||
SD(x4, wback, fixedaddress);
|
||||
MARK3;
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
#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 "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
// emit XOR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
XOR(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SB(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
XORI(s1, s1, c&0xff);
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SB(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
XOR(s1, s1, s2);
|
||||
|
||||
// test sign bit before zeroup.
|
||||
IFX(X_SF) {
|
||||
if (!rex.w) SEXT_W(s1, s1);
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w && s1!=s2) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if(c>=-2048 && c<=2047) {
|
||||
XORI(s1, s1, c);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
XOR(s1, s1, s3);
|
||||
}
|
||||
|
||||
// test sign bit before zeroup.
|
||||
IFX(X_SF) {
|
||||
if (!rex.w) SEXT_W(s1, s1);
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
XOR(s1, s1, s2);
|
||||
ZEXTH(s1, s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SH(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF | X_SF) {
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4) {
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
ZEXTH(s1, s1);
|
||||
IFX(X_PEND) {
|
||||
SD(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
|
||||
// test sign bit before zeroup.
|
||||
IFX(X_SF) {
|
||||
if (!rex.w) SEXT_W(s1, s1);
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit OR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if(c>=-2048 && c<=2047) {
|
||||
ORI(s1, s1, c);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
OR(s1, s1, s3);
|
||||
}
|
||||
|
||||
// test sign bit before zeroup.
|
||||
IFX(X_SF) {
|
||||
if (!rex.w) SEXT_W(s1, s1);
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit AND8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
AND(s1, s1, s2);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SB(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
ANDI(s1, s1, c&0xff);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SD(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_and16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4) {
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
AND(s1, s1, s2); // res = s1 & s2
|
||||
|
||||
IFX(X_PEND) {
|
||||
SH(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
AND(s1, s1, s2); // res = s1 & s2
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, rex.w?63:31);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if(c>=-2048 && c<=2047) {
|
||||
ANDI(s1, s1, c);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
AND(s1, s1, s3); // res = s1 & s2
|
||||
}
|
||||
if (!rex.w && c<0 && c>=-2048) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, rex.w?63:31);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SB(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4)
|
||||
{
|
||||
MOV32w(s2, c&0xff);
|
||||
emit_or8(dyn, ninst, s1, s2, s3, s4);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Loaded 100 of 975 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user