mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 04:09:46 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8545d0505f | ||
|
|
28b101aaf7 | ||
|
|
24d1250e66 | ||
|
|
706ca3649e | ||
|
|
bb537e4dd5 | ||
|
|
eb59ff2ebd | ||
|
|
7842c9e34d | ||
|
|
3882a98755 | ||
|
|
14c9dc5bdb | ||
|
|
181457b69f | ||
|
|
0b6f543bbd | ||
|
|
01a386445c | ||
|
|
3fce669f6e | ||
|
|
8a701755d8 | ||
|
|
aead503f02 | ||
|
|
7ef2af2549 | ||
|
|
1e44a93c87 | ||
|
|
2e55dec949 | ||
|
|
c80a83485d | ||
|
|
8915484251 | ||
|
|
ed3450388b | ||
|
|
a2d580e926 | ||
|
|
47085bb9c9 | ||
|
|
73619f4d75 | ||
|
|
5228338f97 | ||
|
|
71c0aff78f | ||
|
|
4d7e106088 | ||
|
|
d7127ccc3d | ||
|
|
04e960b0da | ||
|
|
8d199cfc6c | ||
|
|
ffa58e23f1 | ||
|
|
289f94599d | ||
|
|
d0b51ae18f | ||
|
|
cea459d1e3 | ||
|
|
f6cd825ab9 | ||
|
|
f8fa438728 | ||
|
|
07aacc9b08 | ||
|
|
50325785f5 | ||
|
|
ef49b97c75 | ||
|
|
75110ac028 | ||
|
|
57bfa38328 | ||
|
|
2c00386e99 | ||
|
|
3b03b7aee6 | ||
|
|
1491270f1d | ||
|
|
46dfaab639 | ||
|
|
ff755facc0 | ||
|
|
d38f659f42 | ||
|
|
6d95a64412 | ||
|
|
21336c527a | ||
|
|
3db2362c86 | ||
|
|
99b7ef0c92 | ||
|
|
ff030fcbec | ||
|
|
ecf19029f5 | ||
|
|
9494801d0b | ||
|
|
1501592fa8 | ||
|
|
12467916a4 | ||
|
|
6f0eb56621 | ||
|
|
31dabf51ae | ||
|
|
22fd100b04 | ||
|
|
20092ef1ac | ||
|
|
aad6a16984 | ||
|
|
9b00df93c2 | ||
|
|
f1da71a8fe | ||
|
|
efd182971a | ||
|
|
40c5125a92 | ||
|
|
0f6654bf95 | ||
|
|
fa27ddecc5 | ||
|
|
e5be67b005 | ||
|
|
85458d1f20 | ||
|
|
5b5723c5a5 | ||
|
|
e148e89091 | ||
|
|
1d0614f0f3 | ||
|
|
2405e6c8e8 | ||
|
|
817408d247 | ||
|
|
8d77e39f4a | ||
|
|
0fe7e7a88d | ||
|
|
08bc57045a | ||
|
|
ee58b6a734 | ||
|
|
2907e5a0bd | ||
|
|
4f229629c0 | ||
|
|
f0fd2bc30c | ||
|
|
86e9a38384 | ||
|
|
322f97ddbc | ||
|
|
695865f408 | ||
|
|
1f9834dc6b | ||
|
|
d1555a4c78 | ||
|
|
5fc4477a94 | ||
|
|
a5753ec0b5 | ||
|
|
f256c48505 | ||
|
|
71c5447b8a | ||
|
|
a9a338ff42 | ||
|
|
06a21d490b | ||
|
|
ef0c9bd429 | ||
|
|
f619df2773 | ||
|
|
41ae74757e | ||
|
|
2304738336 | ||
|
|
e70a9ba485 | ||
|
|
61a759f802 | ||
|
|
3cb61ff840 | ||
|
|
b7a07c3816 | ||
|
|
ae386b3a7d | ||
|
|
2b8a8314c5 | ||
|
|
eb28edbe58 | ||
|
|
8d683fc19c | ||
|
|
0c50f724e6 | ||
|
|
d406946c2d | ||
|
|
1c7e620a86 | ||
|
|
c40096e128 | ||
|
|
43d2817407 | ||
|
|
ff14ccc0a5 | ||
|
|
1222fee0d0 | ||
|
|
b184a184c4 | ||
|
|
e5dcb3f100 | ||
|
|
411fe19ee5 | ||
|
|
1c040117ec | ||
|
|
856d2653bc | ||
|
|
2a79b60454 | ||
|
|
db32e49879 | ||
|
|
65d83bb6f4 | ||
|
|
17b7ec6358 | ||
|
|
73c3190c86 | ||
|
|
b6f58caf24 | ||
|
|
8c19c3a72c | ||
|
|
c017d3e894 | ||
|
|
35696508fb | ||
|
|
7e3996b0d9 | ||
|
|
a7ec8e7c55 | ||
|
|
dfaa6896c1 | ||
|
|
b64e6bdbba | ||
|
|
e0ef248943 | ||
|
|
cdcb0a46dc | ||
|
|
e82e1f9905 | ||
|
|
cb6616bba1 | ||
|
|
e0f0afdf91 | ||
|
|
5120e74b36 | ||
|
|
8f5fa863bf | ||
|
|
d4e32fdbc0 | ||
|
|
067cf75c65 | ||
|
|
7f16ddacf7 | ||
|
|
d936c072ea | ||
|
|
7dee075c10 | ||
|
|
b9ea2408c2 | ||
|
|
6ce570f4a5 | ||
|
|
b95b99b3c9 | ||
|
|
139197230d | ||
|
|
1d0e0307c4 | ||
|
|
f94ab1be6f | ||
|
|
05c7596acb | ||
|
|
b38d51ce37 | ||
|
|
5c0d765f59 | ||
|
|
db35542706 | ||
|
|
eda857cb10 | ||
|
|
b77c8fe5f1 | ||
|
|
0d864ed848 | ||
|
|
7c613198ce | ||
|
|
1ca68a58fd | ||
|
|
b96139274f | ||
|
|
d84faf57ab | ||
|
|
89f0c494e4 | ||
|
|
24f9263fa4 | ||
|
|
5f4f9337cd | ||
|
|
2a75d28386 | ||
|
|
3e41289167 | ||
|
|
9cf5373724 | ||
|
|
6c5d35df6b | ||
|
|
4d26021705 | ||
|
|
2e9b8eff59 | ||
|
|
a4142f68ce | ||
|
|
4a889e39ad | ||
|
|
d206d69b25 | ||
|
|
83e92d6298 | ||
|
|
e080551d54 | ||
|
|
b40195d26d | ||
|
|
316abec693 | ||
|
|
af685a263b | ||
|
|
31e8afa622 | ||
|
|
1d500ad965 | ||
|
|
a8866c3f41 | ||
|
|
f64eca5d9b | ||
|
|
bdd5e7018a | ||
|
|
3d211143e0 | ||
|
|
c1c11d8daa | ||
|
|
0505b19378 | ||
|
|
e18e532846 | ||
|
|
10cec3de2f | ||
|
|
76c0992d02 | ||
|
|
e32a78a944 | ||
|
|
68d710cd94 | ||
|
|
da64a3eeab | ||
|
|
912622bf1f | ||
|
|
70fec208d8 | ||
|
|
e1f69b9c61 | ||
|
|
81f25b219f | ||
|
|
d191b8c090 | ||
|
|
d53ff127ed | ||
|
|
50caca8fdc | ||
|
|
1dca97b4d3 | ||
|
|
14cf474167 | ||
|
|
47b1203805 | ||
|
|
81ca016581 | ||
|
|
cd8bda7a29 | ||
|
|
8115b47051 | ||
|
|
6384cc6e86 | ||
|
|
2f68df2b5f | ||
|
|
ed2697d6ad | ||
|
|
df928fd2d0 | ||
|
|
52c50a2fd4 | ||
|
|
666d051806 | ||
|
|
1e80316a7d | ||
|
|
65404cba33 | ||
|
|
ac0519a046 | ||
|
|
90a6306bbe | ||
|
|
a5a7d9382e | ||
|
|
bc770d908a | ||
|
|
20724ceb17 | ||
|
|
6ae6ac0272 | ||
|
|
5aa5015348 | ||
|
|
411aecde6f | ||
|
|
e89b93285e | ||
|
|
4e702cfeda | ||
|
|
33846405d8 | ||
|
|
378eb79ad3 | ||
|
|
da71b81d01 | ||
|
|
35d734e6ac | ||
|
|
3937fc4b71 | ||
|
|
5debac4c98 | ||
|
|
3737abe081 | ||
|
|
d0013c0700 | ||
|
|
460277289b | ||
|
|
35ed305718 | ||
|
|
d3c57eecbc | ||
|
|
ad75da8502 | ||
|
|
c7c6880a01 | ||
|
|
5ed3ef918d | ||
|
|
c0f78342e1 | ||
|
|
75494978ad | ||
|
|
602c015321 | ||
|
|
55c2c9ee59 | ||
|
|
8fef5f2c69 | ||
|
|
9a4a62ff2d | ||
|
|
4ebc462e23 | ||
|
|
08e93a0fe9 | ||
|
|
4096869c50 | ||
|
|
3cd87e68c7 | ||
|
|
7165ff7b84 | ||
|
|
81d906fd3b | ||
|
|
b51bdf3d5e | ||
|
|
c8ca7876c3 | ||
|
|
c181a6dcc8 | ||
|
|
b763c22ef4 | ||
|
|
5c83475c95 | ||
|
|
1d1670864b | ||
|
|
5e980767b9 | ||
|
|
2b3c9b95af | ||
|
|
09232ad0b6 | ||
|
|
2533197a3c | ||
|
|
71c43b0de7 | ||
|
|
6606b7b097 | ||
|
|
5c994ff222 | ||
|
|
9372b96e47 | ||
|
|
24e133e006 | ||
|
|
995fa013a6 | ||
|
|
4af1f56713 | ||
|
|
584b258241 | ||
|
|
fb13ce2baf | ||
|
|
f910a70c8a | ||
|
|
fedb8bd816 | ||
|
|
c3f97dd730 | ||
|
|
b1ebf9dc79 | ||
|
|
d07ea96570 | ||
|
|
dc3bdd89c1 | ||
|
|
7e92c912b2 | ||
|
|
5d5c3aec3c | ||
|
|
0ba63ea272 | ||
|
|
a242a8e277 | ||
|
|
cc86e94cd5 | ||
|
|
1c10ae443d | ||
|
|
d44f3d9bae | ||
|
|
d71e5f968a | ||
|
|
4aa9fba4fa | ||
|
|
8aaaddde03 | ||
|
|
d5176ba278 | ||
|
|
13a8108e1e | ||
|
|
82b19f6f69 | ||
|
|
9e37dd008d | ||
|
|
5b1057fe08 | ||
|
|
460fa3f3d7 | ||
|
|
61de3532c2 | ||
|
|
ddfc699809 | ||
|
|
d0edf2e8dd | ||
|
|
a159cb5efe | ||
|
|
26371bb9dd | ||
|
|
de4ffcc8bc | ||
|
|
ebaedca708 | ||
|
|
a86f597239 | ||
|
|
b72d3a77e9 | ||
|
|
64fdf54156 | ||
|
|
463e31251f | ||
|
|
9032f24a56 | ||
|
|
c5828803c6 | ||
|
|
9883c6464e | ||
|
|
67006f2809 | ||
|
|
e49728aa82 | ||
|
|
829c254b1f | ||
|
|
8bf54eda56 | ||
|
|
c58adce8f6 | ||
|
|
92532b0fd1 | ||
|
|
8cba5d55ce | ||
|
|
da1ac7beee | ||
|
|
28b79626d9 | ||
|
|
867059dfae | ||
|
|
50250bd2ca | ||
|
|
0e71c3a2ac | ||
|
|
db01a92edf | ||
|
|
6a9836912d | ||
|
|
bdcfd69795 | ||
|
|
dbe1bb0ec4 | ||
|
|
d76841bdc1 | ||
|
|
0251a29841 | ||
|
|
32b0c173f0 | ||
|
|
90167afc2b | ||
|
|
6a4a58185e | ||
|
|
6cffabacb3 | ||
|
|
d658c47cd0 | ||
|
|
21b06ace43 | ||
|
|
7a27b95df7 | ||
|
|
a730935e6e | ||
|
|
ef705ed494 | ||
|
|
fb6915b059 | ||
|
|
20d675ea48 | ||
|
|
900dbc2a47 | ||
|
|
d8affd8564 | ||
|
|
f3d4a1e1c3 | ||
|
|
d5ebea7928 | ||
|
|
bd95c7a366 | ||
|
|
20fc160230 | ||
|
|
c786e6d576 | ||
|
|
e9ce6a4f80 | ||
|
|
0024e4b970 | ||
|
|
cf8ea5953e | ||
|
|
65ddcdeabb | ||
|
|
6576686b36 | ||
|
|
13404ed090 | ||
|
|
ff6cc84482 | ||
|
|
02caee0c02 | ||
|
|
7260da63af | ||
|
|
ec0d333d81 | ||
|
|
d3eb6b8a11 | ||
|
|
cc0ce73d39 | ||
|
|
2eb92951af | ||
|
|
f8202096f1 | ||
|
|
f470d552cf | ||
|
|
be50bbc149 | ||
|
|
50c49a1692 | ||
|
|
70496c9bde | ||
|
|
f7f7c1c9af | ||
|
|
f02d5fc28f | ||
|
|
422a982917 | ||
|
|
ce60a8cfa2 | ||
|
|
f0026927e3 | ||
|
|
d1388dd7eb | ||
|
|
ffda782c3d | ||
|
|
3a6df996dc | ||
|
|
6141376977 | ||
|
|
3ec2ebabfc | ||
|
|
77dcb025fd | ||
|
|
bbaa01af79 | ||
|
|
d033f34a45 | ||
|
|
f2eb5326af | ||
|
|
f09b541ab7 | ||
|
|
e71df7eb67 | ||
|
|
9d1e6b9b96 | ||
|
|
0d43b16fd5 | ||
|
|
b179bd2415 | ||
|
|
64fbd3db46 | ||
|
|
ea096cd593 | ||
|
|
7934e3ad5c | ||
|
|
52a5335770 | ||
|
|
f3d1ffbe01 | ||
|
|
b40a17fc51 | ||
|
|
02fadef9e7 | ||
|
|
6e4d2470d2 | ||
|
|
8e4faa3de2 | ||
|
|
4f3b9f19a7 | ||
|
|
e562baf30b | ||
|
|
efefd13bf5 | ||
|
|
4314ef1ca8 | ||
|
|
477e531af9 | ||
|
|
47b8e2a983 | ||
|
|
cc01018223 | ||
|
|
7a28084b63 | ||
|
|
ea86b0e32f | ||
|
|
96169af71e | ||
|
|
4633817374 | ||
|
|
a190910cbf | ||
|
|
6170fc8e43 | ||
|
|
aa279c332d | ||
|
|
a79e1be034 | ||
|
|
5924a8eca1 | ||
|
|
fc920b0838 | ||
|
|
e33d51641f | ||
|
|
4b979bf206 | ||
|
|
bc5afbea89 | ||
|
|
65f75b0cc0 | ||
|
|
c50b0ef9e8 | ||
|
|
10c479034f | ||
|
|
3c95826c5c | ||
|
|
fa11368599 | ||
|
|
f4fd01c777 | ||
|
|
96941c9978 | ||
|
|
c5a6875de9 | ||
|
|
549e042e67 | ||
|
|
c70581abc9 | ||
|
|
5e6af37532 | ||
|
|
c0184f926d | ||
|
|
a69e81f034 | ||
|
|
5c01fbabac | ||
|
|
fed47bea4a | ||
|
|
213c063895 | ||
|
|
632af46137 | ||
|
|
b527ebbf5b | ||
|
|
ad55cfde7f | ||
|
|
44e77de620 | ||
|
|
40de8e16ec | ||
|
|
d36f9e4dbb | ||
|
|
a65f448856 | ||
|
|
8cba593882 | ||
|
|
0715dd145f | ||
|
|
5a20322251 | ||
|
|
89b5e1163d | ||
|
|
6a9dbe3d89 | ||
|
|
8e6ae3aa01 | ||
|
|
e46707750b | ||
|
|
b1f6ea8ae6 | ||
|
|
82ae65f477 | ||
|
|
4a3595133a | ||
|
|
4c9a6a5d98 | ||
|
|
a2e01c36ba | ||
|
|
774d872f41 | ||
|
|
fa19435d24 | ||
|
|
902186bdff | ||
|
|
6996c06909 | ||
|
|
315068b111 | ||
|
|
4047d1ba3c | ||
|
|
d74bee3596 | ||
|
|
aea1049223 | ||
|
|
3548195fbe | ||
|
|
8d0cc15eb0 | ||
|
|
ee2580a57f | ||
|
|
255d5c661e | ||
|
|
a60d945968 | ||
|
|
f8fa53aa3b | ||
|
|
1642327015 | ||
|
|
399478d635 | ||
|
|
608c13ebba | ||
|
|
99694d67ca | ||
|
|
bde279f2fa | ||
|
|
e4f56f0b23 | ||
|
|
3e8da0cc1a | ||
|
|
ca0e12d93f | ||
|
|
0c41d9810f | ||
|
|
165961f27e | ||
|
|
81386b7a56 | ||
|
|
5bf2a7d51b | ||
|
|
3fa527b45b | ||
|
|
121d986b11 | ||
|
|
f18f5c9b85 | ||
|
|
d5808f6be3 | ||
|
|
2984d30118 | ||
|
|
efbb5a2ae5 | ||
|
|
31aafe23b7 | ||
|
|
09779e294c | ||
|
|
2fe872de3d | ||
|
|
153d8d2cf0 | ||
|
|
1b07a10b5d | ||
|
|
d743c8235f | ||
|
|
7781bfcbac | ||
|
|
0fd81e067f | ||
|
|
acc2f2e3d5 | ||
|
|
a2be60cce8 | ||
|
|
1344b18379 | ||
|
|
1deec05f3d | ||
|
|
2ee5bcf933 | ||
|
|
5f57de017c | ||
|
|
508a153973 | ||
|
|
5d8b70cc0d | ||
|
|
d60ba04cf4 | ||
|
|
8b3949497a | ||
|
|
754b69f746 | ||
|
|
55c99e9ad7 | ||
|
|
aa2e212480 | ||
|
|
96c6abc889 | ||
|
|
74a73dfc97 | ||
|
|
d3b5553433 | ||
|
|
b8856af18c | ||
|
|
63428d0b2e | ||
|
|
22afd245a8 | ||
|
|
26fdf2275a | ||
|
|
1ad38124df | ||
|
|
aaa4fd1265 | ||
|
|
9793c3b142 | ||
|
|
5a753761dd | ||
|
|
37be26e539 | ||
|
|
96023f2274 | ||
|
|
30b83f4f9c | ||
|
|
265f969a44 | ||
|
|
d5b182cac0 | ||
|
|
ce296f0e32 | ||
|
|
6d5c3489c9 | ||
|
|
d48ab49437 | ||
|
|
8ee250e9ac | ||
|
|
e485fe1d18 | ||
|
|
35a32481c6 | ||
|
|
beaf543012 | ||
|
|
c40e31f374 | ||
|
|
f9c09293bf | ||
|
|
cdffe2388e | ||
|
|
6c0af2dbb9 | ||
|
|
eee428afe5 | ||
|
|
047815c764 | ||
|
|
3b8e0d69a3 | ||
|
|
56f2749da0 | ||
|
|
7d85753350 | ||
|
|
367363a8bd | ||
|
|
30d0836329 | ||
|
|
1680dc63d9 | ||
|
|
806298843f | ||
|
|
7cee4e2453 | ||
|
|
82f21de83e | ||
|
|
65c4f9d9c3 | ||
|
|
8043f53d7d | ||
|
|
124672b811 | ||
|
|
28ef6cdefc | ||
|
|
5e38ea28b6 | ||
|
|
1d0d7e9e09 | ||
|
|
aab6bc0869 | ||
|
|
77213bee1d | ||
|
|
90fc1d93ad | ||
|
|
e51f36c651 | ||
|
|
fc63442ded | ||
|
|
0ee5174e18 | ||
|
|
0004f19325 | ||
|
|
da724e3dd5 | ||
|
|
96ccf0dab9 | ||
|
|
aba3e4a460 | ||
|
|
bc852aebeb | ||
|
|
89da530898 | ||
|
|
2367e7df50 | ||
|
|
2ca85a4976 | ||
|
|
e3860cf09c | ||
|
|
07be405f48 | ||
|
|
92d5210e37 | ||
|
|
01bf7aa774 | ||
|
|
427ca732fe | ||
|
|
ca92a0b90a | ||
|
|
db4547115c | ||
|
|
3ad4a3ae3a | ||
|
|
7bef772488 | ||
|
|
e4c64073c5 | ||
|
|
0ff15e91d9 | ||
|
|
a584aa7df8 | ||
|
|
57ca9dfdbc | ||
|
|
3a2073f785 | ||
|
|
e963d99d5e | ||
|
|
bbe188d4f9 | ||
|
|
9df1ed0b3b | ||
|
|
742998b477 | ||
|
|
a577fac1c5 | ||
|
|
d08abf05ff | ||
|
|
cd6af18183 | ||
|
|
a425275108 | ||
|
|
92f7b6fd9e | ||
|
|
68c7586c4c | ||
|
|
9549a3599c | ||
|
|
b826049893 | ||
|
|
88d950bafb | ||
|
|
50242c6eaa | ||
|
|
e5649d90e7 | ||
|
|
d22e6f28a1 | ||
|
|
307acee9d3 | ||
|
|
184b2cc26b | ||
|
|
613781e6c0 | ||
|
|
92c3c1f829 | ||
|
|
6268367b22 | ||
|
|
4c174a42f8 | ||
|
|
71463476f6 | ||
|
|
20b388c1d2 | ||
|
|
3ab7648384 | ||
|
|
9fb84e3ef2 | ||
|
|
d6bfce9a5d | ||
|
|
328d5c6275 | ||
|
|
19be6b5e17 | ||
|
|
499f9633ba | ||
|
|
774ca6cd80 | ||
|
|
22b5cf3536 | ||
|
|
18fa8af728 | ||
|
|
0f01bdad13 | ||
|
|
d787f67ab8 | ||
|
|
16de80f46a | ||
|
|
294bc51f83 | ||
|
|
70987fc55f | ||
|
|
5b700cb6e6 | ||
|
|
dcb31fa783 | ||
|
|
411a52e16f | ||
|
|
41bfd757ad | ||
|
|
d94c6f2132 | ||
|
|
29052c7a90 | ||
|
|
48de41137d | ||
|
|
203d06831e | ||
|
|
3e9c435ed1 | ||
|
|
e65fda875a | ||
|
|
70c745dd84 | ||
|
|
870b71afec | ||
|
|
18e0af6b38 | ||
|
|
ed87cc1b1e | ||
|
|
5d6ff69e8d | ||
|
|
cbea2b5443 | ||
|
|
a891e1f85d | ||
|
|
ade0aa770a | ||
|
|
a5f2f3b3f1 | ||
|
|
077ba65f7e | ||
|
|
6f6a426424 | ||
|
|
163158cf12 | ||
|
|
e4821aa9e1 | ||
|
|
9b23c3272b | ||
|
|
3454afb3e4 | ||
|
|
ab99ae6951 | ||
|
|
a609452cfd | ||
|
|
ee1256a676 | ||
|
|
a9837a3aaf | ||
|
|
499492e10a | ||
|
|
6e77ce999a | ||
|
|
dd05eeb821 | ||
|
|
919f8faeee | ||
|
|
b0db8e1ae0 | ||
|
|
3e0f2bfc4a | ||
|
|
5e9e1faedc | ||
|
|
dba6a88341 | ||
|
|
ee0b86c0c2 | ||
|
|
7ea2e1bf51 | ||
|
|
c801f2d4a5 | ||
|
|
ae84f02bd0 | ||
|
|
a6c73e2840 | ||
|
|
e6bc1d7c22 | ||
|
|
e2abb6b6db | ||
|
|
cb63cdcd42 | ||
|
|
1f28b9f98d | ||
|
|
7fcc0ba8a4 | ||
|
|
6773ac88af | ||
|
|
46bee1d532 | ||
|
|
10062373d1 | ||
|
|
68e3c2be9b | ||
|
|
099df7a0ee | ||
|
|
21b6537215 | ||
|
|
eb70f6d18e | ||
|
|
4ee6ae5da1 | ||
|
|
2c8d2d8643 | ||
|
|
0582b45389 | ||
|
|
f7cbe71bd9 | ||
|
|
1b87600658 | ||
|
|
446fb9c99f | ||
|
|
c774cb0c27 | ||
|
|
8ff9427a04 | ||
|
|
b427e67619 | ||
|
|
6163f98020 | ||
|
|
316b2fc98a | ||
|
|
9c73204224 | ||
|
|
7da59d5a39 | ||
|
|
a34b63b80d | ||
|
|
5b335f0f26 | ||
|
|
28af18f36e | ||
|
|
10bb9f7079 | ||
|
|
ed7006bbf4 | ||
|
|
b272f6bf15 | ||
|
|
715ce5dbe9 | ||
|
|
7d0f807880 | ||
|
|
b66eccedc0 | ||
|
|
f79e725aa3 | ||
|
|
66c4b6815f | ||
|
|
f073da1d27 | ||
|
|
dad0d648a1 | ||
|
|
f20262c5c8 | ||
|
|
23b6617a3f | ||
|
|
ab5c02c2ae | ||
|
|
1005cee4bc | ||
|
|
95a1b12c07 | ||
|
|
23542bbfee | ||
|
|
ec65c26b3c | ||
|
|
837cc9dd93 | ||
|
|
88a8d1c209 | ||
|
|
f4b780b806 | ||
|
|
3a296d237f | ||
|
|
db64c02bee | ||
|
|
97023ce1dd | ||
|
|
3a87a2665d | ||
|
|
6a2f4fb30d | ||
|
|
49b9b70c29 | ||
|
|
356340ad09 | ||
|
|
986bff1c22 |
No files matched your search
@@ -11,4 +11,7 @@ SortIncludes: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
IndentCaseLabels: true
|
||||
AlignConsecutiveMacros: true
|
||||
WhitespaceSensitiveMacros: ['QUOTE']
|
||||
IfMacros: ['IFX', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF']
|
||||
UseTab: Never
|
||||
---
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
|
||||
path: build/box64
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RPI5ARM64, RK3326, RK3399, RK3588, PHYTIUM, SD845, SD888, ADLINK, ARM64, ANDROID]
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RPI5ARM64, RK3326, RK3399, RK3588, PHYTIUM, SD845, SD888, ADLINK, ARM64, ANDROID, TERMUX, LARCH64]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
@@ -41,23 +41,41 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' ]]; then
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
|
||||
sudo apt-get -y install git cmake make python3
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
|
||||
unzip android-ndk-r23b-linux.zip
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DNOLOADADDR=1" >> $GITHUB_ENV
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
|
||||
unzip android-ndk-r26b-linux.zip
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
git clone https://github.com/termux/termux-docker.git
|
||||
sudo cp -rf termux-docker/system/arm /system
|
||||
sudo chown -R $(whoami):$(whoami) /system
|
||||
sudo chmod 755 -R /system
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
sudo apt-get -y install p7zip
|
||||
wget https://mirrors.utermux.dev/termux/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
7z x libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
tar -xf data.tar.xz
|
||||
sudo cp -rf data /
|
||||
sudo chmod 755 -R /data
|
||||
sudo chown -R $(whoami):$(whoami) /data
|
||||
echo "CFLAGS=-L/data/data/com.termux/files/usr/lib" >> $GITHUB_ENV
|
||||
echo "IS_TERMUX=1" >> $GITHUB_ENV
|
||||
echo "QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib" >> $GITHUB_ENV
|
||||
else
|
||||
echo "IS_TERMUX=0" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'X64' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
@@ -67,6 +85,21 @@ jobs:
|
||||
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
sudo mkdir /usr/local/larch
|
||||
wget -O- -q https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
|
||||
sudo ln -sf /usr/local/larch/target /usr/loongarch64-linux-gnu
|
||||
sudo cp -r /usr/local/larch/loongarch64-unknown-linux-gnu/lib/* /usr/loongarch64-linux-gnu/lib64/
|
||||
for i in objdump objcopy strip; do
|
||||
sudo ln -sf /usr/local/larch/bin/loongarch64-unknown-linux-gnu-$i /usr/bin/loongarch64-linux-gnu-$i
|
||||
done
|
||||
echo '/usr/local/larch/bin/loongarch64-unknown-linux-gnu-gcc -L/usr/local/larch/loongarch64-unknown-linux-gnu "$@"' | sudo tee /usr/bin/loongarch64-linux-gnu-gcc
|
||||
echo '/usr/local/larch/bin/loongarch64-unknown-linux-gnu-g++ -L/usr/local/larch/loongarch64-unknown-linux-gnu "$@"' | sudo tee /usr/bin/loongarch64-linux-gnu-g++
|
||||
sudo chmod 755 /usr/bin/loongarch64-linux-gnu-{gcc,g++}
|
||||
|
||||
echo BOX64_PLATFORM_MARCRO="-DLARCH64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3
|
||||
else
|
||||
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
@@ -93,6 +126,7 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }}\
|
||||
-DTERMUX=${{ env.IS_TERMUX }}\
|
||||
${{ env.BOX64_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
|
||||
@@ -103,30 +137,38 @@ jobs:
|
||||
- name: "Test Box64"
|
||||
if: ${{ matrix.platform != 'TEGRAX1' }}
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'ANDROID' ]]; then
|
||||
mkdir qemu8.1.0
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-8.1.0-2-x86_64.pkg.tar.zst | tar -I zstd -C qemu8.1.0 -xf -
|
||||
sudo cp qemu8.1.0/usr/bin/* /usr/bin/
|
||||
if [[ ${{ matrix.platform }} != 'X64' ]]; then
|
||||
mkdir qemu9.0.0
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-9.0.0-1-x86_64.pkg.tar.zst | tar -I zstd -C qemu9.0.0 -xf -
|
||||
sudo cp qemu9.0.0/usr/bin/* /usr/bin/
|
||||
fi
|
||||
|
||||
cd build
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'ANDROID' ]]; then # AArch64
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC_LA64NOEXT=1 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC_TEST=2 BOX64_DYNAREC_LA64NOEXT=1 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
true
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/system/lib64 BOX64_DYNAREC=0 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/system/lib64 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
INTERPRETER=qemu-aarch64-static QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib QEMU_LD_PREFIX=/system/lib64:/data/data/com.termux/files/usr/lib BOX64_DYNAREC=0 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib QEMU_LD_PREFIX=/system/lib64:/data/data/com.termux/files/usr/lib ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} != 'X64' ]]; then # AArch64
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC_TEST=2 ctest -j$(nproc) --output-on-failure
|
||||
else
|
||||
BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
ctest -j$(nproc) --output-on-failure
|
||||
fi
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
+292
-55
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
cmake_policy(SET CMP0065 NEW)
|
||||
|
||||
@@ -8,12 +8,13 @@ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
|
||||
option(RPI3ARM64 "Set to ON if targeting an RaspberryPI3 device with multiarch arm64 and armhf" ${RPI3ARM64})
|
||||
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
|
||||
option(RPI5ARM64 "Set to ON if targeting an RaspberryPi5 device with multiarch arm64 and armhf" ${RPI5ARM64})
|
||||
option(RPI5ARM64PS16K "Set to ON if targeting an RaspberryPi5 device with multiarch arm64, armhf, and 16k pages" ${RPI5ARM64PS16K})
|
||||
option(RK3326 "Set to ON if targeting an Rockchip RK3326 based device" ${RK3326})
|
||||
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
|
||||
option(RK3588 "Set to ON if targeting an Rockchip RK3588(S) based device" ${RK3588})
|
||||
option(ODROIDN2 "Set to ON if targeting an Odroid-N2 device" ${ODROIDN2})
|
||||
option(TEGRAX1 "Set to ON if targeting an Tegra X1 based device" ${TEGRAX1})
|
||||
option(TEGRA_T194 "Set to ON if targeting an Tegra Xavier based device" ${TEGRA_T194})
|
||||
option(TEGRA_T234 "Set to ON if targeting an Tegra Orin based device" ${TEGRA_T234})
|
||||
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
|
||||
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
|
||||
option(SD888 "Set to ON if targeting a Snapragon 888 based device" ${SD888})
|
||||
@@ -46,32 +47,28 @@ if(LARCH64)
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
if(RV64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC ON CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC 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 "")
|
||||
set(LARCH64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RPI5ARM64PS16K)
|
||||
set(RPI5ARM64 ON CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR SD888 OR SD8G2 OR LX2160A OR M1 OR ARM64 OR ADLINK)
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR PHYTIUM OR SD845 OR SD888 OR SD8G2 OR LX2160A OR M1 OR ARM64 OR ADLINK)
|
||||
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 SD888 OR SD8G2 OR LX2160A OR ADLINK)
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64)
|
||||
set(SAVE_MEM ON CACHE BOOL "")
|
||||
@@ -79,13 +76,9 @@ endif()
|
||||
if(RK3588)
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
if(M1 OR LARCH64 OR RPI5ARM64PS16K)
|
||||
set(PAGE16K ON CACHE BOOL "")
|
||||
endif()
|
||||
if(SW64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(PAGE8K ON CACHE BOOL "")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
@@ -96,9 +89,7 @@ option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" $
|
||||
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(LARCH64_DYNAREC "Set to ON to use LOONGARCH64 Dynamic Recompilation" ${LARCH64_DYNAREC})
|
||||
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})
|
||||
@@ -166,6 +157,14 @@ elseif(TEGRAX1)
|
||||
add_definitions(-DTEGRAX1)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto")
|
||||
elseif(TEGRA_T194)
|
||||
add_definitions(-DTEGRA_T194)
|
||||
add_definitions(-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a76+crypto -mtune=cortex-a76)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a76+crypto -mtune=cortex-a76")
|
||||
elseif(TEGRA_T234)
|
||||
add_definitions(-DTEGRA_T234)
|
||||
add_definitions(-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+crc+simd+crypto)
|
||||
@@ -191,7 +190,7 @@ elseif(M1)
|
||||
add_definitions(-pipe -march=armv8.5-a+simd+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.5-a+simd+crypto")
|
||||
elseif(LARCH64)
|
||||
add_definitions(-DLA464)
|
||||
add_definitions(-DLA64)
|
||||
add_definitions(-pipe -march=loongarch64)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=loongarch64")
|
||||
elseif(RV64)
|
||||
@@ -226,16 +225,13 @@ endif()
|
||||
if(SAVE_MEM)
|
||||
add_definitions(-DSAVE_MEM)
|
||||
endif()
|
||||
if(PAGE8K)
|
||||
add_definitions(-DPAGE8K)
|
||||
endif()
|
||||
|
||||
if(PAGE16K)
|
||||
add_definitions(-DPAGE16K)
|
||||
endif()
|
||||
|
||||
if(PAGE64K)
|
||||
add_definitions(-DPAGE64K)
|
||||
if(STATICBUILD)
|
||||
#-fno-pic -mcmodel=large
|
||||
add_definitions(-DSTATICBUILD)
|
||||
add_definitions(-Wno-deprecated-declarations) #by-design, deprecated function can be used
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-static")
|
||||
set(HAVE_TRACE OFF)
|
||||
endif()
|
||||
|
||||
if(NOGIT)
|
||||
@@ -275,6 +271,12 @@ elseif(RV64_DYNAREC)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/rv64")
|
||||
set(DYNAREC ON)
|
||||
elseif(LARCH64_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DLA64)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/la64")
|
||||
set(DYNAREC ON)
|
||||
else()
|
||||
set(DYNAREC OFF)
|
||||
endif()
|
||||
@@ -307,15 +309,16 @@ set_source_files_properties(
|
||||
|
||||
set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/main.c"
|
||||
"${BOX64_ROOT}/src/core.c"
|
||||
"${BOX64_ROOT}/src/box64context.c"
|
||||
"${BOX64_ROOT}/src/build_info.c"
|
||||
"${BOX64_ROOT}/src/custommem.c"
|
||||
"${BOX64_ROOT}/src/mallochook.c"
|
||||
"${BOX64_ROOT}/src/steam.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfparser.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfhash.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfload_dump.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfdwarf_private.c"
|
||||
"${BOX64_ROOT}/src/emu/x64compstrings.c"
|
||||
"${BOX64_ROOT}/src/emu/x64emu.c"
|
||||
"${BOX64_ROOT}/src/emu/x64int3.c"
|
||||
@@ -330,12 +333,9 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/librarian/librarian.c"
|
||||
"${BOX64_ROOT}/src/librarian/library.c"
|
||||
"${BOX64_ROOT}/src/librarian/dictionnary.c"
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX64_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX64_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX64_ROOT}/src/libtools/signals.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
@@ -343,17 +343,26 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/tools/bridge.c"
|
||||
"${BOX64_ROOT}/src/tools/callback.c"
|
||||
"${BOX64_ROOT}/src/tools/my_cpuid.c"
|
||||
"${BOX64_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX64_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX64_ROOT}/src/tools/fileutils.c"
|
||||
"${BOX64_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX64_ROOT}/src/tools/rbtree.c"
|
||||
"${BOX64_ROOT}/src/tools/rcfile.c"
|
||||
"${BOX64_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
if(NOT STATICBUILD)
|
||||
list(APPEND ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/mallochook.c"
|
||||
"${BOX64_ROOT}/src/steam.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX64_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols.c"
|
||||
)
|
||||
endif()
|
||||
if(NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/obstack.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfdwarf_private.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -388,6 +397,20 @@ set(INTERPRETER
|
||||
"${BOX64_ROOT}/src/emu/x64runf30f.c"
|
||||
)
|
||||
|
||||
if(STATICBUILD)
|
||||
set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
)
|
||||
else()
|
||||
set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedalut.c"
|
||||
@@ -407,6 +430,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbusglib1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappeddecor0.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedevent21.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedexpat.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedfaudio.c"
|
||||
@@ -421,6 +445,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgdkx112.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgio2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedglesv2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedglib2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgmodule2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgmp.c"
|
||||
@@ -502,6 +527,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxau.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbcursor.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbglx.c"
|
||||
@@ -517,6 +543,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbsync.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxinput.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxfixes.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxkb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbxtest.c"
|
||||
@@ -550,10 +577,12 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpango.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpam.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpng16.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulse.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulsemainloopglib.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpulsesimple.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl1image.c"
|
||||
@@ -588,6 +617,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommon.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommonx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbregistry.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxml2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxslt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldapr.c"
|
||||
@@ -595,13 +625,22 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedvulkan.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxshmfence.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc64.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n64.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc66.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n66.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"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc73.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n73.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc74.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n74.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedidn2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedanl.c"
|
||||
)
|
||||
endif()
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedandroidshmem.c"
|
||||
@@ -633,7 +672,7 @@ if(NOT CI)
|
||||
OUTPUT "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "--"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "STATICBUILD" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -666,6 +705,7 @@ if(ARM_DYNAREC)
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_immenc.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_jmpnext.c"
|
||||
|
||||
@@ -759,6 +799,37 @@ if(RV64_DYNAREC)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(LARCH64_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_jmpnext.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_shift.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_emit_logic.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_64.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f20f.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
|
||||
@@ -816,7 +887,8 @@ add_dependencies(${BOX64} WRAPPERS)
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
|
||||
if(STATICBUILD)
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-static -Wl,--no-as-needed -Wl,--whole-archive -Wl,--allow-multiple-definition -lm -ldl -lrt -lpthread -lresolv -lc -Wl,-defsym,_DYNAMIC=0 -pthread")
|
||||
#set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-fuse-ld=gold -static -Wl,--no-relax -Wl,--allow-multiple-definition -ldl -lrt -lpthread -lresolv -lc -lutil -lm -Wl,-defsym,_DYNAMIC=0 -pthread")
|
||||
target_link_libraries(${BOX64} c m dl pthread resolv util bsd c)
|
||||
else()
|
||||
if(ANDROID)
|
||||
if(TERMUX)
|
||||
@@ -825,7 +897,7 @@ else()
|
||||
target_link_libraries(${BOX64} c m dl)
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread")
|
||||
endif()
|
||||
endif()
|
||||
if(DYNAREC)
|
||||
@@ -875,28 +947,44 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION /etc/)
|
||||
else()
|
||||
#install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION ${TERMUX_PATH}/usr/etc/)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
set(INSTALL_PATH "/usr/lib/x86_64-linux-gnu/")
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
if(NOT TERMUX)
|
||||
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}/x64lib/libcrypto.so.1.1 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION /usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.14 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.12 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.7 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.3 DESTINATION ${INSTALL_PATH})
|
||||
# Create symlinks
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${INSTALL_PATH}libssl.so.1.1 ${INSTALL_PATH}libssl.so.1.0.0)")
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${INSTALL_PATH}libcrypto.so.1.1 ${INSTALL_PATH}libcrypto.so.1.0.0)")
|
||||
else()
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${TERMUX_PATH}/usr/lib/x86_64-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.14 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.12 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.7 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.3 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -960,6 +1048,7 @@ set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVIS
|
||||
endif()
|
||||
INCLUDE(CPack)
|
||||
|
||||
if(NOT ANDROID)
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
@@ -1111,8 +1200,145 @@ add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29 -D TEST_OUTPUT=tmpfile29.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
else()
|
||||
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01_android -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(bootSyscallC ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02_android -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(printf ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03_android -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(args ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04_android -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(maths1 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05_android -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06_android -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07_android -D TEST_OUTPUT=tmpfile07.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08_android -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09_android -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fpu ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12_android -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12_android.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(linkingIndirectNoversion ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15_android -D TEST_OUTPUT=tmpfile15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# Box64 for Android now have problems with test16, then disable it for now
|
||||
|
||||
#add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16_android -D TEST_OUTPUT=tmpfile16.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# Box64 for Android now have problems with test17, then disable it for now
|
||||
|
||||
#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_android -D TEST_OUTPUT=tmpfile17.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17_android.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_android -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# Android don't have backtrace symbols
|
||||
|
||||
add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20_android -D TEST_OUTPUT=tmpfile20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(longjumpInSignals ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21_android -D TEST_OUTPUT=tmpfile21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22_android -D TEST_OUTPUT=tmpfile22.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22_android.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87 PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(pshufb ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23_android -D TEST_OUTPUT=tmpfile23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24_android -D TEST_OUTPUT=tmpfile24.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87cache ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25_android -D TEST_OUTPUT=tmpfile25.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26_android -D TEST_OUTPUT=tmpfile26.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
set_tests_properties(feround PROPERTIES ENVIRONMENT "BOX64_SYNC_ROUNDING=1")
|
||||
|
||||
# TODO: need to regen test with latest test27.c sources
|
||||
|
||||
#add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test27_android -D TEST_OUTPUT=tmpfile27.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref27.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(shaext ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test28_android -D TEST_OUTPUT=tmpfile28.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref28.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29_android -D TEST_OUTPUT=tmpfile29.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
|
||||
if(NOT ANDROID)
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
@@ -1121,3 +1347,14 @@ foreach(file ${extension_tests})
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
else()
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}_android -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
endif()
|
||||
@@ -57,12 +57,14 @@ Because Box64 works by directly translating function calls from x86_64 to host s
|
||||
So understand that box64 will only run 64-bit linux binaries. For 32-bit binaries, you need box86 (with all the multiarch or proot trickery it implies on a 64-bit OS).
|
||||
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when the argument is "-m"
|
||||
|
||||
An alternative solution is to use Wine with new WoW64, but you will be limited to 32bits windows apps and games.
|
||||
|
||||
----
|
||||
|
||||
Notes about Box64 configuration
|
||||
----
|
||||
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box4.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reason, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box64.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reason, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.box64rc` > `/etc/box64.box64rc` > command line
|
||||
So, your settings in `~/.box64rc` may override the setting from your command line...
|
||||
|
||||
@@ -94,7 +96,7 @@ Notes about Wine
|
||||
----
|
||||
|
||||
Wine64 is supported on box64. Proton too. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively).
|
||||
Note that the new 32-bit PE in 64-bit processes that the Wine team is currently implementing in Wine 7.+ is now supported, but the support is quite young so there might be some residual issues.
|
||||
Note that the new 32-bit PE in 64-bit processes that the Wine team is currently implementing in Wine 7.+ is now supported. It's called "new WoW64" and it's working fine on box64, allowing the use of 32bits windows program on 64bits only system.
|
||||
|
||||
----
|
||||
|
||||
@@ -111,11 +113,10 @@ Final word
|
||||
I want to thank everyone who has contributed to box64 development.
|
||||
There are many ways to contribute: code contribution, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, mogery
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For their major code contribution: rajdakin, mogery, ksco, xctan
|
||||
* For their major financial contribution: [Playtron](https://playtron.one), FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* For their major code contribution on the RV64 Dynarec: ksco, xctan
|
||||
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/)
|
||||
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* For their continuous advertisements for the box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
And I also thank the many other people who participated even once in this project.
|
||||
|
||||
+3
-3
@@ -102,10 +102,10 @@ Box64 封装了 Vulkan 库,但请注意,它仅在 RX550 显卡上进行过
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
|
||||
* 代码贡献:rajdakin, mogery
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 代码贡献:rajdakin, mogery, ksco, xctan
|
||||
* 财务帮助:[Playtron](https://playtron.one), FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠和 LoongArch 迁移:[xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* 硬件捐赠:[ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* 硬件捐赠:[ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* 为本项目持续的宣传: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/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
+3
-4
@@ -107,11 +107,10 @@ Box64 використовує бібліотеки Vulkan, але зауваж
|
||||
Я хочу подякувати всім, хто зробив внесок у розвиток box64.
|
||||
Є багато способів зробити внесок: внесок коду, фінансовий внесок, апаратне забезпечення та реклама!
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, mogery
|
||||
* За великий фінансовий внесок: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За основний внесок у код: rajdakin, mogery, ksco, xctan
|
||||
* За великий фінансовий внесок: [Playtron](https://playtron.one), FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
|
||||
* За основний внесок у код RV64 Dynarec: ksco, xctan
|
||||
* За внесок у апаратне забезпечення: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* За внесок у апаратне забезпечення: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* За безперервну рекламу Box64: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/Команда [TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
|
||||
|
||||
Vendored
+24
@@ -1,3 +1,27 @@
|
||||
box64 (0.2.8) unstable; urgency=low
|
||||
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs and symbol resolution
|
||||
* Some more profiles in box64rc
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
|
||||
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
* => should improve games stability
|
||||
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
|
||||
* Dynarec: RV64 lots of opcoded added.
|
||||
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
|
||||
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
|
||||
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
|
||||
* Dynarec: Better handling of large block in the dynarec
|
||||
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
|
||||
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
|
||||
box64 (0.2.6) unstable; urgency=low
|
||||
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
v0.2.8
|
||||
======
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs and symbol resolution
|
||||
* Some more profiles in box64rc
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
|
||||
=> Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
=> should improve games stability
|
||||
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
|
||||
* Dynarec: RV64 lots of opcoded added.
|
||||
=> Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
|
||||
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
|
||||
=> Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
|
||||
* Dynarec: Better handling of large block in the dynarec
|
||||
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
|
||||
=> It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
|
||||
|
||||
v0.2.6
|
||||
======
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
|
||||
+23
-3
@@ -80,7 +80,6 @@ Warning, you need a 64bit OS:
|
||||
|
||||
#### for Raspberry Pi 5
|
||||
|
||||
If your Raspberry Pi OS use 16K pages use `RPI5ARM64PS16K` instead of `RPI5ARM64`:
|
||||
```
|
||||
-D RPI5ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
@@ -93,6 +92,22 @@ Using a 64bit OS:
|
||||
-D TEGRAX1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Jetson Xavier/T194
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
```
|
||||
-D TEGRA_T194=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Jetson Orin/T234
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
Caution: please use gcc-11 or higher, older gcc dosen't know cortex-a78ae
|
||||
```
|
||||
-D TEGRA_T234=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for ODROID N2/N2+
|
||||
|
||||
@@ -134,7 +149,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for M1
|
||||
|
||||
Only test on Asahi for now, using the default "16K page" kernel
|
||||
Only test on Asahi with Fedora, using the default "16K page" kernel
|
||||
|
||||
```
|
||||
-D M1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -189,7 +204,7 @@ NOTE: BUILDING BOX64 IN TERMUX NATIVE IS EXPERIMENTAL AND DOESN'T GONNA RUN LINU
|
||||
You also needed have `libandroid-sysv-semaphore` and `libandroid-spawn` libraries:
|
||||
|
||||
```
|
||||
-D TERMUX=1 -D -DCMAKE_C_COMPILER=clang CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-D TERMUX=1 -DCMAKE_C_COMPILER=clang -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for x86_64 Linux
|
||||
@@ -234,6 +249,11 @@ If you are not building from a git clone (for example, downloading a release sou
|
||||
|
||||
You need to add `-DWITH_MOLD=1` if GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
|
||||
|
||||
#### Build a statically linked box64
|
||||
|
||||
You can now build box64 staticaly linked, with `-DSTATICBUILD`. This is to use inside an x86_64 chroot. Note that this version of box64 will have just the minimum of wrapped libs. So only libc, libm and libpthread basically are wrapped. Other libs (like libGL or libvulkan, SDL2, etc...) will not be wrapped and x86_64 version will be used. It's designed to be used in docker image, or in headless server.
|
||||
Also, the Static Build is highly experimental, but feedback are always welcomed.
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
|
||||
+44
-17
@@ -104,6 +104,16 @@ Call XInitThreads when loading X11. (This is mostly for old Loki games with the
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX64_MMAP32 *
|
||||
Will use 32bits address in priority for external MMAP (when 32bits process are detected)
|
||||
* 0 : Use regular mmap (default, except for Snapdragron build)
|
||||
* 1 : Use 32bits address space mmap in priority for external mmap as soon a 32bits process are detected (default for SnapDragon and TegraX1 build)
|
||||
|
||||
#### BOX64_IGNOREINT3 *
|
||||
What to do when a CC INT3 opcode is encounter in the code being run
|
||||
* 0 : Trigger a TRAP signal if a handler is present
|
||||
* 1 : Just skip silently the opcode
|
||||
|
||||
#### BOX64_X11GLX *
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
@@ -138,8 +148,9 @@ Forbid dynablock creation in the interval specified (helpfull for debugging beha
|
||||
|
||||
#### 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
|
||||
* 0 : No comparison. (Default.)
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different.
|
||||
* 2 : Thread-safe tests, extremely slow.
|
||||
|
||||
#### BOX64_DYNAREC_BIGBLOCK *
|
||||
Enables/Disables Box64's Dynarec building BigBlock.
|
||||
@@ -183,18 +194,8 @@ Handling of flags on CALL/RET opcodes
|
||||
|
||||
#### BOX64_DYNAREC_CALLRET *
|
||||
Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
* 0 : Don't optimize CALL/RET, use Jump Table for boths
|
||||
* 1 : Try to optimized CALL/RET, skipping the use of the JumpTable when possible (Default)
|
||||
|
||||
#### BOX64_DYNAREC_HOTPAGE *
|
||||
Handling of HotPage (Page being both executed and written)
|
||||
* 0 : Don't track hotpage (Default)
|
||||
* 1-255 : Track HotPage, and disable execution of a page being written for N attempts
|
||||
|
||||
#### BOX64_DYNAREC_FASTPAGE *
|
||||
Will use a faster handling of HotPage (Page being both executed and written)
|
||||
* 0 : use regular hotpage (Default)
|
||||
* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash)
|
||||
* 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
|
||||
|
||||
#### BOX64_DYNAREC_ALIGNED_ATOMICS *
|
||||
Generated code for aligned atomics only
|
||||
@@ -207,9 +208,9 @@ Detect MonoBleedingEdge and apply conservative settings
|
||||
* 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX64_DYNAREC_JVM *
|
||||
Detect libjvm and apply conservative settings
|
||||
Detect libjvm and apply conservative settings. Obsolete, use BOX64_JVM instead.
|
||||
* 0 : Don't detect libjvm
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 SSE42=0 if detected (Default)
|
||||
|
||||
#### BOX64_DYNAREC_WAIT *
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
@@ -231,6 +232,11 @@ Handling of x87 80bits long double
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
#### BOX64_MAXCPU
|
||||
Maximum CPU Core exposed
|
||||
* 0 : Don't cap the number of cpu core exposed (Default)
|
||||
* XXX : Cap the maximum CPU Core exposed to XXX (usefull with wine64 or GridAutosport for example)
|
||||
|
||||
#### BOX64_SYNC_ROUNDING *
|
||||
Box64 will sync rounding mode with fesetround/fegetround.
|
||||
* 0 : Disable rounding mode syncing. (Default.)
|
||||
@@ -241,6 +247,11 @@ Detect libcef and apply malloc_hack settings
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
#### BOX64_JVM *
|
||||
Detect libjvm and apply conservative settings
|
||||
* 0 : Don't detect libjvm
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 SSE42=0 if detected (Default)
|
||||
|
||||
#### BOX64_SDL2_JGUID *
|
||||
Need a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2
|
||||
* 0 : Don't use any workaround
|
||||
@@ -301,6 +312,11 @@ Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX64_SSE42 *
|
||||
Expose or not SSE 4.2 capabilites
|
||||
* 0 : Do not expose SSE 4.2 capabilites (default when libjvm is detected)
|
||||
* 1 : Expose SSE 4.2 capabilites (Default.)
|
||||
|
||||
#### BOX64_FUTEX_WAITV *
|
||||
Use of the new fuext_waitc syscall
|
||||
* 0 : Do not try to use it, return unsupported (Default for BAD_SIGNAL build)
|
||||
@@ -315,7 +331,7 @@ Define x86_64 bash to launch script
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var.
|
||||
|
||||
#### BOX64_ENV1
|
||||
#### BOX64_ENV1 *
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
@@ -338,6 +354,9 @@ Define x86_64 bash to launch script
|
||||
#### BOX64_NORCFILES
|
||||
If the env var exist, no rc files (like /etc/box64.box64rc and ~/.box64rc) will be loaded
|
||||
|
||||
#### BOX64_RCFILE
|
||||
If the env var is set and file exists, this variable will be used as path to the box64rc file instead of default paths (BOX64_RCFILE is loaded first, default paths are not loaded)
|
||||
|
||||
----
|
||||
|
||||
Those variables are only valid inside a rcfile:
|
||||
@@ -351,6 +370,14 @@ Those variables are only valid inside a rcfile:
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "--in-process-gpu" to command line arguments (usefull for chrome based programs)
|
||||
|
||||
#### BOX64_CEFDISABLEGPU
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "-cef-disable-gpu" to command line arguments (usefull for steamwebhelper/cef based programs)
|
||||
|
||||
#### BOX64_CEFDISABLEGPUCOMPOSITOR
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "-cef-disable-gpu-compositor" to command line arguments (usefull for steamwebhelper/cef based programs)
|
||||
|
||||
#### BOX64_EXIT
|
||||
* 0 : Nothing special
|
||||
* 1 : Just exit, don't try to run the program
|
||||
+18
-19
@@ -264,15 +264,15 @@ down the program a lot and generate huge logs.
|
||||
=item B<BOX64_NODYNAREC>=I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging
|
||||
behaviour difference between Dynarec and Interpretor)
|
||||
behaviour difference between Dynarec and Interpreter)
|
||||
|
||||
=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.
|
||||
Dynarec will compare it's execution with the interpreter (super slow, only for testing)
|
||||
|
||||
* 0 : No test for generated code. (Default.)
|
||||
* 1 : Enable Tests for generated code
|
||||
* 0 : No comparison. (Default.)
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different.
|
||||
* 2 : Thread-safe tests, extremely slow.
|
||||
|
||||
=item B<BOX64_DYNAREC_BIGBLOCK>=I<0|1|2|3>
|
||||
|
||||
@@ -334,20 +334,6 @@ 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
|
||||
@@ -481,4 +467,17 @@ script. yyyy needs to be a full path to a valid x86_64 version of bash
|
||||
* 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)
|
||||
|
||||
=head1 VARIABLES FOR ENVIRONMENT ONLY
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<BOX64_VERSION>
|
||||
|
||||
When set, B<box64> will only print its version and then exit. This option is
|
||||
analogous to B<QEMU_VERSION> used by C<binfmt_misc> emulation of qemu-user. Its
|
||||
purpose is the same: provide a way to soft-disable C<binfmt_misc> emulation as
|
||||
well as for identifying B<box64> as the registered C<binfmt_misc> emulator.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
+206
-122
@@ -150,12 +150,12 @@ class FunctionConvention(object):
|
||||
self.ident = ident
|
||||
self.name = convname
|
||||
self.values = valid_chars
|
||||
# Free letters: B FG J QR T XYZab e gh jk mno qrst xyz
|
||||
# Free letters: B FG J QR T YZa e gh jk mno qrst z
|
||||
conventions = {
|
||||
'F': FunctionConvention('F', "System V", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', 'x', 'X']),
|
||||
'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', 'Y', 'y', 'b']),
|
||||
'W': FunctionConvention('W', "Windows", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'P', 'A'])
|
||||
}
|
||||
sortedvalues = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', 'x', 'X', '0', '1']
|
||||
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', 'Y', 'y', 'b', '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):
|
||||
@@ -197,7 +197,7 @@ class FunctionType(str):
|
||||
except ValueError as e:
|
||||
raise ValueError("Value is " + self) from e
|
||||
|
||||
def __getitem__(self, i: Union[int, slice]) -> 'FunctionType':
|
||||
def __getitem__(self, i: Union[int, slice]) -> 'FunctionType': # type: ignore [override]
|
||||
return FunctionType(super().__getitem__(i))
|
||||
|
||||
RedirectType = NewType('RedirectType', FunctionType)
|
||||
@@ -399,7 +399,9 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("sdl1mixer", "sdl2mixer") \
|
||||
or match("sdl1net", "sdl2net") \
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("libGL", "libEGL") \
|
||||
or match("libgl", "libegl") \
|
||||
or match("libgl", "glesv2") \
|
||||
or match("libegl", "glesv2") \
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("libc", "androidshmem") \
|
||||
@@ -816,62 +818,75 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
return 0
|
||||
|
||||
# Detect simple wrappings
|
||||
simple_wraps: Dict[ClausesStr, List[Tuple[FunctionType, int]]] = {}
|
||||
allowed_conv_ident = "F"
|
||||
allowed_conv = conventions[allowed_conv_ident]
|
||||
|
||||
# H could be allowed maybe?
|
||||
allowed_simply: str = "v"
|
||||
allowed_regs : str = "cCwWiuIUlLp"
|
||||
allowed_fpr : str = "fd"
|
||||
allowed_simply: Dict[str, str] = {"ARM64": "v", "RV64": "v"}
|
||||
allowed_regs : Dict[str, str] = {"ARM64": "cCwWiuIUlLp", "RV64": "CWuIUlLp"}
|
||||
allowed_fpr : Dict[str, str] = {"ARM64": "fd", "RV64": "fd"}
|
||||
|
||||
# Detect functions which return in an x87 register
|
||||
retx87_wraps: Dict[ClausesStr, List[FunctionType]] = {}
|
||||
return_x87: str = "DK"
|
||||
|
||||
# Sanity checks
|
||||
forbidden_simple: str = "EDKVOSNMHPAxX"
|
||||
assert(len(allowed_simply) + len(allowed_regs) + len(allowed_fpr) + len(forbidden_simple) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs for c in allowed_simply))
|
||||
assert(all(c not in allowed_simply + allowed_regs for c in allowed_fpr))
|
||||
assert(all(c not in allowed_simply + allowed_regs + allowed_fpr for c in forbidden_simple))
|
||||
assert(all(c in allowed_simply + allowed_regs + allowed_fpr + forbidden_simple for c in allowed_conv.values))
|
||||
forbidden_simple: Dict[str, str] = {"ARM64": "EDKVOSNMHPAxXYyb", "RV64": "EcwiDKVOSNMHPAxXYyb"}
|
||||
assert(all(k in allowed_simply for k in forbidden_simple))
|
||||
assert(all(k in allowed_regs for k in forbidden_simple))
|
||||
assert(all(k in allowed_fpr for k in forbidden_simple))
|
||||
for k1 in forbidden_simple:
|
||||
assert(len(allowed_simply[k1]) + len(allowed_regs[k1]) + len(allowed_fpr[k1]) + len(forbidden_simple[k1]) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs[k1] for c in allowed_simply[k1]))
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] for c in allowed_fpr[k1]))
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] for c in forbidden_simple[k1]))
|
||||
assert(all(c in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] + forbidden_simple[k1] for c in allowed_conv.values))
|
||||
assert(all(c in allowed_conv.values for c in return_x87))
|
||||
|
||||
def check_simple(v: FunctionType) -> Optional[int]:
|
||||
simple_wraps: Dict[str, Dict[ClausesStr, List[Tuple[FunctionType, int]]]] = {
|
||||
k1: {} for k1 in forbidden_simple
|
||||
}
|
||||
|
||||
def check_simple(v: FunctionType) -> Dict[str, int]:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
return None
|
||||
if v[0] in forbidden_simple:
|
||||
return None
|
||||
for c in v[2:]:
|
||||
if c in allowed_regs:
|
||||
regs_count = regs_count + 1
|
||||
elif c in allowed_fpr:
|
||||
fpr_count = fpr_count + 1
|
||||
elif c in allowed_simply:
|
||||
ret = {}
|
||||
for k in forbidden_simple:
|
||||
if v.get_convention() is not allowed_conv:
|
||||
continue
|
||||
if v[0] in forbidden_simple[k]:
|
||||
continue
|
||||
for c in v[2:]:
|
||||
if c in allowed_regs[k]:
|
||||
regs_count = regs_count + 1
|
||||
elif c in allowed_fpr[k]:
|
||||
fpr_count = fpr_count + 1
|
||||
elif c in allowed_simply[k]:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
# No character in forbidden_simply
|
||||
if (regs_count <= 6) and (fpr_count <= 8):
|
||||
# All checks passed!
|
||||
ret_val = 1 + fpr_count
|
||||
if v[0] in allowed_fpr:
|
||||
ret_val = -ret_val
|
||||
return ret_val
|
||||
else:
|
||||
# Too many arguments...
|
||||
return None
|
||||
# No character in forbidden_simply
|
||||
if (regs_count <= 6) and (fpr_count <= 8):
|
||||
# All checks passed!
|
||||
ret_val = 1 + fpr_count
|
||||
if v[0] in allowed_fpr[k]:
|
||||
ret_val = -ret_val
|
||||
ret[k] = ret_val
|
||||
# Else, too many arguments
|
||||
return ret
|
||||
|
||||
# Only search in real wrappers (mapped ones are nearly always not simple)
|
||||
for k in gbls:
|
||||
tmp = [ (v, ret_val) for v, ret_val in map(lambda v: (v, check_simple(v)), gbls[k]) if ret_val is not None ]
|
||||
if tmp:
|
||||
simple_wraps[k] = tmp
|
||||
simple_idxs = sorted(simple_wraps.keys(), key=lambda x: Clauses(x).splitdef())
|
||||
for v in gbls[k]:
|
||||
simples = check_simple(v)
|
||||
for k1, i in simples.items():
|
||||
if k in simple_wraps[k1]:
|
||||
simple_wraps[k1][k].append((v, i))
|
||||
else:
|
||||
simple_wraps[k1][k] = [(v, i)]
|
||||
simple_idxs = { k1: sorted(v1.keys(), key=lambda x: Clauses(x).splitdef()) for k1, v1 in simple_wraps.items() }
|
||||
|
||||
def check_return_x87(v: FunctionType) -> bool:
|
||||
return v[0] in return_x87
|
||||
@@ -918,6 +933,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
#define ST0val ST0.d
|
||||
|
||||
int of_convert(int);
|
||||
void* align_xcb_connection(void* src);
|
||||
void unalign_xcb_connection(void* src, void* dst);
|
||||
|
||||
""",
|
||||
"wrapper.h": """
|
||||
@@ -954,6 +971,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
// 0 = constant 0, 1 = constant 1
|
||||
// x = float complex
|
||||
// X = double complex
|
||||
// b = xcb_connection_t*
|
||||
|
||||
""",
|
||||
"fntypes.h": """
|
||||
@@ -1015,8 +1033,8 @@ 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 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 D K l L p V O S N M H P A x X Y y b
|
||||
'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", "complexl_t", "complex_t", "void*"],
|
||||
# E v c w i I C W u U f d K l L p V O S N M P A
|
||||
'W': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "void*", "void*"]
|
||||
}
|
||||
@@ -1074,8 +1092,11 @@ 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
|
||||
'from_complexf(emu, fn({0}));', # x
|
||||
'from_complex(emu, fn({0}));', # X
|
||||
'from_complexl(emu, fn({0}));', # Y
|
||||
'from_complexk(emu, fn({0}));', # y
|
||||
"\n#error Invalid return type: xcb_connection_t*\n", # b
|
||||
],
|
||||
conventions['W']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
@@ -1105,17 +1126,17 @@ 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 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]
|
||||
# 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 Y y b
|
||||
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, 0, 0, 1]
|
||||
# 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 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]
|
||||
# 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 Y y b
|
||||
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, 0, 0, 0]
|
||||
# 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 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]
|
||||
# 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 Y y b
|
||||
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, 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 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]
|
||||
# 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 Y y b
|
||||
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, 4, 4, 1]
|
||||
arg_r = [
|
||||
"", # E
|
||||
"", # v
|
||||
@@ -1144,64 +1165,73 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"(void*){p}, ", # A
|
||||
"", # x
|
||||
"", # X
|
||||
"", # Y
|
||||
"", # y
|
||||
"aligned_xcb, ", # b
|
||||
]
|
||||
arg_x = [
|
||||
"", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"emu->xmm[{p}].f[0], ", # f
|
||||
"emu->xmm[{p}].d[0], ", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"to_complexf(emu, {p}),",# x
|
||||
"to_complex(emu, {p})," # X
|
||||
"", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"emu->xmm[{p}].f[0], ", # f
|
||||
"emu->xmm[{p}].d[0], ", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"to_complexf(emu, {p}), ", # x
|
||||
"to_complex(emu, {p}), ", # X
|
||||
"", # Y
|
||||
"", # y
|
||||
"", # b
|
||||
]
|
||||
arg_o = [
|
||||
"emu, ", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"", # f
|
||||
"", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"(void*)(R_RSP + {p}), ", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"", # x
|
||||
"", # X
|
||||
"emu, ", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"", # f
|
||||
"", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"(void*)(R_RSP + {p}), ", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"", # x
|
||||
"", # X
|
||||
"", # Y
|
||||
"", # y
|
||||
"", # b
|
||||
]
|
||||
arg_s = [
|
||||
"", # E
|
||||
@@ -1226,11 +1256,14 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"io_convert(*(void**)(R_RSP + {p})), ", # S
|
||||
"*(void**)(R_RSP + {p}), ", # N
|
||||
"*(void**)(R_RSP + {p}),*(void**)(R_RSP + {p} + 8), ", # M
|
||||
"*(unsigned __int128)(R_RSP + {p}), ", # H
|
||||
"*(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
|
||||
"to_complexl(emu, R_RSP + {p}), ", # Y
|
||||
"to_complexk(emu, R_RSP + {p}), ", # y
|
||||
"aligned_xcb, ", # b
|
||||
]
|
||||
|
||||
# Asserts
|
||||
@@ -1258,7 +1291,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
for k in conventions:
|
||||
c = conventions[k]
|
||||
if c not in vals:
|
||||
raise NotImplementedError("[{k}]values not in vals".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
raise NotImplementedError("convention {k} not in vals".format(k=k))
|
||||
if len(c.values) != len(vals[c]):
|
||||
raise NotImplementedError("len([{k}]values) = {lenval} != len(vals[...]) = {lenvals}".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
# When arg_* is not empty, v* should not be 0
|
||||
@@ -1282,6 +1315,50 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Helper functions to write the function definitions
|
||||
systemVconv = conventions['F']
|
||||
def function_pre_systemV(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> Tuple[Optional[str], str]:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
# r: general register no
|
||||
# x: XMM register no
|
||||
if len(args) == 0:
|
||||
return None, ""
|
||||
|
||||
# Redirections
|
||||
if args[0] == "0":
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
elif args[0] == "1":
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
|
||||
idx = systemVconv.values.index(args[0])
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
if args[0] == "b":
|
||||
if 'b' in args[1:]:
|
||||
raise NotImplementedError("Multiple XCB connections unsupported")
|
||||
content = ""
|
||||
if r < len(reg_arg):
|
||||
content = reg_arg[r]
|
||||
else:
|
||||
content = "(R_RSP + " + str(d) + ")"
|
||||
return "(void*)" + content, f"void *aligned_xcb = align_xcb_connection((void*){content}); "
|
||||
elif (r < len(reg_arg)) and (vreg[idx] > 0):
|
||||
for _ in range(vreg[idx]):
|
||||
if r < len(reg_arg):
|
||||
r = r + 1
|
||||
else:
|
||||
d = d + 8
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
elif (x < 8) and (vxmm[idx] > 0):
|
||||
return function_pre_systemV(args[1:], d, r, x+1)
|
||||
elif vstack[idx] > 0:
|
||||
return function_pre_systemV(args[1:], d+8*vstack[idx], r, x)
|
||||
else:
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
def function_post_systemV(content: Optional[str]) -> str:
|
||||
if content is not None:
|
||||
return f" unalign_xcb_connection(aligned_xcb, {content});"
|
||||
else:
|
||||
return ""
|
||||
def function_args_systemV(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> str:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
@@ -1314,7 +1391,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
return ret + function_args_systemV(args[1:], d, r, x)
|
||||
elif (x < 8) and (vxmm[idx] > 0):
|
||||
# Value is in an XMM register
|
||||
return arg_x[idx].format(p=x) + function_args_systemV(args[1:], d, r, x+1)
|
||||
return arg_x[idx].format(p=x) + function_args_systemV(args[1:], d, r, x+vxmm[idx])
|
||||
elif vstack[idx] > 0:
|
||||
# Value is in the stack
|
||||
return arg_s[idx].format(p=d) + function_args_systemV(args[1:], d+8*vstack[idx], r, x)
|
||||
@@ -1361,9 +1438,11 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
# Generic function
|
||||
conv = N.get_convention()
|
||||
if conv is systemVconv:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_systemV(N[2:])[:-2]) + " }\n")
|
||||
prepost, pre = function_pre_systemV(N[2:])
|
||||
f.write(pre + vals[conv][conv.values.index(N[0])].format(function_args_systemV(N[2:])[:-2]) + function_post_systemV(prepost))
|
||||
else:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_windows(N[2:])[:-2]) + " }\n")
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_windows(N[2:])[:-2]))
|
||||
f.write(" }\n")
|
||||
|
||||
for k in gbls:
|
||||
if k != str(Clauses()):
|
||||
@@ -1386,15 +1465,20 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write("#endif\n")
|
||||
|
||||
# Write the isSimpleWrapper function
|
||||
file.write("\nint isSimpleWrapper(wrapper_t fun) {\n")
|
||||
for k in simple_idxs:
|
||||
if k != str(Clauses()):
|
||||
file.write("#if " + k + "\n")
|
||||
for vf, val in simple_wraps[k]:
|
||||
file.write("\tif (fun == &" + vf + ") return " + str(val) + ";\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
inttext = ""
|
||||
file.write("\n")
|
||||
for k1 in simple_idxs:
|
||||
file.write("#{inttext}if defined({k1})\nint isSimpleWrapper(wrapper_t fun) {{\n".format(inttext=inttext, k1=k1))
|
||||
inttext = "el"
|
||||
for k in simple_idxs[k1]:
|
||||
if k != str(Clauses()):
|
||||
file.write("#if " + k + "\n")
|
||||
for vf, val in simple_wraps[k1][k]:
|
||||
file.write("\tif (fun == &" + vf + ") return " + str(val) + ";\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
file.write("\n#else\nint isSimpleWrapper(wrapper_t fun) {\n\treturn 0;\n}\n#endif\n")
|
||||
|
||||
# Write the isRetX87Wrapper function
|
||||
file.write("\nint isRetX87Wrapper(wrapper_t fun) {\n")
|
||||
@@ -1480,6 +1564,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.18") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.4.0.21") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
+23
-2
@@ -21,6 +21,8 @@
|
||||
#include "signals.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
#include "rbtree.h"
|
||||
#include "dynarec.h"
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box64context_t* context)
|
||||
@@ -211,8 +213,12 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
init_custommem_helper(context);
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
#ifdef DYNAREC
|
||||
x64test_init();
|
||||
#endif
|
||||
|
||||
context->maplib = NewLibrarian(context);
|
||||
context->local_maplib = NewLibrarian(context);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
// Cannot use Bridge name as the map is not initialized yet
|
||||
@@ -229,7 +235,9 @@ box64context_t *NewBox64Context(int argc)
|
||||
// create exit bridge
|
||||
context->exit_bridge = AddBridge(context->system, NULL, NULL, 0, NULL);
|
||||
// get handle to box64 itself
|
||||
#ifndef STATICBUILD
|
||||
context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
|
||||
#endif
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->argc = argc;
|
||||
@@ -262,8 +270,13 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->segtls[4].is32bits = 1;
|
||||
|
||||
context->globdata = NewMapSymbols();
|
||||
context->uniques = NewMapSymbols();
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
#ifdef DYNAREC
|
||||
context->db_sizes = init_rbtree();
|
||||
#endif
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -335,8 +348,10 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
#ifndef STATICBUILD
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
#endif
|
||||
|
||||
if(ctx->stack_clone)
|
||||
box_free(ctx->stack_clone);
|
||||
@@ -358,6 +373,12 @@ void FreeBox64Context(box64context_t** context)
|
||||
FreeX64Emu(&ctx->emu_sig);
|
||||
|
||||
FreeMapSymbols(&ctx->globdata);
|
||||
FreeMapSymbols(&ctx->uniques);
|
||||
|
||||
#ifdef DYNAREC
|
||||
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, righter=%d\n", ctx->max_db_size, rb_get_righter(ctx->db_sizes));
|
||||
delete_rbtree(ctx->db_sizes);
|
||||
#endif
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_REVISION 6
|
||||
#define BOX64_REVISION 8
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
void PrintBox64Version()
|
||||
{
|
||||
printf("Box64%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
printf_log(LOG_NONE, "Box64%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
#ifdef HAVE_TRACE
|
||||
" with trace",
|
||||
#else
|
||||
|
||||
+2226
File diff suppressed because it is too large.
Load diff
+411
-587
File diff suppressed because it is too large.
Load diff
@@ -70,24 +70,46 @@
|
||||
#define wZR xZR
|
||||
|
||||
// conditions
|
||||
// Z == 1
|
||||
#define cEQ 0b0000
|
||||
// Z != 1
|
||||
#define cNE 0b0001
|
||||
// C == 1
|
||||
#define cCS 0b0010
|
||||
// C == 1
|
||||
#define cHS cCS
|
||||
// C != 1
|
||||
#define cCC 0b0011
|
||||
// C != 1
|
||||
#define cLO cCC
|
||||
// N == 1
|
||||
#define cMI 0b0100
|
||||
// N != 1
|
||||
#define cPL 0b0101
|
||||
// V == 1
|
||||
#define cVS 0b0110
|
||||
// V != 1
|
||||
#define cVC 0b0111
|
||||
// C == 1 && Z == 0
|
||||
#define cHI 0b1000
|
||||
// C !=1 || Z == 1
|
||||
#define cLS 0b1001
|
||||
// N == V
|
||||
#define cGE 0b1010
|
||||
// N != V
|
||||
#define cLT 0b1011
|
||||
// N == V && Z == 0
|
||||
#define cGT 0b1100
|
||||
// N != V || Z == 1
|
||||
#define cLE 0b1101
|
||||
// always
|
||||
#define c__ 0b1110
|
||||
|
||||
int convert_bitmask(uint64_t bitmask);
|
||||
#define convert_bitmask_w(A) convert_bitmask(((uint64_t)(A) << 32) + (uint32_t)(A))
|
||||
#define convert_bitmask_x(A) convert_bitmask((uint64_t)A)
|
||||
#define convert_bitmask_xw(A) convert_bitmask(rex.w?((uint64_t)(A)):(((uint64_t)(A) << 32) + (uint32_t)(A)))
|
||||
|
||||
#define invCond(cond) ((cond)^0b0001)
|
||||
|
||||
// MOVZ
|
||||
@@ -111,23 +133,8 @@
|
||||
#define MOVKw(Rd, imm16) EMIT(MOVK_gen(0, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVKw_LSL(Rd, imm16, shift) EMIT(MOVK_gen(0, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
|
||||
// This macro will give a -Wsign-compare warning, probably bug #38341
|
||||
#define MOV32w(Rd, imm32) \
|
||||
if(~((uint32_t)(imm32))<0xffffu) { \
|
||||
MOVNw(Rd, (~(uint32_t)(imm32))&0xffff); \
|
||||
} else { \
|
||||
MOVZw(Rd, (imm32)&0xffff); \
|
||||
if((imm32)&0xffff0000) {MOVKw_LSL(Rd, ((imm32)>>16)&0xffff, 16);} \
|
||||
}
|
||||
#define MOV64x(Rd, imm64) \
|
||||
if(~((uint64_t)(imm64))<0xffff) { \
|
||||
MOVNx(Rd, (~(uint64_t)(imm64))&0xffff); \
|
||||
} else { \
|
||||
MOVZx(Rd, ((uint64_t)(imm64))&0xffff); \
|
||||
if(((uint64_t)(imm64))&0xffff0000) {MOVKx_LSL(Rd, (((uint64_t)(imm64))>>16)&0xffff, 16);} \
|
||||
if(((uint64_t)(imm64))&0xffff00000000LL) {MOVKx_LSL(Rd, (((uint64_t)(imm64))>>32)&0xffff, 32);} \
|
||||
if(((uint64_t)(imm64))&0xffff000000000000LL) {MOVKx_LSL(Rd, (((uint64_t)(imm64))>>48)&0xffff, 48);} \
|
||||
}
|
||||
#define MOV32w(Rd, imm32) arm64_move32(dyn, ninst, Rd, imm32)
|
||||
#define MOV64x(Rd, imm64) arm64_move64(dyn, ninst, Rd, imm64)
|
||||
|
||||
#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);}
|
||||
@@ -513,18 +520,24 @@
|
||||
// logic to get the mask is ... convoluted... list of possible value there: https://gist.github.com/dinfuehr/51a01ac58c0b23e4de9aac313ed6a06a
|
||||
#define ANDx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b00, N, immr, imms, Rn, Rd))
|
||||
#define ANDw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b00, 0, immr, imms, Rn, Rd))
|
||||
#define ANDxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b00, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define ANDSx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b11, N, immr, imms, Rn, Rd))
|
||||
#define ANDSw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b11, 0, immr, imms, Rn, Rd))
|
||||
#define ANDSxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b11, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define ORRx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b01, N, immr, imms, Rn, Rd))
|
||||
#define ORRw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b01, 0, immr, imms, Rn, Rd))
|
||||
#define ORRxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b01, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define EORx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b10, N, immr, imms, Rn, Rd))
|
||||
#define EORw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b10, 0, immr, imms, Rn, Rd))
|
||||
#define EORxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b10, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define TSTx_mask(Rn, N, immr, imms) ANDSx_mask(xZR, Rn, N, immr, imms)
|
||||
#define TSTw_mask(Rn, immr, imms) ANDSw_mask(wZR, Rn, immr, imms)
|
||||
#define TSTxw_mask(Rn, N, immr, imms) ANDSxw_mask(xZR, Rn, N, immr, imms)
|
||||
|
||||
#define LOGIC_REG_gen(sf, opc, shift, N, Rm, imm6, Rn, Rd) ((sf)<<31 | (opc)<<29 | 0b01010<<24 | (shift)<<22 | (N)<<21 | (Rm)<<16 | (imm6)<<10 | (Rn)<<5 | (Rd))
|
||||
#define ANDx_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b00, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 0b00, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(0, 0b00, 0b01, 0, Rm, lsr, Rn, Rd))
|
||||
#define ANDxw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(rex.w, 0b00, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSx_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
@@ -610,6 +623,7 @@
|
||||
#define BFIx(Rd, Rn, lsb, width) BFMx(Rd, Rn, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFIw(Rd, Rn, lsb, width) BFMw(Rd, Rn, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFIxw(Rd, Rn, lsb, width) if(rex.w) {BFIx(Rd, Rn, lsb, width);} else {BFIw(Rd, Rn, lsb, width);}
|
||||
#define BFIz(Rd, Rn, lsb, width) if(rex.is32bits) {BFIw(Rd, Rn, lsb, width);} else {BFIx(Rd, Rn, lsb, width);}
|
||||
#define BFCx(Rd, lsb, width) BFMx(Rd, xZR, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFCw(Rd, lsb, width) BFMw(Rd, xZR, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFCxw(Rd, lsb, width) BFMxw(Rd, xZR, rex.w?(((-(lsb))%64)&0x3f):(((-(lsb))%32)&0x1f), (width)-1)
|
||||
@@ -766,6 +780,10 @@
|
||||
// mrs x0, fpsr : 1101010100 1 1 1 011 0100 0100 001 00000 o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0100(4) op2=1
|
||||
#define MRS_fpsr(Rt) EMIT(MRS_gen(1, 1, 3, 4, 4, 1, Rt))
|
||||
#define MSR_fpsr(Rt) EMIT(MRS_gen(0, 1, 3, 4, 4, 1, Rt))
|
||||
// mrs x0, cntvct_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b010
|
||||
#define MRS_cntvct_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b010, Rt))
|
||||
// mrs x0, cntpctss_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b101
|
||||
#define MRS_cntpctss_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b101, Rt))
|
||||
// NEON Saturation Bit
|
||||
#define FPSR_QC 27
|
||||
// NEON Input Denormal Cumulative
|
||||
@@ -1192,8 +1210,8 @@
|
||||
#define FCMP_scalar(type, Rn, Rm, opc) (0b11110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | 0b1000<<10 | (Rn)<<5 | (opc)<<3)
|
||||
#define FCMPS(Sn, Sm) EMIT(FCMP_scalar(0b00, Sn, Sm, 0b00))
|
||||
#define FCMPD(Dn, Dm) EMIT(FCMP_scalar(0b01, Dn, Dm, 0b00))
|
||||
#define FCMPS_0(Sn) EMIT(FCMP_scalar(0b00, 0, Sn, 0b01))
|
||||
#define FCMPD_0(Dn) EMIT(FCMP_scalar(0b01, 0, Dn, 0b01))
|
||||
#define FCMPS_0(Sn) EMIT(FCMP_scalar(0b00, Sn, 0, 0b01))
|
||||
#define FCMPD_0(Dn) EMIT(FCMP_scalar(0b01, Dn, 0, 0b01))
|
||||
|
||||
// CVT
|
||||
#define FCVT_scalar(sf, type, rmode, opcode, Rn, Rd) ((sf)<<31 | 0b11110<<24 | (type)<<22 | 1<<21 | (rmode)<<19 | (opcode)<<16 | (Rn)<<5 | (Rd))
|
||||
@@ -1563,6 +1581,15 @@
|
||||
// Signed saturating extract Unsigned Narrow, takes Rn element and reduce 16->8 with Unsigned saturation and fit higher part of Rd
|
||||
#define SQXTUN2_8(Rd, Rn) EMIT(QXTUN_vector(1, 1, 0b00, Rn, Rd))
|
||||
|
||||
#define XTN_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b10010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Xtract narrow to X bits
|
||||
#define XTN_8(Vd, Vn) EMIT(XTN_vector(0, 0b00, Vn, Vd))
|
||||
#define XTN_16(Vd, Vn) EMIT(XTN_vector(0, 0b01, Vn, Vd))
|
||||
#define XTN_32(Vd, Vn) EMIT(XTN_vector(0, 0b10, Vn, Vd))
|
||||
#define XTN2_8(Vd, Vn) EMIT(XTN_vector(1, 0b00, Vn, Vd))
|
||||
#define XTN2_16(Vd, Vn) EMIT(XTN_vector(1, 0b01, Vn, Vd))
|
||||
#define XTN2_32(Vd, Vn) EMIT(XTN_vector(1, 0b10, Vn, Vd))
|
||||
|
||||
// Integer CMP
|
||||
// EQual
|
||||
#define CMEQ_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b10001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -2171,6 +2198,24 @@
|
||||
#define FRINT64XS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b11, Sn, Sd))
|
||||
#define FRINT64XD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b11, Dn, Dd))
|
||||
|
||||
#define FRINTxx_vector(Q, U, sz, op, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b1111<<13 | (op)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFRINT32ZS(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 0, 0, Vn, Vd))
|
||||
#define VFRINT32ZSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 0, 0, Vn, Vd))
|
||||
#define VFRINT32XS(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 0, 0, Vn, Vd))
|
||||
#define VFRINT32XSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 0, 0, Vn, Vd))
|
||||
#define VFRINT32ZD(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 1, 0, Vn, Vd))
|
||||
#define VFRINT32ZDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 1, 0, Vn, Vd))
|
||||
#define VFRINT32XD(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 1, 0, Vn, Vd))
|
||||
#define VFRINT32XDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 1, 0, Vn, Vd))
|
||||
#define VFRINT64ZS(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 0, 1, Vn, Vd))
|
||||
#define VFRINT64ZSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 0, 1, Vn, Vd))
|
||||
#define VFRINT64XS(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINT64XSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINT64ZD(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 1, 1, Vn, Vd))
|
||||
#define VFRINT64ZDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 1, 1, Vn, Vd))
|
||||
#define VFRINT64XD(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 1, 1, Vn, Vd))
|
||||
#define VFRINT64XDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 1, 1, Vn, Vd))
|
||||
|
||||
// CRC32 extension
|
||||
#define CRC32C_gen(sf, Rm, sz, Rn, Rd) ((sf)<<31 | 0b11010110<<21 | (Rm)<<16 | 0b010<<13 | 1<<12 | (sz)<<10 | (Rn)<<5 | (Rd))
|
||||
#define CRC32CB(Wd, Wn, Wm) EMIT(CRC32C_gen(0, Wm, 0b00, Wn, Wd))
|
||||
|
||||
@@ -34,23 +34,3 @@ arm64_epilog:
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
|
||||
.global arm64_epilog_fast
|
||||
arm64_epilog_fast:
|
||||
//restore all used register
|
||||
add sp, x28, 0
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldp x27, x28, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
@@ -0,0 +1,86 @@
|
||||
#include <stdint.h>
|
||||
#include "arm64_immenc.h"
|
||||
|
||||
#define one (uint64_t)1
|
||||
|
||||
// Returns the packed valid-N-imms-immr (1-1-6-6 bits); returns 0 if bitmask is not encodable
|
||||
int convert_bitmask(uint64_t bitmask) {
|
||||
if (!bitmask || !~bitmask) return 0;
|
||||
|
||||
uint64_t size, mask, pat;
|
||||
|
||||
for (size = 6; size > 1; --size) {
|
||||
mask = (one << (1 << (size - 1))) - 1;
|
||||
pat = bitmask & mask;
|
||||
// printf("%016lX/%lu: %016lX %016lX %2d\n", bitmask, size, mask, pat, (1 << (size - 1)));
|
||||
if (pat != ((bitmask >> (1 << (size - 1))) & mask)) {
|
||||
// printf("%016lX/%lu: %016lX %016lX xx\n", bitmask, size, pat, (bitmask >> (1 << (size - 1))) & mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mask = (size >= 6) ? ((uint64_t)-1) : ((one << (1 << size)) - 1);
|
||||
pat = bitmask & mask;
|
||||
for (uint64_t i = 1; i < 7 - size; ++i) {
|
||||
uint64_t boff = i * (1 << size);
|
||||
if (((bitmask >> boff) & mask) != pat) {
|
||||
// printf("%016lX/%lu: no %lu %lu %016lX %016lX %016lX\n", bitmask, size, i, size, boff, mask, pat);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Note that here, pat != 0 and ~pat & (1 << size) != 0 (otherwise size = 1 and bitmask = all 0 or all 1)
|
||||
int immr = 0;
|
||||
uint64_t last_bit = one << ((1 << size) - 1);
|
||||
// printf("%016lX/%lu: %016lX %016lX %lu\n", bitmask, size, mask, pat, last_bit);
|
||||
if (pat & 1) {
|
||||
while (pat & last_bit) {
|
||||
pat = ((pat - last_bit) << 1) + 1;
|
||||
++immr;
|
||||
}
|
||||
} else {
|
||||
immr = 1 << size;
|
||||
while (!(pat & 1)) {
|
||||
pat >>= 1;
|
||||
--immr;
|
||||
}
|
||||
}
|
||||
// printf("%016lX/%lu: %016lX %016lX %lu %d\n", bitmask, size, mask, pat, last_bit, immr);
|
||||
if (pat & (pat + 1)) return 0; // Not 0...01...1
|
||||
int to = 1;
|
||||
while (pat & (one << to)) ++to;
|
||||
|
||||
// printf("%016lX/%lu: returning %c%c%02lX%02lX\n", bitmask, size, '2' + (size == 6), (uint64_t)(((0x1E << size) & 0x3F) + (to - 1)), (uint64_t)immr);
|
||||
return 0x2000 + ((size == 6) << 12) + ((((0x1E << size) & 0x3F) + (to - 1)) << 6) + immr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <unordered_set>
|
||||
int main() {
|
||||
std::unordered_set<uint64_t> okvals;
|
||||
uint64_t val;
|
||||
for (int n = 1; n < 7; ++n) {
|
||||
int imms0 = ((n == 6) ? 0xC0 : 0x80) + ((0x1E << n) & 0x3F);
|
||||
for (int nones = 0; nones < (1 << n) - 1; ++nones) {
|
||||
val = (one << (nones + 1)) - 1;
|
||||
for (int j = 0; j < 6 - n; ++j) {
|
||||
val = val + (val << (1 << (n + j)));
|
||||
}
|
||||
for (int immr = 0; immr < (1 << n); ++immr) {
|
||||
int exp = ((imms0 + nones) << 6) + immr;
|
||||
int got = convert_bitmask(val);
|
||||
if (exp != got) {
|
||||
printf("0x%016lX: expected %04X, got %04X\n", val, exp, got);
|
||||
}
|
||||
okvals.emplace(val);
|
||||
val = (val >> 1) + ((val & 1) << 63);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma omp parallel for
|
||||
for (uint64_t i = 1; i < 0xFFFFFFFFFFFFFFFFu; ++i) {
|
||||
int got = convert_bitmask(val);
|
||||
if (!!got != (okvals.find(val) != okvals.cend())) {
|
||||
printf("0x%016lX: expected %s, got %04X\n", val, (!!got ? "0000" : "non0"), got);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef __ARM64_IMMENC_H__
|
||||
#define __ARM64_IMMENC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
#endif // __ARM64_IMMENC_H__
|
||||
@@ -34,10 +34,12 @@ uint64_t DecodeBitMasks(int N, int imms, int immr)
|
||||
if(s==levels) return 0;
|
||||
uint64_t mask = (1LL<<(s+1))-1;
|
||||
if(r) { // rotate
|
||||
mask=(mask>>r)|(mask<<(e-r));
|
||||
mask&=((1LL<<e)-1);
|
||||
mask=(mask>>r)|(mask<<(e-r));
|
||||
if(e<64) {
|
||||
mask&=((1LL<<e)-1);
|
||||
}
|
||||
}
|
||||
while (e<64) { // replicate
|
||||
while(e<64) { // replicate
|
||||
mask|=(mask<<e);
|
||||
e<<=1;
|
||||
}
|
||||
@@ -387,13 +389,13 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "f00100101wwiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
if(sf) {
|
||||
uint64_t noti=~(uint64_t)imm;
|
||||
uint64_t noti=~(((uint64_t)imm)<<(hw*16));
|
||||
if(!hw)
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%lx", Xt[Rd], imm, noti);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x LSL %d\t; 0x%lx", Xt[Rd], imm, 16*hw, noti);
|
||||
} else {
|
||||
uint32_t noti=~(uint32_t)imm;
|
||||
uint32_t noti=~(((uint32_t)imm)<<(hw*16));
|
||||
if(!hw)
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%x", Wt[Rd], imm, noti);
|
||||
else
|
||||
@@ -1574,6 +1576,17 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%cSHLL%s V%d.%s, V%d.%s, #%d", a.U?'U':'S', a.Q?"2":"", Rd, Va, Rn, Vd, sh);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q0011110hhhhiii010101nnnnnddddd", &a) && (a.h != 0b1000)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
int sz = 3;
|
||||
if((a.h&0b1111)==0b0001) sz=0;
|
||||
else if((a.h&0b1110)==0b0010) sz=1;
|
||||
else if((a.h&0b1100)==0b0100) sz=2;
|
||||
int sh=(((a.h)<<3)|(imm)) - (8<<sz);
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
snprintf(buff, sizeof(buff), "SHL%s V%d.%s, V%d.%s, #%d", a.Q?"Q":"", Rd, Vd, Rn, Vd, sh);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DUP
|
||||
if(isMask(opcode, "0Q001110000iiiii000001nnnnnddddd", &a)) {
|
||||
@@ -1759,6 +1772,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "SHA256H2 Q%d, Q%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
// UDF
|
||||
if(isMask(opcode, "0000000000000000iiiiiiiiiiiiiiii", &a)) {
|
||||
snprintf(buff, sizeof(buff), "UDF 0x%x", a.i);
|
||||
return buff;
|
||||
}
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X ???", __builtin_bswap32(opcode));
|
||||
return buff;
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_next
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
@@ -34,8 +32,7 @@ arm64_prolog:
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
// Push a jump next on the stack
|
||||
adr x28, arm64_next
|
||||
stp x28, xzr, [sp, -16]!
|
||||
stp xzr, xzr, [sp, -16]!
|
||||
// Save old xSP in x28
|
||||
add x28, sp, 16
|
||||
//jump to function
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -63,17 +63,87 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
// TODO:, /0 is SGDT. While 0F 01 D0 is XGETBV, etc...
|
||||
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;
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // 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 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("SMSW Ed");
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(ed, (1<<0) | (1<<4)); // only PE and ET set...
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("RDTSCP");
|
||||
NOTEST(x1);
|
||||
if(box64_rdtsc) {
|
||||
CALL_(ReadTSC, x1, x3);
|
||||
} else {
|
||||
MRS_cntvct_el0(x1);
|
||||
}
|
||||
if(box64_rdtsc_shift) {
|
||||
LSLx(x1, x1, box64_rdtsc_shift);
|
||||
}
|
||||
LSRx(xRDX, x1, 32);
|
||||
MOVw_REG(xRAX, x1); // wipe upper part
|
||||
MOVw_REG(xRCX, xZR); // IA32_TSC, 0 for now
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // SGDT
|
||||
INST_NAME("SGDT Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
MOV32w(x1, 0x7f);
|
||||
STURH_I9(x1, wback, 0);
|
||||
if(rex.is32bits) {
|
||||
MOV32w(x1, 0x3000);
|
||||
STURw_I9(x1, wback, 2);
|
||||
} else {
|
||||
MOV64x(x1, 0xfffffe0000077000LL);
|
||||
STURx_I9(x1, wback, 2);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("SIDT Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
MOV32w(x1, 0xfff);
|
||||
STURH_I9(x1, wback, 0);
|
||||
if(rex.is32bits) {
|
||||
STURw_I9(xZR, wback, 2);
|
||||
} else {
|
||||
MOV64x(x1, 0xfffffe0000000000LL);
|
||||
STURx_I9(x1, wback, 2);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("SMSW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
// dummy for now... Do I need to track CR0 state?
|
||||
MOV32w(x1, (1<<0) | (1<<4)); // only PE and ET set...
|
||||
STURH_I9(x1, wback, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
@@ -96,7 +166,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("WBINVD");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
@@ -108,7 +178,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x0B:
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
@@ -130,6 +200,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x0E:
|
||||
INST_NAME("femms");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // 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 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
@@ -336,24 +417,29 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (box64_dynarec_fastround) {
|
||||
VFCVTZSS(q0, v1);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZS(q0, v1);
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTZS(d0, d0);
|
||||
} else {
|
||||
FRINTZS(d0, v1);
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTZS(d0, d0);
|
||||
} else {
|
||||
FRINTZS(d0, v1);
|
||||
}
|
||||
FCVTZSwS(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
FCVTZSwS(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -369,24 +455,29 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSS(q0, q0);
|
||||
} 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(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32XS(q0, v1);
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
} else {
|
||||
FRINTIS(d0, v1);
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
} else {
|
||||
FRINTIS(d0, v1);
|
||||
}
|
||||
FCVTZSwS(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
FCVTZSwS(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
@@ -395,7 +486,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
@@ -406,10 +497,16 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
LSRx(xRDX, x3, 32);
|
||||
MOVw_REG(xRAX, x3); // wipe upper part
|
||||
if(box64_rdtsc) {
|
||||
CALL_(ReadTSC, x1, x3);
|
||||
} else {
|
||||
MRS_cntvct_el0(x1);
|
||||
}
|
||||
if(box64_rdtsc_shift) {
|
||||
LSLx(x1, x1, box64_rdtsc_shift);
|
||||
}
|
||||
LSRx(xRDX, x1, 32);
|
||||
MOVw_REG(xRAX, x1); // wipe upper part
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
@@ -560,7 +657,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q1, 0);
|
||||
ABS_32(q0, q1);
|
||||
break;
|
||||
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("SHA1NEXTE Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -803,7 +900,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = v0;
|
||||
else
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
} else
|
||||
} else
|
||||
v1 = q1;
|
||||
if(v1!=v0) {
|
||||
VEXTQ_8(v1, q1, q1, 8);
|
||||
@@ -1454,6 +1551,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
@@ -1467,7 +1565,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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+i32_, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i32_, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
@@ -1505,7 +1603,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
#undef GO
|
||||
|
||||
case 0xA0:
|
||||
INST_NAME("PUSH FS");
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_FS]));
|
||||
PUSH1z(x2);
|
||||
break;
|
||||
case 0xA1:
|
||||
INST_NAME("POP FS");
|
||||
POP1z(x2);
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_FS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_FS]));
|
||||
break;
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
NOTEST(x1);
|
||||
@@ -1555,24 +1663,28 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
UFLAG_IF {
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
if(rex.w) {
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
emit_shld32(dyn, ninst, rex, ed, gd, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0xA8:
|
||||
INST_NAME("PUSH GS");
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_GS]));
|
||||
PUSH1z(x2);
|
||||
break;
|
||||
case 0xA9:
|
||||
INST_NAME("POP GS");
|
||||
POP1z(x2);
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_GS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_GS]));
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
@@ -1627,62 +1739,52 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
UFLAG_IF {
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
if(rex.w) {
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if((nextop&0xF8)==0xE8) {
|
||||
INST_NAME("LFENCE");
|
||||
SMDMB();
|
||||
} else
|
||||
if((nextop&0xF8)==0xF0) {
|
||||
INST_NAME("MFENCE");
|
||||
SMDMB();
|
||||
} else
|
||||
if((nextop&0xF8)==0xF8) {
|
||||
INST_NAME("SFENCE");
|
||||
SMDMB();
|
||||
} else {
|
||||
if(MODREG)
|
||||
switch (nextop) {
|
||||
case 0xE8:
|
||||
INST_NAME("LFENCE");
|
||||
SMDMB();
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("MFENCE");
|
||||
SMDMB();
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("SFENCE");
|
||||
SMDMB();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FXSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
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:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
@@ -1715,7 +1817,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
@@ -1739,8 +1840,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ASRx(x4, gd, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
CSETw(x3, cNE);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
@@ -1749,21 +1854,25 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, gd, ed);
|
||||
LSRx(x3, gd, 32);
|
||||
MOVw_REG(gd, gd);
|
||||
IFX(X_PEND) {
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x4, d_imul32);
|
||||
} else IFX(X_CF|X_OF) {
|
||||
SET_DFNONE(x4);
|
||||
}
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRx(x3, gd, 31);
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
CSETw(x3, cNE);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
@@ -1772,13 +1881,44 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFCw(xFlags, F_ZF, 1);
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
}
|
||||
MOVw_REG(gd, gd);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB1:
|
||||
// rep has no impact on this opcode
|
||||
INST_NAME("CMPXCHG Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
if(rex.w) {
|
||||
CSELxw(ed, gd, ed, cEQ);
|
||||
} else {
|
||||
B_MARK2(cNE);
|
||||
MOVw_REG(ed, gd);
|
||||
MARK2;
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STxw(gd, wback, fixedaddress);
|
||||
MARK;
|
||||
}
|
||||
MOVxw_REG(xRAX, x1); // upper part of RAX will be erase on 32bits, no mater what
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
@@ -2176,7 +2316,40 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v0, d0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDPxw_S7_offset(x2, x3, wback, 0);
|
||||
CMPSxw_REG(xRAX, x2);
|
||||
CCMPxw(xRDX, x3, 0, cEQ);
|
||||
B_MARK(cNE); // EAX!=ED[0] || EDX!=Ed[1]
|
||||
STPxw_S7_offset(xRBX, xRCX, wback, 0);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
}
|
||||
MARK3;
|
||||
UFLAG_IF {
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
@@ -2346,7 +2519,34 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(v1, 0);
|
||||
URHADD_8(v0, v0, v1);
|
||||
break;
|
||||
|
||||
case 0xE1:
|
||||
INST_NAME("PSRAW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 15);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +15 values
|
||||
NEG_32(v0, v0);
|
||||
VDUP_16(v0, v0, 0); // only the low 8bits will be used anyway
|
||||
SSHL_16(d0, d0, v0);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("PSRAD Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 31);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +31 values
|
||||
NEG_32(v0, v0);
|
||||
VDUP_32(v0, v0, 0); // only the low 8bits will be used anyway
|
||||
SSHL_32(d0, d0, v0);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("PAVGW Gm,Em");
|
||||
nextop = F8;
|
||||
@@ -2456,9 +2656,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
VMOVeD(v0, 1, d1, 0);
|
||||
SQXTN_32(v0, v0); // 2*q1 in 32bits now
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 32);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +32 values
|
||||
VDUPQ_32(v0, v0, 0);
|
||||
SSHL_32(d0, d0, v0);
|
||||
break;
|
||||
case 0xF3:
|
||||
@@ -2466,7 +2668,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
USHL_R_64(d0, d0, d1);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 64);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +64 values
|
||||
USHL_R_64(d0, d0, v0);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("PMULUDQ Gm,Em");
|
||||
|
||||
@@ -78,6 +78,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_or32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
@@ -278,6 +288,17 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gd, Seg:Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_adc32(dyn, ninst, rex, gd, ed, x3, x5);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -289,6 +310,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
WBACKO(x4);
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
INST_NAME("AND Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_and32(dyn, ninst, rex, gd, ed, x3, x5);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("SUB Seg:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -762,27 +793,19 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOV32w(x2, 1);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEDO(x6, 0);
|
||||
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
|
||||
if(ed!=x1) {MOVxw_REG(x1, ed);}
|
||||
CALL_(rcl32, ed, x6);
|
||||
WBACK;
|
||||
emit_rcl32c(dyn, ninst, rex, ed, 1, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOV32w(x2, 1);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEDO(x6, 0);
|
||||
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
|
||||
if(ed!=x1) {MOVxw_REG(x1, ed);}
|
||||
CALL_(rcr32, ed, x6);
|
||||
WBACK;
|
||||
emit_rcr32c(dyn, ninst, rex, ed, 1, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -867,7 +890,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x2, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
@@ -884,7 +907,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x2, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
@@ -1011,9 +1034,19 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2);
|
||||
GETEDO(x6, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
if(MODREG) {
|
||||
@@ -1029,8 +1062,17 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
&& 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);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
UDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
@@ -1041,10 +1083,19 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CALL(div64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
UDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
SET_DFNONE(x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1052,11 +1103,21 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2)
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2)
|
||||
GETSEDOw(x6, 0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZx_MARK3(wb);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
SDIVx(x2, x3, wb);
|
||||
MSUBx(x4, x2, wb, x3);
|
||||
MOVw_REG(xRAX, x2);
|
||||
@@ -1066,13 +1127,32 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
&& 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)
|
||||
GETEDO(x6, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
SDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
} else {
|
||||
GETEDO(x6, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
CBZxw_MARK(xRDX);
|
||||
MVNx_REG(x2, xRDX);
|
||||
CBZxw_MARK(x2);
|
||||
@@ -1083,7 +1163,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
SET_DFNONE(x2)
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1116,7 +1195,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDOz(x6, 0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
@@ -1145,14 +1224,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETEDOz(x6, 0);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
@@ -81,26 +81,18 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x06:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("PUSH ES");
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
PUSH1_32(x1);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
INST_NAME("PUSH ES");
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
PUSH1_16(x1);
|
||||
break;
|
||||
case 0x07:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POP ES");
|
||||
POP1_32(x1);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
INST_NAME("POP ES");
|
||||
POP1_16(x1);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
@@ -128,7 +120,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
@@ -166,7 +158,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
@@ -197,26 +189,18 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOVZw(x2, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x1E:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("PUSH DS");
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
PUSH1_32(x1);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
INST_NAME("PUSH DS");
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
PUSH1_16(x1);
|
||||
break;
|
||||
case 0x1F:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POP DS");
|
||||
POP1_32(x1);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
INST_NAME("POP DS");
|
||||
POP1_16(x1);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
@@ -244,7 +228,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
@@ -272,7 +256,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
@@ -300,7 +284,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
@@ -370,17 +354,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("PUSH reg");
|
||||
gd = xRAX+(opcode&0x07);
|
||||
if (gd==xRSP) {
|
||||
MOVw_REG(x1, xRSP);
|
||||
PUSH1_16(x1);
|
||||
} else {
|
||||
PUSH1_16(gd);
|
||||
}
|
||||
INST_NAME("PUSH reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
if (gd==xRSP) {
|
||||
MOVw_REG(x1, xRSP);
|
||||
PUSH1_16(x1);
|
||||
} else {
|
||||
DEFAULT;
|
||||
PUSH1_16(gd);
|
||||
}
|
||||
break;
|
||||
case 0x58:
|
||||
@@ -391,14 +371,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POP reg");
|
||||
gd = xRAX+(opcode&0x07);
|
||||
POP1_16(x1);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
INST_NAME("POP reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
POP1_16(x1);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x60:
|
||||
if(rex.is32bits) {
|
||||
@@ -449,6 +425,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x68:
|
||||
INST_NAME("PUSH Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
PUSH1_16(x2);
|
||||
break;
|
||||
case 0x69:
|
||||
case 0x6B:
|
||||
if(opcode==0x69) {
|
||||
@@ -586,8 +568,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
GETED(0);
|
||||
MOVxw_REG(x1, gd);
|
||||
BFIx(gd, ed, 0, 16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
BFIz(gd, ed, 0, 16);
|
||||
BFIz(ed, x1, 0, 16);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -621,7 +603,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMDMB();
|
||||
MARK2;
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -632,7 +614,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
BFIz(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
@@ -647,13 +629,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(gd, ed, 0, 16);
|
||||
BFIz(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDH(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
case 0x8C:
|
||||
@@ -662,7 +644,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = (nextop&0x38)>>3;
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
UXTHw(xRAX+(nextop&7)+(rex.b<<3), x3);
|
||||
BFIz(xRAX+(nextop&7)+(rex.b<<3), x3, 0, 16);
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
STH(x3, wback, fixedaddress);
|
||||
@@ -685,30 +667,41 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(ed, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
STRw_U12(wZR, xEmu, offsetof(x64emu_t, segs_serial[u8]));
|
||||
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");
|
||||
MOVw_REG(x2, xRAX);
|
||||
BFIx(xRAX, gd, 0, 16);
|
||||
BFIx(gd, x2, 0, 16);
|
||||
}
|
||||
case 0x8F:
|
||||
INST_NAME("POP Ew");
|
||||
nextop = F8;
|
||||
POP1_16(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
BFIz(wback, x1, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
STH(x1, wback, fixedaddress);
|
||||
}
|
||||
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");
|
||||
MOVw_REG(x2, xRAX);
|
||||
BFIz(xRAX, gd, 0, 16);
|
||||
BFIz(gd, x2, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x98:
|
||||
INST_NAME("CBW");
|
||||
SXTBw(x1, xRAX);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x99:
|
||||
INST_NAME("CWD");
|
||||
@@ -718,11 +711,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
READFLAGS(X_ALL);
|
||||
WILLWRITE();
|
||||
PUSH1_16(xFlags);
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SMREAD();
|
||||
POP1_16(x1); // probably not usefull...
|
||||
BFIw(xFlags, x1, 0, 16);
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
@@ -731,10 +727,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SET_DFNONE(x1);
|
||||
if(box64_wine) { // should this be done all the time?
|
||||
TBZ_NEXT(xFlags, F_TF);
|
||||
MOV64x(x1, addr);
|
||||
STORE_XEMU_CALL(x1);
|
||||
CALL(native_singlestep, -1);
|
||||
BFCw(xFlags, F_TF, 1);
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpretor only
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -748,7 +742,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(isLockAddress(u64)) lock=1; else lock = 0;
|
||||
SMREADLOCK(lock);
|
||||
LDRH_U12(x2, x1, 0);
|
||||
BFIx(xRAX, x2, 0, 16);
|
||||
BFIz(xRAX, x2, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
@@ -759,11 +753,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
if(isLockAddress(u64)) lock=1; else lock = 0;
|
||||
WILLWRITELOCK(lock);
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
SMWRITELOCK(lock);
|
||||
break;
|
||||
|
||||
case 0xA5:
|
||||
SMREAD();
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
@@ -788,9 +784,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
|
||||
case 0xA7:
|
||||
SMREAD();
|
||||
switch(rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
@@ -840,6 +838,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
WILLWRITE();
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
@@ -848,11 +847,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_S9_postindex(xRAX, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
STRH_S9_postindex(xRAX, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3;
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
@@ -860,6 +860,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
|
||||
case 0xAD:
|
||||
@@ -877,14 +878,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3;
|
||||
BFIx(xRAX, x2, 0, 16);
|
||||
BFIz(xRAX, x2, 0, 16);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("LODSW");
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x2, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
BFIx(xRAX, x2, 0, 16);
|
||||
BFIz(xRAX, x2, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -938,7 +939,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
@@ -946,11 +947,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&15) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 15;
|
||||
if (u8) {
|
||||
SETFLAGS(X_CF | X_OF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
emit_rol16c(dyn, ninst, x1, u8&15, x4, x5);
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -959,11 +961,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&15) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 15) {
|
||||
SETFLAGS(X_CF | X_OF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
emit_ror16c(dyn, ninst, x1, u8&15, x4, x5);
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -972,31 +974,37 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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;
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 31) {
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
emit_rcl16c(dyn, ninst, ed, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
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;
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 31) {
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
emit_rcr16c(dyn, ninst, ed, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_shl16c(dyn, ninst, x1, u8, x5, x4);
|
||||
@@ -1007,9 +1015,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
INST_NAME("SHR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_shr16c(dyn, ninst, x1, u8, x5, x4);
|
||||
@@ -1020,9 +1028,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
INST_NAME("SAR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETSEW(x1, 0);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_sar16c(dyn, ninst, x1, u8, x5, x4);
|
||||
@@ -1042,7 +1050,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
BFIz(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 2);
|
||||
u16 = F16;
|
||||
@@ -1071,22 +1079,18 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOV32w(x2, 1);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
emit_rcl16c(dyn, ninst, x1, 1, x5, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOV32w(x2, 1);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
emit_rcr16c(dyn, ninst, x1, 1, x5, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1172,7 +1176,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("RCL Ew, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
@@ -1182,7 +1188,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("RCR Ew, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
@@ -1272,7 +1280,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
UFLAG_DF(x1, d_mul16);
|
||||
break;
|
||||
@@ -1283,35 +1291,69 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
UDIVw(x3, x2, ed);
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIx(xRAX, x3, 0, 16);
|
||||
BFIx(xRDX, x4, 0, 16);
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
SKIPTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
GETSEW(x1, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
SDIVw(x3, x2, ed);
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIx(xRAX, x3, 0, 16);
|
||||
BFIx(xRDX, x4, 0, 16);
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("CLC");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
BFCx(xFlags, F_CF, 1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("STC");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
@@ -1331,13 +1373,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: // Push Ew
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("PUSH Ew");
|
||||
GETEW(x1, 0);
|
||||
PUSH1_16(ed);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
INST_NAME("PUSH Ew");
|
||||
GETEW(x1, 0);
|
||||
PUSH1_16(ed);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -234,24 +234,30 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSQD(q0, v1);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZD(q0, q0);
|
||||
VFCVTZSQD(q0, q0);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTZD(d0, d0);
|
||||
} else {
|
||||
FRINTZD(d0, v1);
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTZD(d0, d0);
|
||||
} else {
|
||||
FRINTZD(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, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -268,24 +274,30 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSS(q0, q0);
|
||||
} 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(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32XD(q0, q0);
|
||||
VFCVTZSQD(q0, q0);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
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, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x2);
|
||||
VMOVQSfrom(q0, i, x1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
@@ -1097,7 +1109,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(ed, xZR);
|
||||
VMOVSto(ed, q0, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
u8 = F8&0b11;
|
||||
VMOVSto(x1, q0, u8);
|
||||
STW(x1, wback, fixedaddress);
|
||||
@@ -1217,14 +1229,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0x60:
|
||||
INST_NAME("PCMPESTRM Gx, Ex, Ib");
|
||||
SETFLAGS(X_OF|X_CF|X_AF|X_ZF|X_SF|X_PF, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -1237,9 +1250,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, gd);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
switch(u8&1) {
|
||||
case 0b00:
|
||||
VDUPQB(q0, x1); // load the low 8bits of the mask
|
||||
@@ -1271,49 +1284,165 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PCMPESTRI Gx, Ex, Ib");
|
||||
SETFLAGS(X_OF|X_CF|X_AF|X_ZF|X_SF|X_PF, SF_SET);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
if((u8&0b1100)==0b1000) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
// this case is (un)signed word, equal each
|
||||
GETGX(v0, 0);
|
||||
GETEX(v1, 0, 1);
|
||||
u8 = F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if(u8&1) {
|
||||
//16bits
|
||||
VCMEQQ_16(q0, v0, v1); // equal => mask regs
|
||||
XTN_8(q0, q0); // 8 bits mask, in lower 64bits
|
||||
// transform that a mask in x1
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VSHL_8(q0, q0, 7); // keep only bit 0x80
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
VLDR64_U12(q1, x1, 0); // load shift
|
||||
USHL_8(q0, q0, q1); // shift
|
||||
UADDLV_8(q0, q0); // accumulate
|
||||
VMOVBto(x1, q0, 0);
|
||||
} else {
|
||||
//8 bits
|
||||
VCMEQQ_8(q0, v0, v1); // equal => mask regs
|
||||
// transform that a mask in x1
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VSHL_8(d0, q0, 7); // keep only bit 0x80
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
VLDR64_U12(q1, x1, 0); // load shift
|
||||
USHL_8(d0, d0, q1); // shift
|
||||
UADDLV_8(d0, d0); // accumulate
|
||||
VMOVBto(x1, d0, 0);
|
||||
// high part
|
||||
VMOVeD(d0, 0, q0, 1);
|
||||
VSHL_8(d0, d0, 7); // keep only bit 0x80
|
||||
USHL_8(d0, d0, q1); // shift
|
||||
UADDLV_8(d0, d0); // accumulate
|
||||
VMOVBto(x2, d0, 0);
|
||||
BFIw(x1, x2, 8, 8); // insert
|
||||
}
|
||||
// get abs of eax / edx and find min
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
NEGxw_REG(x2, x2);
|
||||
ADDSxw_U12(x3, xRDX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
NEGxw_REG(x3, x3);
|
||||
MOV32w(x4, (u8&1)?8:16);
|
||||
CMPSw_REG(x3, x4);
|
||||
CSELw(x3, x3, x4, cLT); // x3 is lmem
|
||||
CMPSw_REG(x2, x4);
|
||||
CSELw(x2, x2, x4, cLT); // x2 is lreg
|
||||
CMPSw_REG(x2, x3);
|
||||
CSELw(x5, x3, x2, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, x2, x3, cLT); // x2 is min(lmem, lreg)
|
||||
// x2 is min length 0-n_packed
|
||||
MVNw_REG(x4, xZR);
|
||||
LSLw_REG(x7, x4, x2);
|
||||
BICw_REG(x1, x1, x7);
|
||||
LSLw_REG(x4, x4, x5);
|
||||
ORRw_REG(x1, x1, x4);
|
||||
ANDw_mask(x1, x1, 0, (u8&1)?7:15);
|
||||
// x1 is intres1, transform to intres2
|
||||
switch((u8>>4)&3) {
|
||||
case 0b01:
|
||||
MOV32w(x4, (1<<((u8&1)?8:16))-1);
|
||||
EORw_REG(x1, x1, x4);
|
||||
break;
|
||||
case 0b11:
|
||||
MOV32w(x4, 1);
|
||||
LSLw_REG(x4, x4, x3);
|
||||
SUBw_U12(x4, x4, 1);
|
||||
EORw_REG(x1, x1, x4);
|
||||
}
|
||||
// flags
|
||||
IFX(X_ALL) {
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF) {
|
||||
CMPSw_REG(x1, xZR);
|
||||
CSETw(x4, cNE);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF|X_SF) {
|
||||
MOV32w(x4, 8);
|
||||
IFX(X_ZF) {
|
||||
CMPSw_REG(x3, x4);
|
||||
CSETw(x4, cLT);
|
||||
BFIw(xFlags, x4, F_ZF, 1);
|
||||
}
|
||||
IFX(F_SF) {
|
||||
CMPSw_REG(x2, x4);
|
||||
CSETw(x4, cLT);
|
||||
BFIw(xFlags, x4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
CMPSw_U12(x1, 0);
|
||||
CSETw(x4, cEQ);
|
||||
CMPSw_U12(x3, (u8&1)?8:16);
|
||||
CSETw(x5, cEQ);
|
||||
ANDw_REG(x4, x4, x5);
|
||||
BFIw(xFlags, x4, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFCw(xFlags, F_PF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
if(gd>7) // no need to reflect cache as xmm0-xmm7 will be saved before the function call anyway
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
}
|
||||
MOVw_REG(x2, xRDX);
|
||||
MOVw_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
}
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
CBNZw_MARK(x1);
|
||||
MOV32w(xRCX, (u8&1)?8:16);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if(u8&0b1000000) {
|
||||
CBNZw_MARK(x1);
|
||||
MOV32w(xRCX, (u8&1)?8:16);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
CLZw(xRCX, x1);
|
||||
MOV32w(x2, 31);
|
||||
SUBw_REG(xRCX, x2, xRCX);
|
||||
} else {
|
||||
RBITxw(xRCX, x1);
|
||||
ORRw_mask(xRCX, x1, (u8&1)?0b011000:0b010000,0);
|
||||
RBITw(xRCX, xRCX);
|
||||
CLZw(xRCX, xRCX);
|
||||
}
|
||||
break;
|
||||
case 0x62:
|
||||
INST_NAME("PCMPISTRM Gx, Ex, Ib");
|
||||
SETFLAGS(X_OF|X_CF|X_AF|X_ZF|X_SF|X_PF, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -1324,9 +1453,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
CALL(sse42_compare_string_implicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, gd);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
switch(u8&1) {
|
||||
case 0b00:
|
||||
VDUPQB(q0, x1); // load the low 8bits of the mask
|
||||
@@ -1358,14 +1487,16 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 0x63:
|
||||
INST_NAME("PCMPISTRI Gx, Ex, Ib");
|
||||
SETFLAGS(X_OF|X_CF|X_AF|X_ZF|X_SF|X_PF, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
if(gd>7)
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -2410,7 +2541,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Ew,Gw");
|
||||
INST_NAME("BSF Gw,Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
@@ -2426,7 +2557,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Ew,Gw");
|
||||
INST_NAME("BSR Gw,Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
@@ -2651,6 +2782,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
@@ -2942,7 +3074,6 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 64);
|
||||
|
||||
@@ -27,8 +27,9 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t gd, ed, wb1, wback;
|
||||
int64_t j64;
|
||||
int16_t i16;
|
||||
int v0, v1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
@@ -66,27 +67,149 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
FCMPD(v0, v1);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQA Gx,Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
SMREAD();
|
||||
VLDR128_REG(v0, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQA Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR128_REG(v0, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4);
|
||||
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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4);
|
||||
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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
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);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOVZw(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew, Gw");
|
||||
nextop = F8;
|
||||
|
||||
@@ -48,6 +48,37 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("LOCK ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALH(x5, x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STADDLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("LOCK OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -98,8 +129,14 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK3(cGE);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
}
|
||||
}
|
||||
// Aligned version
|
||||
if(arm64_atomics) {
|
||||
@@ -171,6 +208,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
INST_NAME("LOCK ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
@@ -192,6 +230,38 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("LOCK AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UXTHw(x6, ed);
|
||||
emit_and16(dyn, ninst, x6, gd, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
MVNw_REG(x3, gd);
|
||||
UFLAG_IF {
|
||||
LDCLRALH(x3, x1, wback);
|
||||
emit_and16(dyn, ninst, x1, gd, x3, x4);
|
||||
} else {
|
||||
STCLRLH(x3, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_and16(dyn, ninst, x1, gd, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
@@ -215,8 +285,14 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK(cGE);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
LDADDALH(x5, x1, wback);
|
||||
@@ -370,8 +446,14 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK(cGE);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
NEGw_REG(x4, x5);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
@@ -652,6 +653,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x66:
|
||||
opcode=F8;
|
||||
GETREX();
|
||||
switch(opcode) {
|
||||
|
||||
case 0x89:
|
||||
@@ -665,16 +667,66 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
WILLWRITELOCK(lock);
|
||||
STH(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gw, Ed");
|
||||
nextop=F8;
|
||||
//GETGW(x1);
|
||||
gd = x1; // no need to read
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=gd)
|
||||
gd = ed;
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gd, Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(1);
|
||||
i64 = F8S;
|
||||
MOV64xw(x4, i64);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, ed, x4);
|
||||
MULx(gd, ed, x4);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, ed, x4);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
MOVw_REG(gd, gd);
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
@@ -782,6 +834,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(eb1, gd, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, &lock, 0, 0);
|
||||
WILLWRITELOCK(lock);
|
||||
STB(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -794,6 +847,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
WILLWRITELOCK(lock);
|
||||
STxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -880,25 +934,21 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETED32W(x4, x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rcl32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETED32W(x4, x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rcr32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -932,6 +982,34 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Eb, Ib");
|
||||
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;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
BFIx(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, &unscaled, 0xfff, 0, rex, &lock, 0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
MOV32w(x3, u8);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
WILLWRITELOCK(lock);
|
||||
STB(ed, wback, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ed, Id");
|
||||
nextop=F8;
|
||||
@@ -943,6 +1021,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
WILLWRITELOCK(lock);
|
||||
STxw(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -960,7 +1039,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
@@ -1077,8 +1156,8 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2);
|
||||
GETED32(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
@@ -1095,7 +1174,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
&& 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);
|
||||
UDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
@@ -1110,7 +1188,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
SET_DFNONE(x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1118,8 +1195,8 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2);
|
||||
if(!rex.w) {
|
||||
SET_DFNONE(x2)
|
||||
GETSED32w(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
@@ -1132,7 +1209,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
&& 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)
|
||||
GETED32(0);
|
||||
SDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
@@ -1149,12 +1225,58 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SDIVx(x2, xRAX, ed);
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
SET_DFNONE(x2)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF((box64_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETED32(0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
if(box64_dynarec_callret) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -61,6 +61,60 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
STRw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg => reg
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem => reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
LDRw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP Seg:Ed");
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= reg
|
||||
POP1_32(x1);
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), x1);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
POP1_32(x1);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
STRw_REG(x1, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, Seg:[Od]");
|
||||
i32 = F16;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(i32<4096 && !(i32&3)) {
|
||||
LDRw_U12(xRAX, x4, i32);
|
||||
} else if(i32<256) {
|
||||
LDURw_I9(xRAX, x4, i32);
|
||||
} else {
|
||||
MOV32w(x1, i32);
|
||||
LDRw_REG(xRAX, x4, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Seg:[Od], EAX");
|
||||
i32 = F16;
|
||||
|
||||
@@ -65,6 +65,66 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} 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); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (16bits)");
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JCXZ");
|
||||
i8 = F8S;
|
||||
TSTw_mask(xRCX, 0, 15); //mask=0xffff
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -178,119 +179,120 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(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, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
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, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
DEFAULT;
|
||||
break;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(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, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
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, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int64_t fixedaddress, j64;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
@@ -41,6 +41,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -131,18 +132,103 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
#if 1
|
||||
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
|
||||
// value put in x14
|
||||
if(i1==-1) {
|
||||
if(fpu_is_st_freed(dyn, ninst, 0)) {
|
||||
MOV32w(x4, 0b100000100000000);
|
||||
B_MARK3_nocond;
|
||||
} else {
|
||||
// not in cache, so check Empty status and load it
|
||||
i2 = -dyn->n.x87stack;
|
||||
LDRw_U12(x3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
ADDw_U12(x3, x3, -i2);
|
||||
} else {
|
||||
SUBw_U12(x3, x3, i2);
|
||||
}
|
||||
}
|
||||
CMPSw_U12(x3, 0);
|
||||
MOV32w(x4, 0b100000100000000); // empty: C3,C2,C0 = 101
|
||||
B_MARK3(cLE);
|
||||
// x5 will be the actual top
|
||||
LDRw_U12(x5, xEmu, offsetof(x64emu_t, top));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUBw_U12(x5, x5, -i2);
|
||||
} else {
|
||||
ADDw_U12(x5, x5, i2);
|
||||
}
|
||||
ANDw_mask(x5, x5, 0, 3); // (emu->top + i)&7
|
||||
}
|
||||
// load tag
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
TSTw_mask(x3, 0, 1); // 0b11
|
||||
B_MARK3(cNE); // empty: C3,C2,C0 = 101
|
||||
// load x2 with ST0 anyway, for sign extraction
|
||||
ADDx_REG_LSL(x1, xEmu, x5, 3);
|
||||
LDRx_U12(x2, x1, offsetof(x64emu_t, x87));
|
||||
}
|
||||
} else {
|
||||
// simply move from cache reg to x2
|
||||
v1 = dyn->n.x87reg[i1];
|
||||
VMOVQDto(x2, v1, 0);
|
||||
}
|
||||
// get exponant in x1
|
||||
LSRx_IMM(x1, x2, 20+32);
|
||||
ANDSx_mask(x1, x1, 1, 0b00000, 0b001010); // 0x7ff
|
||||
B_MARK(cNE); // not zero or denormal
|
||||
ANDSx_mask(x1, x2, 1, 0, 0b111110); // 0x7fffffffffffffff
|
||||
MOV32w(x4, 0b100000000000000); // Zero: C3,C2,C0 = 100
|
||||
MOV32w(x5, 0b100010000000000); // Denormal: C3,C2,C0 = 110
|
||||
CSELx(x4, x4, x5, cEQ);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
CMPSx_U12(x1, 0x7ff); // infinite/NaN?
|
||||
MOV32w(x5, 0b000010000000000); // normal: C3,C2,C0 = 010
|
||||
CSELx(x4, x5, x4, cNE);
|
||||
B_MARK3(cNE);
|
||||
TSTx_mask(x2, 1, 0b000000, 0b110011); // 0x000fffffffffffff
|
||||
MOV32w(x4, 0b000010100000000); // infinity: C3,C2,C0 = 011
|
||||
MOV32w(x3, 0b000000100000000); // NaN: C3,C2,C0 = 001
|
||||
CSELx(x4, x4, x3, cEQ);
|
||||
MARK3;
|
||||
// Extract signa & Update SW
|
||||
LSRx_IMM(x1, x2, 63);
|
||||
BFIx(x4, x1, 9, 1); //C1
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x2, 0b01000111);
|
||||
BICw_REG_LSL(x1, x1, x2, 8);
|
||||
ORRw_REG(x4, x4, x1);
|
||||
STRH_U12(x4, xEmu, offsetof(x64emu_t, sw));
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1); // should be possible inline, but is it worth it?
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
if(ninst<dyn->size+2 && (dyn->insts[ninst+1].pred_sz==1) && (dyn->insts[ninst+2].pred_sz==1)
|
||||
&& PK(0)==0xD9 && PK(1)==0xE8
|
||||
&& PK(2)==0xD9 && PK(3)==0xF3
|
||||
) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FLD1 FLD1 FPATAN");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
FTABLE64(v1, PI/4.0);
|
||||
addr+=4;
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
@@ -384,92 +470,79 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CALL(native_fcos, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_D_S(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_S_D(v1, v1);
|
||||
}
|
||||
VST32(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(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, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
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));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_D_S(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_S_D(v1, v1);
|
||||
}
|
||||
VST32(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(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, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
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));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -42,6 +42,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(ed);
|
||||
MAYUSE(j64);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -134,106 +135,95 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -176,35 +177,29 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
SXTL_32(v1, v1); // i32 -> i64
|
||||
SCVTFDD(v1, v1); // i64 -> double
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
SXTL_32(v1, v1); // i32 -> i64
|
||||
SCVTFDD(v1, v1); // i64 -> double
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
if(arm64_frintts) {
|
||||
FRINT32ZD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
#else
|
||||
FCVTZSwD(x5, s0);
|
||||
STW(x5, wback, fixedaddress);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -217,21 +212,20 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x5, 0x80000000);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
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;
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
if(arm64_frintts) {
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
#else
|
||||
FCVTZSwD(x5, s0);
|
||||
STW(x5, wback, fixedaddress);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -244,21 +238,20 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x5, 0x80000000);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
ed = x1;
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
if(arm64_frintts) {
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(ed, s0);
|
||||
WBACK;
|
||||
#else
|
||||
FCVTZSwD(x5, s0);
|
||||
STW(x5, wback, fixedaddress);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -271,112 +264,116 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x5, 0x80000000);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
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) || (!rex.is32bits && PK(0)>=0x40 && PK(0)<=0x4f && PK(1)==0xDB && ((PK(2)>>3)&7)==7)) {
|
||||
NOTEST(x5);
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; // 0xDB or rex
|
||||
if(!rex.is32bits && nextop>=0x40 && nextop<=0x4f) {
|
||||
rex.rex = nextop;
|
||||
nextop = F8; //0xDB
|
||||
} else
|
||||
rex.rex = 0;
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if((PK(0)==0xDB && ((PK(1)>>3)&7)==7) || (PK(0)>=0x40 && PK(0)<=0x4f && PK(1)==0xDB && ((PK(2)>>3)&7)==7)) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; // 0xDB or rex
|
||||
if(nextop>=0x40 && nextop<=0x4f) {
|
||||
rex.rex = nextop;
|
||||
nextop = F8; //0xDB
|
||||
} else
|
||||
rex.rex = 0;
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
if(box64_x87_no80bits) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
} else {
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x3);
|
||||
CALL(native_fld, -1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
if(box64_x87_no80bits) {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, wback, fixedaddress);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
} else {
|
||||
#if 0
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL(native_fstp, -1);
|
||||
#else
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
FMOVxD(x1, v1);
|
||||
// do special value first
|
||||
TSTx_mask(x1, 1, 0b00000, 0b111110); //0x7fffffffffffffffL
|
||||
B_MARK(cNE);
|
||||
// Zero
|
||||
LSRx(x3, x1, 63-15); //x3 = sign+exp
|
||||
MOVZw(x5, 0); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// get sign, in main ouput x5 for sign+exp
|
||||
ANDx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
LSRx(x5, x5, 63-15); // x5 = sign
|
||||
// get exp
|
||||
LSRx(x3, x1, 52); // x3 = exp11
|
||||
ANDw_mask(x3, x3, 0, 0b1010); //0x7ff
|
||||
MOV32w(x4, 0x7ff);
|
||||
CMPSw_REG(x3, x4);
|
||||
B_MARK2(cNE);
|
||||
// NaN and Infinite
|
||||
ORRw_mask(x3, x5, 0, 0b1110); //x3 = sign | 0x7fff
|
||||
TSTx_mask(x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
ORRx_mask(x4, xZR, 1, 0b10, 0b01); //0xc000000000000000
|
||||
CSELx(x5, x5, x4, cEQ); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// regular / denormals
|
||||
ANDx_mask(x1, x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
LSLx_IMM(x1, x1, 11); //x1 = mantisse missing "1"
|
||||
MOVZw(x4, 16383-1023); //BIAS80 - BIAS64
|
||||
CBZw(x3, 4+3*4); // exp11 == 0?
|
||||
// normals
|
||||
ADDw_REG(x3, x3, x4); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
#endif
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
// sync top
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(native_fld, -1);
|
||||
// go back with the top & stack counter
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
#if 0
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL(native_fstp, -1);
|
||||
#else
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
FMOVxD(x1, v1);
|
||||
// do special value first
|
||||
TSTx_mask(x1, 1, 0b00000, 0b111110); //0x7fffffffffffffffL
|
||||
B_MARK(cNE);
|
||||
// Zero
|
||||
LSRx(x3, x1, 63-15); //x3 = sign+exp
|
||||
MOVZw(x5, 0); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// get sign, in main ouput x5 for sign+exp
|
||||
ANDx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
LSRx(x5, x5, 63-15); // x5 = sign
|
||||
// get exp
|
||||
LSRx(x3, x1, 52); // x3 = exp11
|
||||
ANDw_mask(x3, x3, 0, 0b1010); //0x7ff
|
||||
MOV32w(x4, 0x7ff);
|
||||
CMPSw_REG(x3, x4);
|
||||
B_MARK2(cNE);
|
||||
// NaN and Infinite
|
||||
ORRw_mask(x3, x5, 0, 0b1110); //x3 = sign | 0x7fff
|
||||
TSTx_mask(x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
ORRx_mask(x4, xZR, 1, 0b10, 0b01); //0xc000000000000000
|
||||
CSELx(x5, x5, x4, cEQ); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// regular / denormals
|
||||
ANDx_mask(x1, x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
LSLx_IMM(x1, x1, 11); //x1 = mantisse missing "1"
|
||||
MOVZw(x4, 16383-1023); //BIAS80 - BIAS64
|
||||
CBZw(x3, 4+3*4); // exp11 == 0?
|
||||
// normals
|
||||
ADDw_REG(x3, x3, x4); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
#endif
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -36,6 +36,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -177,75 +178,77 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
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, &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, &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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &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, &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, &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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DEFAULT;
|
||||
break;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
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, &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, &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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &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, &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, &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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -40,6 +40,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -50,10 +51,20 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
#if 1
|
||||
if((nextop&7)==0 && PK(0)==0xD9 && PK(1)==0xF7) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FFREE ST0 / FINCSTP\n");
|
||||
x87_do_pop(dyn, ninst, x1);
|
||||
addr+=2;
|
||||
SKIPTEST(x1);
|
||||
} else
|
||||
x87_free(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOV32w(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1);
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -129,121 +140,95 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
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:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_I64);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
if(ST_IS_I64(0)) {
|
||||
VST64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// those are ARM 8.5 opcode!
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_I64);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
if(ST_IS_I64(0)) {
|
||||
VST64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
if(arm64_frintts) {
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
STRx_U12(x2, ed, fixedaddress);
|
||||
#else
|
||||
STx(x2, ed, fixedaddress);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTRRD(s0, v1, 3);
|
||||
FCVTZSxD(x2, s0);
|
||||
STx(x2, ed, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STx(x5, ed, fixedaddress);
|
||||
ORRx_mask(x2, xZR, 1, 1, 0); //0x8000000000000000
|
||||
MARK3;
|
||||
#endif
|
||||
STx(x2, ed, fixedaddress);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(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, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
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, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
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, &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) {
|
||||
// update top
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUBw_U12(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADDw_U12(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
ANDw_mask(x2, x2, 0, 2);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &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, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(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, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_frstor, -1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_fsave, -1);
|
||||
CALL(reset_fpu, -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, &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) {
|
||||
// update top
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUBw_U12(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADDw_U12(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
BFIw(x3, x2, 11, 3); // inject TOP at bit 11 (3 bits)
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
STH(x3, ed, fixedaddress); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
ANDw_mask(x2, x2, 0, 2);
|
||||
}
|
||||
BFIw(x3, x2, 11, 3); // inject TOP at bit 11 (3 bits)
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
STH(x3, ed, fixedaddress); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -36,6 +36,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -177,109 +178,102 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -41,6 +41,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -55,6 +56,25 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FSTP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS(v2, v1);
|
||||
} else {
|
||||
FMOVD(v2, v1);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
@@ -114,283 +134,245 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDSHw(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
SCVTFSw(v1, x1);
|
||||
} else {
|
||||
SCVTFDw(v1, x1);
|
||||
}
|
||||
break;
|
||||
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, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// this version needs ARM v8.5, //TODO: add detection of this extension to use it
|
||||
FRINT32ZD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDSHw(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
SCVTFSw(v1, x1);
|
||||
} else {
|
||||
SCVTFDw(v1, x1);
|
||||
}
|
||||
break;
|
||||
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, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
// this version needs ARM v8.5, and doesn't handle saturation for 32bits integer not fitting 16bits
|
||||
FRINT32ZD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
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);
|
||||
} else {
|
||||
VFCVTZSd(s0, v1);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
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_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
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);
|
||||
VFCVTZSs(s0, s0);
|
||||
} else {
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
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);
|
||||
} else {
|
||||
VFCVTZSd(s0, v1);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
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_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
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;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VST16(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTXS(s0, v1);
|
||||
VFCVTZSs(s0, s0);
|
||||
} else {
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
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);
|
||||
VFCVTZSs(s0, s0);
|
||||
} else {
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
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;
|
||||
case 3:
|
||||
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, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VST16(s0, wback, fixedaddress);
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTXS(s0, v1);
|
||||
VFCVTZSs(s0, s0);
|
||||
} else {
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
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_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbld, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_I64);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, wback, fixedaddress);
|
||||
if(!ST_IS_I64(0)) {
|
||||
if(rex.is32bits) {
|
||||
// need to also feed the STll stuff...
|
||||
ADDx_U12(x4, xEmu, offsetof(x64emu_t, fpu_ll));
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUBw_U12(x1, x1, -a);
|
||||
} else {
|
||||
ADDw_U12(x1, x1, a);
|
||||
}
|
||||
ANDw_mask(x1, x1, 0, 2); //mask=7
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
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_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbld, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_I64);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v1, wback, fixedaddress);
|
||||
if(!ST_IS_I64(0)) {
|
||||
if(rex.is32bits) {
|
||||
// need to also feed the STll stuff...
|
||||
ADDx_U12(x4, xEmu, offsetof(x64emu_t, fpu_ll));
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUBw_U12(x1, x1, -a);
|
||||
} else {
|
||||
ADDw_U12(x1, x1, a);
|
||||
}
|
||||
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
|
||||
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
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_I64);
|
||||
if(!ST_IS_I64(0)) {
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
SCVTFDD(v1, v1);
|
||||
if(rex.is32bits) {
|
||||
VSTR64_U12(v1, x1, 0); // ref
|
||||
}
|
||||
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(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
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_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(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);
|
||||
}
|
||||
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;
|
||||
ANDw_mask(x1, x1, 0, 2); //mask=7
|
||||
}
|
||||
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
|
||||
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);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
B_MARK3(c__);
|
||||
MARK2;
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STx(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -60,8 +60,13 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
MOV64xw(s3, c);
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(mask) {
|
||||
ORRxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -122,8 +127,13 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
MOV64xw(s3, c);
|
||||
EORxw_REG(s1, s1, s3);
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(mask) {
|
||||
EORxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
EORxw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -187,11 +197,20 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
MOV64xw(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(mask) {
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
ANDxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s3);
|
||||
MOV64xw(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s3);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -239,13 +258,18 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG(s1, s1, s3);
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ORRw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c&0xff);
|
||||
ORRw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -285,13 +309,18 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORw_REG(s1, s1, s3);
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
EORw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c&0xff);
|
||||
EORw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -342,16 +371,25 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s3);
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
ANDw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s3);
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s3);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
|
||||
@@ -297,8 +297,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRw(s3, s1, 8);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
BFXILw(xFlags, s1, 8, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -341,8 +340,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRw(s3, s1, 8);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
BFXILw(xFlags, s1, 8, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -478,8 +476,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRw(s3, s1, 16);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
BFXILw(xFlags, s1, 16, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
|
||||
@@ -82,6 +82,8 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -131,7 +133,12 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
if(c>7) {
|
||||
// the 0xff area will be 0, so PF is known
|
||||
MOV32w(s3, 1);
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
} else
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +192,8 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -193,12 +202,6 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFIw(xFlags, s1, 0, 1);
|
||||
@@ -223,8 +226,8 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
// no sign if c>0
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
@@ -238,6 +241,8 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -246,12 +251,6 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ASRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
@@ -309,7 +308,7 @@ void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1); // if s2==1
|
||||
IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
@@ -348,7 +347,7 @@ void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
@@ -430,8 +429,7 @@ void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit SHR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
if (!c) return;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -505,8 +503,7 @@ void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit SAR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
if (!c) return;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -570,7 +567,7 @@ void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1); // if s2==1
|
||||
IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
@@ -587,8 +584,7 @@ void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit SHL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
if (!c) return;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -610,7 +606,7 @@ void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
@@ -621,7 +617,12 @@ void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
if(c>7) {
|
||||
// the 0xff area will be 0, so PF is known
|
||||
MOV32w(s3, 1);
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
} else
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
@@ -760,8 +761,7 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit SAR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
if (!c) return;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -795,6 +795,9 @@ void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(rex); MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -827,6 +830,9 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -860,6 +866,9 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -867,15 +876,11 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
if(c&7) {
|
||||
int rc = 8-(c&7);
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
LSRw(s1, s1, rc);
|
||||
}
|
||||
int rc = 8-(c&7);
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
LSRw(s1, s1, rc);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -894,6 +899,9 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -901,14 +909,10 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
if(c&7) {
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
LSRw(s1, s1, c&7);
|
||||
}
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
LSRw(s1, s1, c&7);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -928,6 +932,9 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -935,9 +942,11 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int rc = 16-(c&15);
|
||||
ORRw_REG_LSL(s1, s1, s1, 16);
|
||||
LSRw(s1, s1, rc);
|
||||
if(c&15) {
|
||||
int rc = 16-(c&15);
|
||||
ORRw_REG_LSL(s1, s1, s1, 16);
|
||||
LSRw(s1, s1, rc);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -956,6 +965,9 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -963,8 +975,10 @@ void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG_LSL(s1, s1, s1, 16);
|
||||
LSRw(s1, s1, c&15);
|
||||
if(c&15) {
|
||||
ORRw_REG_LSL(s1, s1, s1, 16);
|
||||
LSRw(s1, s1, c&15);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -980,6 +994,203 @@ void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!(c%9)) return;
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
c%=9;
|
||||
BFIw(s1, xFlags, 8, 1); // insert cf
|
||||
IFX(X_OF|X_CF) {
|
||||
if(c!=8) {
|
||||
LSRw_IMM(s3, s1, 8-c);
|
||||
} else {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
}
|
||||
ORRw_REG_LSL(s1, s1, s1, 9); // insert s1 again
|
||||
LSRw_IMM(s1, s1, 9-c); // do the rcl
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_OF|X_CF) {
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
EORw_REG_LSR(s3, s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!(c%9)) return;
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
c%=9;
|
||||
IFX(X_OF) {
|
||||
MOVw_REG(s3, wFlags);
|
||||
}
|
||||
BFIw(s1, xFlags, 8, 1); // insert cf
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, s1, c-1, 1);
|
||||
}
|
||||
if(c>1) {
|
||||
ORRw_REG_LSL(s1, s1, s1, 9); // insert s1 again
|
||||
}
|
||||
LSRw_IMM(s1, s1, c); // do the rcr
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
EORw_REG_LSR(s3, s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!(c%17)) return;
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
c%=17;
|
||||
BFIw(s1, xFlags, 16, 1); // insert cf
|
||||
IFX(X_OF|X_CF) {
|
||||
if(c!=16) {
|
||||
LSRw_IMM(s3, s1, 16-c);
|
||||
} else {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
}
|
||||
ORRx_REG_LSL(s1, s1, s1, 17); // insert s1 again
|
||||
LSRx_IMM(s1, s1, 17-c); // do the rcl
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
EORw_REG_LSR(s3, s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!(c%17)) return;
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
c%=17;
|
||||
BFIw(s1, xFlags, 16, 1); // insert cf
|
||||
IFX(X_OF) {
|
||||
MOVw_REG(s3, wFlags);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILx(xFlags, s1, c-1, 1);
|
||||
}
|
||||
if(c>1) {
|
||||
ORRx_REG_LSL(s1, s1, s1, 17); // insert s1 again
|
||||
}
|
||||
LSRx_IMM(s1, s1, c); // do the rcr
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
EORw_REG_LSR(s3, s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL32/RCL64 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
IFX(X_OF|X_CF) {
|
||||
LSRxw_IMM(s3, s1, (rex.w?64:32)-c);
|
||||
}
|
||||
if(c==1) {
|
||||
LSLxw(s1, s1, 1);
|
||||
BFIxw(s1, xFlags, 0, 1);
|
||||
} else {
|
||||
LSLxw(s4, s1, c);
|
||||
BFIxw(s4, xFlags, c-1, 1);
|
||||
ORRxw_REG_LSR(s1, s4, s1, (rex.w?65:33)-c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
EORxw_REG_LSR(s3, s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// emit RCR32/RCR64 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
EORxw_REG_LSR(s3, xFlags, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILxw(s3, s1, c-1, 1);
|
||||
}
|
||||
if(c==1) {
|
||||
LSRxw(s1, s1, 1);
|
||||
BFIxw(s1, xFlags, rex.w?63:31, 1);
|
||||
} else {
|
||||
LSRxw(s4, s1, c);
|
||||
BFIxw(s4, xFlags, (rex.w?64:32)-c, 1);
|
||||
ORRxw_REG_LSL(s1, s4, s1, (rex.w?65:33)-c);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(wFlags, s3, 0, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
@@ -1022,9 +1233,8 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s4, s1, rex.w?63:31);
|
||||
EORw_REG_LSR(s4, s4, xFlags, F_OF); // set if sign changed
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
UBFXx(s3, s1, rex.w?63:31, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
@@ -1076,9 +1286,8 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
EORxw_REG_LSR(s3, s3, xFlags, F_OF); // OF is set if sign changed
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
UBFXx(s3, s1, rex.w?63:31, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
@@ -1127,10 +1336,9 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+3*4);
|
||||
LSRxw(s4, s1, rex.w?63:31);
|
||||
EORw_REG_LSR(s4, s4, xFlags, F_OF); // Set if sign changed
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
UBFXx(s3, s1, rex.w?63:31, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -1174,10 +1382,9 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+3*4);
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
EORxw_REG_LSR(s3, s3, xFlags, F_OF); // OF is set if sign changed
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
UBFXx(s3, s1, rex.w?63:31, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -1219,9 +1426,8 @@ void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRw(s4, s1, 15);
|
||||
EORw_REG_LSR(s4, s4, xFlags, F_OF); // set if sign changed
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
UBFXw(s3, s1, 15, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
@@ -1257,10 +1463,9 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+3*4);
|
||||
LSRw(s4, s1, 15);
|
||||
EORw_REG_LSR(s4, s4, xFlags, F_OF); // Set if sign changed
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
UBFXw(s3, s1, 15, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
@@ -1292,7 +1497,7 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
if(c<16)
|
||||
LSRw(s3, s1, 16-c);
|
||||
else
|
||||
MOVx_REG(s3, s1);
|
||||
LSRw(s3, s2, 32-c);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
@@ -1307,9 +1512,8 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRw(s3, s1, 15);
|
||||
EORw_REG_LSR(s3, s3, xFlags, F_OF); // OF is set if sign changed
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
UBFXw(s3, s1, 15, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
@@ -1328,20 +1532,18 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG_LSL(s1, s1, s2, 16); // create concat first
|
||||
IFX(X_CF) {
|
||||
MOVw_REG(s3, s1);
|
||||
CMPSw_U12(s5, 16);
|
||||
Bcond(cGE, 4+3*4);
|
||||
MOV32w(s3, 16);
|
||||
SUBw_REG(s3, s3, s5);
|
||||
LSRw_REG(s3, s1, s3);
|
||||
ORRw_REG_LSL(s4, s2, s1, 16);
|
||||
MOV32w(s3, 32);
|
||||
SUBw_REG(s3, s3, s5);
|
||||
LSRw_REG(s3, s4, s3);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_OF, 1); // store current sign for later use
|
||||
}
|
||||
ORRw_REG_LSL(s1, s1, s2, 16); // create concat first
|
||||
MOV32w(s3, 32);
|
||||
SUBw_REG(s3, s3, s5);
|
||||
RORw_REG(s1, s1, s3);
|
||||
@@ -1352,10 +1554,9 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+3*4);
|
||||
LSRw(s3, s1, 15);
|
||||
EORw_REG_LSR(s3, s3, xFlags, F_OF); // OF is set if sign changed
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
UBFXw(s3, s1, 15, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)rep; (void)need_epilog;
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
@@ -46,6 +46,10 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
while((opcode==0x36) || (opcode==0x2e) || (opcode==0x3E) || (opcode==0x26)) {
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
|
||||
GETREX();
|
||||
|
||||
@@ -96,6 +100,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALxw(gd, x1, wback);
|
||||
@@ -103,14 +117,27 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
STADDLxw(gd, wback);
|
||||
}
|
||||
SMDMB();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -214,7 +241,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARKLOCK;
|
||||
LDAXRB(ed, wback);
|
||||
LSRw_REG(x4, ed, x2);
|
||||
BFIw(xFlags, x5, F_CF, 1);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
LSLw_REG(x4, x5, x2);
|
||||
ORRw_REG(ed, ed, x4);
|
||||
STLXRB(x4, ed, wback);
|
||||
@@ -302,8 +329,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK3(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK3(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK3(cNE);
|
||||
}
|
||||
}
|
||||
// Aligned version
|
||||
if(arm64_atomics) {
|
||||
@@ -528,6 +561,52 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC0:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("LOCK XADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
GETEB(x2, 0);
|
||||
gd = x2; ed = x1; // swap gd/ed
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
GBBACK; // gb gets x2 (old ed)
|
||||
EBBACK; // eb gets x1 (sum)
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
MOVxw_REG(x3, gd);
|
||||
LDADDALB(x3, gd, wback);
|
||||
SMDMB();
|
||||
emit_add8(dyn, ninst, x3, gd, x4, x5);
|
||||
} else {
|
||||
LDADDALB(gd, gd, wback);
|
||||
SMDMB();
|
||||
}
|
||||
GBBACK;
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
ADDw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add8(dyn, ninst, x2, gd, x3, x4);
|
||||
}
|
||||
BFIz(gb1, x1, gb2, 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC1:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
@@ -544,8 +623,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
@@ -598,52 +683,99 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
MOVx_REG(x2, xRAX);
|
||||
MOVx_REG(x3, xRDX);
|
||||
MOVx_REG(x4, xRBX);
|
||||
MOVx_REG(x5, xRCX);
|
||||
CASPALxw(x2, x4, wback);
|
||||
UFLAG_IF {
|
||||
CMPSxw_REG(x2, xRAX);
|
||||
CCMPxw(x3, xRDX, 0, cEQ);
|
||||
CSETw(x1, cEQ);
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
if(rex.w) {
|
||||
TSTx_mask(wback, 1, 0, 3);
|
||||
B_MARK2(cNE);
|
||||
} else {
|
||||
ANDx_mask(x2, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x2, 8);
|
||||
B_MARK2(cGT);
|
||||
}
|
||||
MOVx_REG(xRAX, x2);
|
||||
MOVx_REG(xRDX, x3);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXPxw(x2, x3, wback);
|
||||
CMPSxw_REG(xRAX, x2);
|
||||
CCMPxw(xRDX, x3, 0, cEQ);
|
||||
B_MARK(cNE); // EAX!=ED[0] || EDX!=Ed[1]
|
||||
STLXPxw(x4, xRBX, xRCX, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
}
|
||||
TSTx_mask(wback, 1, 0, 2+rex.w); // mask=7 or F
|
||||
B_MARK2(cNE); // unaligned
|
||||
}
|
||||
MARK3;
|
||||
SMDMB();
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOVx_REG(x2, xRAX);
|
||||
MOVx_REG(x3, xRDX);
|
||||
MOVx_REG(x4, xRBX);
|
||||
MOVx_REG(x5, xRCX);
|
||||
CASPALxw(x2, x4, wback);
|
||||
UFLAG_IF {
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
CMPSxw_REG(x2, xRAX);
|
||||
CCMPxw(x3, xRDX, 0, cEQ);
|
||||
CSETw(x1, cEQ);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
MOVx_REG(xRAX, x2);
|
||||
MOVx_REG(xRDX, x3);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXPxw(x2, x3, wback);
|
||||
CMPSxw_REG(xRAX, x2);
|
||||
CCMPxw(xRDX, x3, 0, cEQ);
|
||||
B_MARK(cNE); // EAX!=ED[0] || EDX!=Ed[1]
|
||||
STLXPxw(x4, xRBX, xRCX, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
STLXPxw(x4, x2, x3, wback); // write back, to be sure it was "atomic"
|
||||
CBNZx_MARKLOCK(x4);
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
MARK2;
|
||||
LDPxw_S7_offset(x2, x3, wback, 0);
|
||||
LDAXRB(x5, wback);
|
||||
CMPSxw_REG(xRAX, x2);
|
||||
CCMPxw(xRDX, x3, 0, cEQ);
|
||||
B_MARKSEG(cNE); // EAX!=ED[0] || EDX!=Ed[1]
|
||||
STLXRB(x4, xRBX, wback);
|
||||
CBNZx_MARK2(x4);
|
||||
STPxw_S7_offset(xRBX, xRCX, wback, 0);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARKSEG;
|
||||
STLXRB(x4, x5, wback); //write back
|
||||
CBNZx_MARK2(x4);
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
}
|
||||
}
|
||||
MARK3;
|
||||
SMDMB();
|
||||
UFLAG_IF {
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -737,6 +869,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
NEGxw_REG(x1, gd);
|
||||
UFLAG_IF {
|
||||
@@ -753,6 +895,69 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("LOCK XOR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDEORALxw(gd, x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
} else {
|
||||
STEORLxw(gd, wback);
|
||||
}
|
||||
SMDMB();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -998,8 +1203,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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;
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x3, i64);
|
||||
@@ -1147,8 +1358,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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;
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x5, -i64);
|
||||
@@ -1277,8 +1494,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, ed, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
SWPALxw(gd, gd, ed);
|
||||
@@ -1419,8 +1642,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOV32w(x3, 1);
|
||||
@@ -1461,8 +1690,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x3, -1);
|
||||
|
||||
@@ -71,6 +71,7 @@ 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 {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
@@ -358,17 +359,27 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
|
||||
u8 = F8;
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
if(v0==v1) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQ(d0, v1);
|
||||
}
|
||||
VDUP_16(v0, v1, u8&3);
|
||||
if(v0==v1)
|
||||
v1 = d0;
|
||||
} else {
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
}
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
@@ -333,16 +333,20 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 1) ;
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+8)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+9)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
if (u8 == 0b00000000 || u8 == 0b01010101 || u8 == 0b10101010 || u8 == 0b11111111) {
|
||||
VDUPQ_16(d0, v1, (u8 & 3) + 4);
|
||||
} else {
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u64 = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
u64 |= ((uint64_t)((u8 >> (i * 2)) & 3) * 2 + 8) << (i * 16 + 0);
|
||||
u64 |= ((uint64_t)((u8 >> (i * 2)) & 3) * 2 + 9) << (i * 16 + 8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
}
|
||||
VMOVeD(v0, 1, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
|
||||
@@ -85,15 +85,19 @@ int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
|
||||
return i;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
static void fpu_reset_reg_neoncache(neoncache_t* n)
|
||||
{
|
||||
dyn->n.fpu_reg = 0;
|
||||
n->fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i) {
|
||||
dyn->n.fpuused[i]=0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
n->fpuused[i]=0;
|
||||
n->neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
}
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
fpu_reset_reg_neoncache(&dyn->n);
|
||||
}
|
||||
|
||||
int neoncache_no_i64(dynarec_arm_t* dyn, int ninst, int st, int a)
|
||||
{
|
||||
@@ -208,15 +212,13 @@ static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, a-dyn->insts[ninst].n.stack_push);
|
||||
// go forward is combined is not pop'd
|
||||
if(a-dyn->insts[ninst].n.stack_pop>=0)
|
||||
if(!dyn->insts[ninst+1].n.barrier)
|
||||
if(!((ninst+1<dyn->size) && dyn->insts[ninst+1].n.barrier))
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, a-dyn->insts[ninst].n.stack_pop);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
if(dyn->insts[ninst+1].n.barrier)
|
||||
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_i64(dyn, ninst, a);
|
||||
@@ -387,6 +389,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
// unswap
|
||||
int a = -1;
|
||||
int b = -1;
|
||||
// in neoncache
|
||||
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 || cache->neoncache[j].t == NEON_CACHE_ST_I64)) {
|
||||
if(cache->neoncache[j].n == cache->combined1)
|
||||
@@ -399,11 +402,12 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->neoncache[a].n = cache->neoncache[b].n;
|
||||
cache->neoncache[b].n = tmp;
|
||||
}
|
||||
// done
|
||||
cache->swapped = 0;
|
||||
cache->combined1 = cache->combined2 = 0;
|
||||
}
|
||||
if(cache->news) {
|
||||
// reove the newly created neoncache
|
||||
// remove the newly created neoncache
|
||||
for(int i=0; i<24; ++i)
|
||||
if(cache->news&(1<<i))
|
||||
cache->neoncache[i].v = 0;
|
||||
@@ -420,11 +424,23 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
}
|
||||
}
|
||||
cache->x87stack-=cache->stack_push;
|
||||
cache->tags>>=(cache->stack_push*2);
|
||||
cache->stack-=cache->stack_push;
|
||||
if(cache->pushed>=cache->stack_push)
|
||||
cache->pushed-=cache->stack_push;
|
||||
else
|
||||
cache->pushed = 0;
|
||||
cache->stack_push = 0;
|
||||
}
|
||||
cache->x87stack+=cache->stack_pop;
|
||||
cache->stack_next = cache->stack;
|
||||
if(cache->stack_pop) {
|
||||
if(cache->poped>=cache->stack_pop)
|
||||
cache->poped-=cache->stack_pop;
|
||||
else
|
||||
cache->poped = 0;
|
||||
cache->tags<<=(cache->stack_pop*2);
|
||||
}
|
||||
cache->stack_pop = 0;
|
||||
cache->barrier = 0;
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
@@ -537,7 +553,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
{
|
||||
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",
|
||||
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/%d)",
|
||||
(box64_dynarec_dump>1)?"\e[32m":"",
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address),
|
||||
dyn->insts[ninst].size/4,
|
||||
@@ -552,7 +568,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smread, dyn->smwrite);
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
|
||||
if(dyn->insts[ninst].pred_sz) {
|
||||
dynarec_log(LOG_NONE, ", pred=");
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)
|
||||
@@ -589,3 +605,60 @@ 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));
|
||||
}
|
||||
|
||||
static void x87_reset(neoncache_t* n)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
n->x87cache[i] = -1;
|
||||
n->tags = 0;
|
||||
n->x87stack = 0;
|
||||
n->stack = 0;
|
||||
n->stack_next = 0;
|
||||
n->stack_pop = 0;
|
||||
n->stack_push = 0;
|
||||
n->combined1 = n->combined2 = 0;
|
||||
n->swapped = 0;
|
||||
n->barrier = 0;
|
||||
n->pushed = 0;
|
||||
n->poped = 0;
|
||||
|
||||
for(int i=0; i<24; ++i)
|
||||
if(n->neoncache[i].t == NEON_CACHE_ST_F
|
||||
|| n->neoncache[i].t == NEON_CACHE_ST_D
|
||||
|| n->neoncache[i].t == NEON_CACHE_ST_I64)
|
||||
n->neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
static void mmx_reset(neoncache_t* n)
|
||||
{
|
||||
n->mmxcount = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
n->mmxcache[i] = -1;
|
||||
}
|
||||
|
||||
static void sse_reset(neoncache_t* n)
|
||||
{
|
||||
for (int i=0; i<16; ++i)
|
||||
n->ssecache[i].v = -1;
|
||||
}
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
x87_reset(&dyn->n);
|
||||
mmx_reset(&dyn->n);
|
||||
sse_reset(&dyn->n);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
void fpu_reset_ninst(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
x87_reset(&dyn->insts[ninst].n);
|
||||
mmx_reset(&dyn->insts[ninst].n);
|
||||
sse_reset(&dyn->insts[ninst].n);
|
||||
fpu_reset_reg_neoncache(&dyn->insts[ninst].n);
|
||||
}
|
||||
|
||||
int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st)
|
||||
{
|
||||
return (dyn->n.tags&(0b11<<(st*2)))?1:0;
|
||||
}
|
||||
@@ -54,4 +54,11 @@ const char* getCacheName(int t, int n);
|
||||
|
||||
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);
|
||||
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_native_t* dyn);
|
||||
void fpu_reset_ninst(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
// is st freed
|
||||
int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st);
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
@@ -57,7 +57,7 @@ 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))) || !(unscaled && (tmp>-256) && (tmp<256))) {
|
||||
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 {
|
||||
@@ -212,7 +212,7 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
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))) {
|
||||
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 {
|
||||
@@ -348,7 +348,7 @@ 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))) || !(unscaled && (tmp>-256) && (tmp<256))) {
|
||||
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 {
|
||||
@@ -564,7 +564,7 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void jump_to_next(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, int is32bits)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
@@ -575,15 +575,17 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
MOVx_REG(xRIP, reg);
|
||||
}
|
||||
NOTEST(x2);
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
uintptr_t tbl = is32bits?getJumpTable32():getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
TABLE64(x3, tbl);
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x2, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
#endif
|
||||
UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
if(!is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x2, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
#endif
|
||||
UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
}
|
||||
UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
@@ -617,24 +619,24 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_offset(x2, x6, xSP, 0);
|
||||
CBZx(x6, 6*4);
|
||||
ADDx_U12(xSP, xSP, 16);
|
||||
LDPx_S7_postindex(x2, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
BLR(x2);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
SUBx_U12(xSP, xSavedSP, 0);
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
uintptr_t tbl = rex.is32bits?getJumpTable32():getJumpTable64();
|
||||
NOTEST(x2);
|
||||
MOV64x(x2, tbl);
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
#endif
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
if(!rex.is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
#endif
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
}
|
||||
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
@@ -660,24 +662,24 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_offset(x2, x6, xSP, 0);
|
||||
CBZx(x6, 6*4);
|
||||
ADDx_U12(xSP, xSP, 16);
|
||||
LDPx_S7_postindex(x2, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
BLR(x2);
|
||||
// not the correct return address, regular jump
|
||||
SUBx_U12(xSP, xSavedSP, 0);
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
uintptr_t tbl = rex.is32bits?getJumpTable32():getJumpTable64();
|
||||
NOTEST(x2);
|
||||
MOV64x(x2, tbl);
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
#endif
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
if(!rex.is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
#endif
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
}
|
||||
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
@@ -694,6 +696,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "IRet to epilog\n");
|
||||
SMEND();
|
||||
SET_DFNONE(x2);
|
||||
// POP IP
|
||||
NOTEST(x2);
|
||||
if(is64bits) {
|
||||
@@ -774,7 +777,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
SET_NODF();
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
@@ -820,7 +823,7 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
|
||||
fpu_popcache(dyn, ninst, x3, 1);
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
SET_NODF();
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment)
|
||||
@@ -849,25 +852,6 @@ void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int se
|
||||
}
|
||||
|
||||
// x87 stuffs
|
||||
static void x87_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->n.x87cache[i] = -1;
|
||||
dyn->n.x87stack = 0;
|
||||
dyn->n.stack = 0;
|
||||
dyn->n.stack_next = 0;
|
||||
dyn->n.stack_pop = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;
|
||||
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
|
||||
|| dyn->n.neoncache[i].t == NEON_CACHE_ST_I64)
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
int x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
{
|
||||
MAYUSE(scratch);
|
||||
@@ -910,7 +894,7 @@ void x87_unstackcount(dynarec_arm_t* dyn, int ninst, int scratch, int count)
|
||||
return;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, scratch);
|
||||
MESSAGE(LOG_DUMP, "\tUnsynch x87 Stackcount (%d)\n", count);
|
||||
MESSAGE(LOG_DUMP, "\tUnsynch x87 Unstackcount (%d)\n", count);
|
||||
int a = -count;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(scratch, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
@@ -958,6 +942,9 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
dyn->n.stack+=1;
|
||||
dyn->n.stack_next+=1;
|
||||
dyn->n.stack_push+=1;
|
||||
++dyn->n.pushed;
|
||||
if(dyn->n.poped)
|
||||
--dyn->n.poped;
|
||||
// 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)
|
||||
@@ -965,7 +952,8 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
||(dyn->n.neoncache[j].t == NEON_CACHE_ST_I64))
|
||||
++dyn->n.neoncache[j].n;
|
||||
int ret = -1;
|
||||
for(int i=0; i<8; ++i)
|
||||
dyn->n.tags<<=2;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(dyn->n.x87cache[i]!=-1)
|
||||
++dyn->n.x87cache[i];
|
||||
else if(ret==-1) {
|
||||
@@ -973,6 +961,11 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
ret=dyn->n.x87reg[i]=fpu_get_reg_x87(dyn, t, 0);
|
||||
dyn->n.neoncache[ret].t = X87_ST0;
|
||||
}
|
||||
}
|
||||
if(ret==-1) {
|
||||
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
|
||||
dyn->abort = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
@@ -983,26 +976,30 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
dyn->n.stack+=1;
|
||||
dyn->n.stack_next+=1;
|
||||
dyn->n.stack_push+=1;
|
||||
++dyn->n.pushed;
|
||||
if(dyn->n.poped)
|
||||
--dyn->n.poped;
|
||||
// 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)
|
||||
||(dyn->n.neoncache[j].t == NEON_CACHE_ST_I64))
|
||||
++dyn->n.neoncache[j].n;
|
||||
for(int i=0; i<8; ++i)
|
||||
int ret = -1;
|
||||
dyn->n.tags<<=2;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(dyn->n.x87cache[i]!=-1)
|
||||
++dyn->n.x87cache[i];
|
||||
if(s1)
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
else if(ret==-1)
|
||||
ret = i;
|
||||
}
|
||||
if(ret==-1) {
|
||||
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
|
||||
dyn->abort = 1;
|
||||
}
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
void static internal_x87_dopop(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
dyn->n.x87stack-=1;
|
||||
dyn->n.stack_next-=1;
|
||||
dyn->n.stack_pop+=1;
|
||||
// move all regs in cache, poping ST0
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
--dyn->n.x87cache[i];
|
||||
@@ -1012,7 +1009,37 @@ void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int static internal_x87_dofree(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->n.tags&0b11) {
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 FREED ST0, poping 1 more\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
do {
|
||||
dyn->n.x87stack-=1;
|
||||
dyn->n.stack_next-=1;
|
||||
dyn->n.stack_pop+=1;
|
||||
dyn->n.tags>>=2;
|
||||
++dyn->n.poped;
|
||||
if(dyn->n.pushed)
|
||||
--dyn->n.pushed;
|
||||
// move all regs in cache, poping ST0
|
||||
internal_x87_dopop(dyn);
|
||||
} while(internal_x87_dofree(dyn));
|
||||
}
|
||||
static int x87_is_stcached(dynarec_arm_t* dyn, int st)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i] == st)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1025,8 +1052,9 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
int a = dyn->n.x87stack;
|
||||
if(a!=0) {
|
||||
// reset x87stack
|
||||
if(!next)
|
||||
if(!next) {
|
||||
dyn->n.x87stack = 0;
|
||||
}
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
@@ -1037,30 +1065,33 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags (and top at the same time)
|
||||
if(a>0) {
|
||||
// new tag to fulls
|
||||
MOVZw(s3, 0);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, p_regs));
|
||||
for (int i=0; i<a; ++i) {
|
||||
SUBw_U12(s2, s2, 1);
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + st)&7
|
||||
STRw_REG_LSL2(s3, s1, s2);
|
||||
}
|
||||
SUBw_U12(s2, s2, a);
|
||||
} else {
|
||||
// empty tags
|
||||
MOVZw(s3, 0b11);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, p_regs));
|
||||
for (int i=0; i<-a; ++i) {
|
||||
STRw_REG_LSL2(s3, s1, s2);
|
||||
ADDw_U12(s2, s2, 1);
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + st)&7
|
||||
}
|
||||
ADDw_U12(s2, s2, -a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2);
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
LSLw_IMM(s1, s1, a*2);
|
||||
} else {
|
||||
ORRw_mask(s1, s1, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(s1, s1, -a*2);
|
||||
}
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
} else {
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
}
|
||||
// check if free is used
|
||||
if(dyn->n.tags) {
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
MOV32w(s3, dyn->n.tags);
|
||||
ORRw_REG(s1, s1, s3);
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
}
|
||||
|
||||
if(ret!=0) {
|
||||
// --- set values
|
||||
// prepare offset to fpu => s1
|
||||
@@ -1069,29 +1100,34 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
// loop all cache entries
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
int st = dyn->n.x87cache[i]+dyn->n.stack_pop;
|
||||
#if STEP == 1
|
||||
if(!next) { // don't force promotion here
|
||||
// pre-apply pop, because purge happens in-between
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.x87cache[i]+dyn->n.stack_pop);
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
}
|
||||
#endif
|
||||
#if STEP == 3
|
||||
if(!next && neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[i])>=0) {
|
||||
MESSAGE(LOG_DUMP, "Warning, incoherency with purged ST%d cache\n", dyn->n.x87cache[i]);
|
||||
if(!next && neoncache_get_current_st(dyn, ninst, st)!=NEON_CACHE_ST_D) {
|
||||
MESSAGE(LOG_DUMP, "Warning, incoherency with purged ST%d cache\n", st);
|
||||
}
|
||||
#endif
|
||||
ADDw_U12(s3, s2, dyn->n.x87cache[i]);
|
||||
ADDw_U12(s3, s2, dyn->n.x87cache[i]); // unadjusted count, as it's relative to real top
|
||||
ANDw_mask(s3, s3, 0, 2); //mask=7 // (emu->top + st)&7
|
||||
if(next) {
|
||||
// need to check if a ST_F need local promotion
|
||||
if(neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[i])>=0) {
|
||||
FCVT_D_S(0, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(0, s1, s3); // save the value
|
||||
} else {
|
||||
switch(neoncache_get_current_st(dyn, ninst, st)) {
|
||||
case NEON_CACHE_ST_D:
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[i], s1, s3); // save the value
|
||||
}
|
||||
} else {
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[i], s1, s3);
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
FCVT_D_S(SCRATCH, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s3); // save the value
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
SCVTFDD(SCRATCH, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s3); // save the value
|
||||
break;
|
||||
}
|
||||
if(!next) {
|
||||
fpu_free_reg(dyn, dyn->n.x87reg[i]);
|
||||
dyn->n.x87reg[i] = -1;
|
||||
dyn->n.x87cache[i] = -1;
|
||||
@@ -1101,9 +1137,13 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
}
|
||||
if(!next) {
|
||||
dyn->n.stack_next = 0;
|
||||
dyn->n.tags = 0;
|
||||
#if STEP < 2
|
||||
// refresh the cached valued, in case it's a purge outside a instruction
|
||||
dyn->insts[ninst].n.barrier = 1;
|
||||
dyn->n.pushed = 0;
|
||||
dyn->n.poped = 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---Purge x87 Cache and Synch Stackcount\n");
|
||||
@@ -1131,6 +1171,15 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
LSLw_IMM(s1, s1, a*2);
|
||||
} else {
|
||||
ORRw_mask(s1, s1, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(s1, s1, -a*2);
|
||||
}
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
}
|
||||
int ret = 0;
|
||||
for (int i=0; (i<8) && (!ret); ++i)
|
||||
@@ -1179,6 +1228,15 @@ static void x87_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, in
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
ORRw_mask(s1, s1, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(s1, s1, a*2);
|
||||
} else {
|
||||
LSLw_IMM(s1, s1, -a*2);
|
||||
}
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,38 +1313,6 @@ int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t
|
||||
return dyn->n.x87reg[x87_get_cache(dyn, ninst, 0, s1, s2, a, t)];
|
||||
}
|
||||
|
||||
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i] == st)
|
||||
ret = i;
|
||||
if(ret==-1) // nothing to do
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// Update
|
||||
if(st) {
|
||||
ADDw_U12(s2, s2, st);
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
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);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 Cache for ST%d\n", st);
|
||||
}
|
||||
|
||||
void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
int ret = -1;
|
||||
@@ -1316,11 +1342,11 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(31, reg);
|
||||
VSTR64_REG_LSL3(31, s1, s2);
|
||||
FCVT_D_S(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
} else if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_I64) {
|
||||
SCVTFDD(31, reg);
|
||||
VSTR64_REG_LSL3(31, s1, s2);
|
||||
SCVTFDD(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
} else {
|
||||
VSTR64_REG_LSL3(reg, s1, s2);
|
||||
}
|
||||
@@ -1382,6 +1408,66 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
MESSAGE(LOG_DUMP, "\t-------x87 Cache for ST%d\n", st);
|
||||
}
|
||||
|
||||
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st)
|
||||
{
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i] == st)
|
||||
ret = i;
|
||||
MESSAGE(LOG_DUMP, "\tFFREE%s x87 Cache for ST%d\n", (ret!=-1)?" (and Forget)":"", st);
|
||||
if(ret!=-1) {
|
||||
const int reg = dyn->n.x87reg[ret];
|
||||
#if STEP == 1
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F || dyn->n.neoncache[reg].t==NEON_CACHE_ST_I64)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// Update
|
||||
int ast = st - dyn->n.x87stack;
|
||||
if(ast) {
|
||||
if(ast>0) {
|
||||
ADDw_U12(s2, s2, ast);
|
||||
} else {
|
||||
SUBw_U12(s2, s2, -ast);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
} else if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_I64) {
|
||||
SCVTFDD(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
} else {
|
||||
VSTR64_REG_LSL3(reg, s1, s2);
|
||||
}
|
||||
// and forget that cache
|
||||
fpu_free_reg(dyn, reg);
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
dyn->n.x87cache[ret] = -1;
|
||||
dyn->n.x87reg[ret] = -1;
|
||||
} else {
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// Update
|
||||
int ast = st - dyn->n.x87stack;
|
||||
if(ast) {
|
||||
if(ast>0) {
|
||||
ADDw_U12(s2, s2, ast);
|
||||
} else {
|
||||
SUBw_U12(s2, s2, -ast);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
}
|
||||
// add mark in the freed array
|
||||
dyn->n.tags |= 0b11<<(st*2);
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 FFREE for ST%d\n", st);
|
||||
}
|
||||
|
||||
void x87_swapreg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int b)
|
||||
{
|
||||
int i1, i2, i3;
|
||||
@@ -1442,12 +1528,6 @@ void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
}
|
||||
|
||||
// MMX helpers
|
||||
static void mmx_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->n.mmxcount = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->n.mmxcache[i] = -1;
|
||||
}
|
||||
static int isx87Empty(dynarec_arm_t* dyn)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
@@ -1514,11 +1594,6 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
|
||||
|
||||
// SSE / SSE2 helpers
|
||||
static void sse_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
for (int i=0; i<16; ++i)
|
||||
dyn->n.ssecache[i].v = -1;
|
||||
}
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite)
|
||||
{
|
||||
@@ -1737,7 +1812,6 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
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
|
||||
if(quad) {
|
||||
VMOVQ(SCRATCH, i);
|
||||
VMOVQ(i, j);
|
||||
@@ -1912,43 +1986,6 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
int stack_cnt = dyn->n.stack_next;
|
||||
int s3_top = 0xffff;
|
||||
if(stack_cnt != cache_i2.stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d -\n", stack_cnt, cache_i2.stack);
|
||||
int a = stack_cnt - cache_i2.stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADDw_U12(s3, s3, a);
|
||||
} else {
|
||||
SUBw_U12(s3, s3, -a);
|
||||
}
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags (and top at the same time)
|
||||
if(a>0) {
|
||||
// new tag to fulls
|
||||
MOVZw(s2, 0);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, p_regs));
|
||||
for (int i=0; i<a; ++i) {
|
||||
SUBw_U12(s3, s3, 1);
|
||||
ANDw_mask(s3, s3, 0, 2); // (emu->top + st)&7
|
||||
STRw_REG_LSL2(s2, s1, s3); // that slot is full
|
||||
}
|
||||
} else {
|
||||
// empty tags
|
||||
MOVZw(s2, 0b11);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, p_regs));
|
||||
for (int i=0; i<-a; ++i) {
|
||||
STRw_REG_LSL2(s2, s1, s3); // empty slot before leaving it
|
||||
ADDw_U12(s3, s3, 1);
|
||||
ANDw_mask(s3, s3, 0, 2); // (emu->top + st)&7
|
||||
}
|
||||
}
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, top));
|
||||
s3_top = 0;
|
||||
stack_cnt = cache_i2.stack;
|
||||
}
|
||||
neoncache_t cache = dyn->n;
|
||||
int s1_val = 0;
|
||||
int s2_val = 0;
|
||||
@@ -2019,6 +2056,38 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
}
|
||||
if(stack_cnt != cache_i2.stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d -\n", stack_cnt, cache_i2.stack);
|
||||
int a = stack_cnt - cache_i2.stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADDw_U12(s3, s3, a);
|
||||
} else {
|
||||
SUBw_U12(s3, s3, -a);
|
||||
}
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, top));
|
||||
if(a>0) {
|
||||
SUBw_U12(s3, s3, a);
|
||||
} else {
|
||||
ADDw_U12(s3, s3, -a);
|
||||
}
|
||||
ANDw_mask(s3, s3, 0, 2); //mask=7
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags
|
||||
LDRH_U12(s2, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
LSLw_IMM(s2, s2, a*2);
|
||||
} else {
|
||||
ORRw_mask(s2, s2, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(s2, s2, -a*2);
|
||||
}
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
s3_top = 0;
|
||||
stack_cnt = cache_i2.stack;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
#endif
|
||||
}
|
||||
@@ -2086,14 +2155,6 @@ void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
x87_unreflectcache(dyn, ninst, s1, s2, s3);
|
||||
}
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
x87_reset(dyn);
|
||||
mmx_reset(dyn);
|
||||
sse_reset(dyn);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
@@ -2109,6 +2170,82 @@ void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
|
||||
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val)
|
||||
{
|
||||
// simple cases with only 1 operations
|
||||
for(int i=0; i<2; ++i)
|
||||
if((val&(0xFFFF<<(i*16)))==val) {
|
||||
MOVZw_LSL(reg, (val>>(i*16))&0xFFFF, i*16);
|
||||
return;
|
||||
}
|
||||
// same but with negation
|
||||
for(int i=0; i<2; ++i)
|
||||
if(((~val)&(0xFFFF<<(i*16)))==(~val)) {
|
||||
MOVNw_LSL(reg, ((~val)>>(i*16))&0xFFFF, i*16);
|
||||
return;
|
||||
}
|
||||
// generic cases
|
||||
int mask = convert_bitmask_w(val);
|
||||
if(mask) {
|
||||
ORRw_mask(reg, xZR, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOVZw(reg, val&0xFFFF);
|
||||
MOVKw_LSL(reg, (val>>16)&0xFFFF, 16);
|
||||
}
|
||||
}
|
||||
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val)
|
||||
{
|
||||
// simple cases with only 1 operations
|
||||
for(int i=0; i<4; ++i)
|
||||
if((val&(0xFFFFLL<<(i*16)))==val) {
|
||||
MOVZx_LSL(reg, (val>>(i*16))&0xFFFF, i*16);
|
||||
return;
|
||||
}
|
||||
// same but with negation
|
||||
for(int i=0; i<4; ++i)
|
||||
if(((~val)&(0xFFFFLL<<(i*16)))==(~val)) {
|
||||
MOVNx_LSL(reg, ((~val)>>(i*16))&0xFFFF, i*16);
|
||||
return;
|
||||
}
|
||||
// mask
|
||||
int mask = convert_bitmask_x(val);
|
||||
if(mask) {
|
||||
ORRx_mask(reg, xZR, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
return;
|
||||
}
|
||||
// 32bit value?
|
||||
if((val&0xFFFFFFFF)==val) {
|
||||
arm64_move32(dyn, ninst, reg, val);
|
||||
return;
|
||||
}
|
||||
int n = 0;
|
||||
// negatives values
|
||||
if((val&0xFFFF000000000000LL)==0xFFFF000000000000LL) {
|
||||
for(int i=0; i<3; ++i) {
|
||||
if(((~val)>>(i*16))&0xFFFF) {
|
||||
if(n) {
|
||||
MOVKx_LSL(reg, (val>>(i*16))&0xFFFF, i*16);
|
||||
} else {
|
||||
MOVNx_LSL(reg, ((~val)>>(i*16))&0xFFFF, i*16);
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// positive values
|
||||
for(int i=0; i<4; ++i) {
|
||||
if((val>>(i*16))&0xFFFF) {
|
||||
if(n) {
|
||||
MOVKx_LSL(reg, (val>>(i*16))&0xFFFF, i*16);
|
||||
} else {
|
||||
MOVZx_LSL(reg, (val>>(i*16))&0xFFFF, i*16);
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
@@ -2116,8 +2253,14 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int 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;
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
#if STEP == 0
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "New x87stack=%d\n", dyn->n.x87stack);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
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=");
|
||||
@@ -2147,9 +2290,6 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
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
|
||||
|
||||
@@ -33,31 +33,57 @@
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
|
||||
// Strong mem emulation helpers
|
||||
#define SMREAD_MIN 2
|
||||
#define SMWRITE_MIN 1
|
||||
// Sequence of Read will trigger a DMB on "first" read if strongmem is >= SMREAD_MIN
|
||||
#define SMREAD_VAL 4
|
||||
#define SMWRITE2_MIN 1
|
||||
#define SMFIRST_MIN 1
|
||||
#define SMSEQ_MIN 2
|
||||
#define SMSEQ_MAX 3
|
||||
#if STEP == 1
|
||||
// pass 1 has the jump point available
|
||||
#define SMWRITE() dyn->insts[ninst].will_write = 1; dyn->smwrite = 1
|
||||
#define SMREAD()
|
||||
#define SMREADLOCK(lock)
|
||||
#define SMMIGHTREAD()
|
||||
#define WILLWRITE2() if(box64_dynarec_strongmem>SMWRITE2_MIN) {WILLWRITE();}
|
||||
#define SMWRITE2() if(box64_dynarec_strongmem>SMWRITE2_MIN) {SMWRITE();}
|
||||
#define SMWRITELOCK(lock) SMWRITE()
|
||||
#define WILLWRITELOCK(lock)
|
||||
#define WILLWRITE()
|
||||
#define SMMIGHTWRITE() if(!MODREG) {SMWRITE();}
|
||||
#define SMSTART() dyn->smwrite = 0; dyn->smread = 0;
|
||||
#define SMEND() if(dyn->smwrite && (box64_dynarec_strongmem>SMFIRST_MIN)) {int i = ninst; while(i>=0 && !dyn->insts[i].will_write) --i; if(i>=0) {dyn->insts[i].last_write = 1;}} dyn->smwrite = 0
|
||||
#define SMDMB()
|
||||
#else
|
||||
// Sequence of Write will trigger a DMB on "last" write if strongmem is >= 1
|
||||
// All Write operation that might use a lock all have a memory barrier if strongmem is >= SMWRITE_MIN
|
||||
// Block will trigget at 1st and last if strongmem is >= SMFIRST_MIN
|
||||
// Read will contribute to trigger a DMB on "first" read if strongmem is >= SMREAD_MIN
|
||||
// Opcode will read
|
||||
#define SMREAD() if((dyn->smread==0) && (box64_dynarec_strongmem>SMREAD_MIN)) {SMDMB();} else dyn->smread=1
|
||||
#define SMREAD() if(dyn->insts[ninst].will_write) {WILLWRITE();} else if(box64_dynarec_strongmem==SMREAD_VAL && !dyn->smread) {DSB_SY(); dyn->smread = 1;}
|
||||
// Opcode will read with option forced lock
|
||||
#define SMREADLOCK(lock) if((lock) || ((dyn->smread==0) && (box64_dynarec_strongmem>SMREAD_MIN))) {SMDMB();}
|
||||
#define SMREADLOCK(lock) if((lock)) {SMWRITELOCK(lock);} else {SMREAD();}
|
||||
// Opcode might read (depend on nextop)
|
||||
#define SMMIGHTREAD() if(!MODREG) {SMREAD();}
|
||||
// Opcode has wrote
|
||||
#define SMWRITE() dyn->smwrite=1
|
||||
#define SMWRITE() if((box64_dynarec_strongmem>=SMFIRST_MIN) && dyn->smwrite==0 && (box64_dynarec_strongmem!=SMREAD_VAL)) {SMDMB();} if(box64_dynarec_strongmem>SMSEQ_MIN && (box64_dynarec_strongmem!=SMREAD_VAL)) {if(++dyn->smwrite>=SMSEQ_MAX) {SMDMB(); dyn->smwrite=1;}} else dyn->smwrite=1
|
||||
// Opcode has wrote (strongmem>1 only)
|
||||
#define SMWRITE2() if(box64_dynarec_strongmem>SMREAD_MIN) dyn->smwrite=1
|
||||
#define WILLWRITE2() if(box64_dynarec_strongmem>SMWRITE2_MIN) {WILLWRITE();}
|
||||
#define SMWRITE2() if(box64_dynarec_strongmem>SMWRITE2_MIN) {SMWRITE();}
|
||||
// Opcode has wrote with option forced lock
|
||||
#define SMWRITELOCK(lock) if(lock || (box64_dynarec_strongmem>SMWRITE_MIN)) {SMDMB();} else dyn->smwrite=1
|
||||
#define SMWRITELOCK(lock) if(lock) {SMDMB(); dyn->smwrite=1;} else {SMWRITE();}
|
||||
// Opcode has wrote with option forced lock
|
||||
#define WILLWRITELOCK(lock) if(lock) {DMB_ISH();} else {WILLWRITE();}
|
||||
// Opcode might have wrote (depend on nextop)
|
||||
#define SMMIGHTWRITE() if(!MODREG) {SMWRITE();}
|
||||
// Opcode will write (without reading)
|
||||
#define WILLWRITE() if((box64_dynarec_strongmem>=SMFIRST_MIN) && dyn->smwrite==0 && (box64_dynarec_strongmem!=SMREAD_VAL)) {SMDMB();} else if(box64_dynarec_strongmem>=SMFIRST_MIN && dyn->insts[ninst].last_write && (box64_dynarec_strongmem!=SMREAD_VAL)) {SMDMB();} dyn->smwrite=1
|
||||
// Start of sequence
|
||||
#define SMSTART() SMEND()
|
||||
// End of sequence
|
||||
#define SMEND() if(dyn->smwrite && box64_dynarec_strongmem) {if(box64_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();}} dyn->smwrite=0; dyn->smread=0;
|
||||
#define SMEND() if(dyn->smwrite && box64_dynarec_strongmem && (box64_dynarec_strongmem!=SMREAD_VAL)) {DMB_ISH();} dyn->smwrite=0; dyn->smread=0
|
||||
// Force a Data memory barrier (for LOCK: prefix)
|
||||
#define SMDMB() if(box64_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();} dyn->smwrite=0; dyn->smread=1
|
||||
#define SMDMB() if(box64_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();} dyn->smwrite=0; dyn->smread=0
|
||||
|
||||
#endif
|
||||
|
||||
//LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
@@ -254,6 +280,21 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETEWO will use i for ed, i is also Offset, and can use r3 for wback.
|
||||
#define GETEWO(i, D) if(MODREG) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);\
|
||||
UXTHw(i, wback); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, D); \
|
||||
ADDx_REG(x3, wback, i); \
|
||||
if(wback!=x3) wback = x3; \
|
||||
LDH(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
|
||||
#define GETSEW(i, D) if(MODREG) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);\
|
||||
@@ -400,7 +441,7 @@
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLD128(a, ed, fixedaddress); \
|
||||
@@ -419,7 +460,7 @@
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
VLD64(a, ed, fixedaddress); \
|
||||
@@ -433,7 +474,7 @@
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
VLD32(a, ed, fixedaddress); \
|
||||
@@ -447,7 +488,7 @@
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, D); \
|
||||
VLD16(a, ed, fixedaddress); \
|
||||
@@ -484,7 +525,7 @@
|
||||
TSTw_mask(xFlags, 0b010110, 0); \
|
||||
CNEGx(r, r, cNE)
|
||||
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&((1<<(2+rex.w)-1)))) || box64_dynarec_aligned_atomics)
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || box64_dynarec_aligned_atomics)
|
||||
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || box64_dynarec_aligned_atomics)
|
||||
|
||||
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
@@ -650,6 +691,7 @@
|
||||
CBNZx(reg, j64)
|
||||
|
||||
#define IFX(A) if((dyn->insts[ninst].x64.gen_flags&(A)))
|
||||
#define IFX2(A, B) if((dyn->insts[ninst].x64.gen_flags&(A)) B)
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.gen_flags&(X_PEND) || !dyn->insts[ninst].x64.gen_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x64.gen_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x64.gen_flags==(A) || dyn->insts[ninst].x64.gen_flags==(B) || dyn->insts[ninst].x64.gen_flags==((A)|(B))))
|
||||
@@ -660,12 +702,12 @@
|
||||
LDRH_U12(s3, xEmu, offsetof(x64emu_t, sw)); /*offset is 8bits right?*/\
|
||||
MOV32w(s1, 0b0100011100000000); \
|
||||
BICw_REG(s3, s3, s1); \
|
||||
/* greater than leave 0 */ \
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
|
||||
MOV32w(s2, 0b01000101); /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
MOV32w(s2, 0b01000000); /* zero */ \
|
||||
CSELw(s1, s2, s1, cEQ); \
|
||||
/* greater than leave 0 */ \
|
||||
MOV32w(s2, 0b01000101); /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
ORRw_REG_LSL(s3, s3, s1, 8); \
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, sw))
|
||||
|
||||
@@ -765,26 +807,35 @@
|
||||
LDP_REGS(R12, R13); \
|
||||
LDP_REGS(R14, R15)
|
||||
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if (dyn->n.stack == +8) { \
|
||||
*ok = 0; \
|
||||
break; \
|
||||
} \
|
||||
var = x87_do_push(dyn, ninst, scratch, t);
|
||||
#if STEP == 0
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) var = x87_do_push(dyn, ninst, scratch, t)
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) x87_do_push_empty(dyn, ninst, scratch)
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) x87_do_pop(dyn, ninst, scratch)
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
var = x87_do_push(dyn, ninst, scratch, t)
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if (dyn->n.stack == +8) { \
|
||||
*ok = 0; \
|
||||
break; \
|
||||
} \
|
||||
x87_do_push_empty(dyn, ninst, scratch);
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_push_empty(dyn, ninst, scratch)
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if (dyn->n.stack == -8) { \
|
||||
*ok = 0; \
|
||||
break; \
|
||||
} \
|
||||
x87_do_pop(dyn, ninst, scratch);
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_pop(dyn, ninst, scratch)
|
||||
#endif
|
||||
|
||||
#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) \
|
||||
@@ -830,6 +881,8 @@
|
||||
if(dyn->insts[ninst].x64.gen_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_SET_DF: dyn->f.pending = SF_SET; dyn->f.dfnone = 1; break; \
|
||||
case SF_SET_NODF: dyn->f.pending = SF_SET; dyn->f.dfnone = 0; break; \
|
||||
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
|
||||
case SF_SUBSET_PENDING: \
|
||||
case SF_SET_PENDING: \
|
||||
@@ -868,13 +921,14 @@
|
||||
#define FTABLE64(A, V)
|
||||
#endif
|
||||
|
||||
#define ARCH_INIT() \
|
||||
dyn->doublepush = 0; \
|
||||
#define ARCH_INIT() \
|
||||
dyn->smread = dyn->smwrite = 0; \
|
||||
dyn->doublepush = 0; \
|
||||
dyn->doublepop = 0;
|
||||
|
||||
#if STEP < 2
|
||||
#define GETIP(A)
|
||||
#define GETIP_(A)
|
||||
#define GETIP(A) TABLE64(0, 0)
|
||||
#define GETIP_(A) TABLE64(0, 0)
|
||||
#else
|
||||
// put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later...
|
||||
#define GETIP(A) \
|
||||
@@ -1044,6 +1098,12 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define emit_ror8c STEPNAME(emit_ror8c)
|
||||
#define emit_rol16c STEPNAME(emit_rol16c)
|
||||
#define emit_ror16c STEPNAME(emit_ror16c)
|
||||
#define emit_rcl8c STEPNAME(emit_rcl8c)
|
||||
#define emit_rcr8c STEPNAME(emit_rcr8c)
|
||||
#define emit_rcl16c STEPNAME(emit_rcl16c)
|
||||
#define emit_rcr16c STEPNAME(emit_rcr16c)
|
||||
#define emit_rcl32c STEPNAME(emit_rcl32c)
|
||||
#define emit_rcr32c STEPNAME(emit_rcr32c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shrd32 STEPNAME(emit_shrd32)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
@@ -1063,7 +1123,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st)
|
||||
#define x87_refresh STEPNAME(x87_refresh)
|
||||
#define x87_free STEPNAME(x87_free)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
@@ -1082,7 +1142,6 @@ 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)
|
||||
@@ -1093,6 +1152,9 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
|
||||
#define arm64_move32 STEPNAME(arm64_move32)
|
||||
#define arm64_move64 STEPNAME(arm64_move64)
|
||||
|
||||
/* 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* unscaled, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
@@ -1105,7 +1167,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
|
||||
// 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 jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
|
||||
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);
|
||||
@@ -1195,6 +1257,12 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4);
|
||||
@@ -1227,8 +1295,8 @@ int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
|
||||
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// refresh a value from the cache ->emu (nothing done if value is not cached)
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// Free st, using the FFREE opcode (so it's freed but stack is not moved)
|
||||
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st);
|
||||
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
|
||||
void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh the cache value from emu
|
||||
@@ -1244,6 +1312,9 @@ int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
|
||||
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
|
||||
|
||||
#if STEP < 2
|
||||
#define CHECK_CACHE() 0
|
||||
#else
|
||||
@@ -1252,6 +1323,8 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2,
|
||||
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
// scratch fpu regs for convertions
|
||||
#define SCRATCH 31
|
||||
|
||||
#if STEP == 0
|
||||
#define ST_IS_F(A) 0
|
||||
@@ -1295,8 +1368,6 @@ void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Push current value to the cache
|
||||
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// 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
|
||||
|
||||
@@ -12,21 +12,16 @@
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = B; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0;
|
||||
#define EMIT(A) dyn->native_size+=4
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst].x64.barrier_next = A
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_native_t*)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; \
|
||||
} \
|
||||
dyn->insts[ninst].x64.addr = ip; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
@@ -43,7 +38,7 @@
|
||||
*ok = -1; \
|
||||
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 ":"",\
|
||||
(void*)ip, rex.is32bits?"x86 ":"x64 ",\
|
||||
PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
|
||||
@@ -42,10 +42,13 @@ typedef struct neoncache_s {
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint8_t pushed; // positive pushed value (to check for overflow)
|
||||
uint8_t poped; // positive poped value (to check for underflow)
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8]; // cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int16_t tags; // similar to fpu_tags
|
||||
int8_t mmxcache[8]; // cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[16]; // cache status for the 16 SSE(2) registers
|
||||
int8_t fpuused[24]; // all 0..24 double reg from fpu, used by x87, sse and mmx
|
||||
@@ -76,7 +79,9 @@ typedef struct instruction_arm64_s {
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
int barrier_maybe;
|
||||
uint8_t barrier_maybe;
|
||||
uint8_t will_write;
|
||||
uint8_t last_write;
|
||||
flagcache_t f_exit; // flags status at end of instruction
|
||||
neoncache_t n; // neoncache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
@@ -109,15 +114,16 @@ typedef struct dynarec_arm_s {
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uint8_t smread;
|
||||
uint8_t doublepush;
|
||||
uint8_t doublepop;
|
||||
uint8_t always_test;
|
||||
uint8_t abort; // abort the creation of the block
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
|
||||
+44
-52
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
#include "rbtree.h"
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
@@ -47,6 +48,18 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
int db_size = db->x64_size;
|
||||
if(db_size && my_context) {
|
||||
uint32_t n = rb_get(my_context->db_sizes, db_size);
|
||||
if(n>1)
|
||||
rb_set(my_context->db_sizes, db_size, db_size+1, n-1);
|
||||
else
|
||||
rb_unset(my_context->db_sizes, db_size, db_size+1);
|
||||
if(db_size == my_context->max_db_size) {
|
||||
my_context->max_db_size = rb_get_righter(my_context->db_sizes);
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
@@ -81,6 +94,18 @@ 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;
|
||||
int db_size = db->x64_size;
|
||||
if(db_size && my_context) {
|
||||
uint32_t n = rb_get(my_context->db_sizes, db_size);
|
||||
if(n>1)
|
||||
rb_set(my_context->db_sizes, db_size, db_size+1, n-1);
|
||||
else
|
||||
rb_unset(my_context->db_sizes, db_size, db_size+1);
|
||||
if(db_size == my_context->max_db_size) {
|
||||
my_context->max_db_size = rb_get_righter(my_context->db_sizes);
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
@@ -120,15 +145,6 @@ static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(getNeedTest((uintptr_t)db->x64_addr))
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
@@ -155,15 +171,6 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
dynablock_t* block;
|
||||
#if 0
|
||||
// check if memory as the correct flags
|
||||
int prot = getProtection(addr);
|
||||
if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) {
|
||||
dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
@@ -228,17 +235,20 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
}
|
||||
// check size
|
||||
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->dirty?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0);
|
||||
block = getDB(addr);
|
||||
MarkDynablock(block); // just in case...
|
||||
} else {
|
||||
if(block->x64_size)
|
||||
if(block->x64_size) {
|
||||
if(block->x64_size>my_context->max_db_size) {
|
||||
my_context->max_db_size = block->x64_size;
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: higher max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
rb_set(my_context->db_sizes, block->x64_size, block->x64_size+1, rb_get(my_context->db_sizes, block->x64_size)+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
@@ -251,33 +261,17 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
{
|
||||
if(isInHotPage(addr))
|
||||
return NULL;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) {
|
||||
emu->test.test = 0;
|
||||
if(box64_dynarec_fastpage) {
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(hash==db->hash) { // seems ok, run it without reprotecting it
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
return db;
|
||||
}
|
||||
db->done = 0; // invalidating the block, it's already not good
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 1);
|
||||
return NULL; // not building a new one, it's still a hotpage
|
||||
} else {
|
||||
dynarec_log(LOG_INFO, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,(void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
@@ -289,12 +283,11 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
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
|
||||
if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->always_test, (void*)addr);
|
||||
if(db->always_test)
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
else
|
||||
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
|
||||
}
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
@@ -328,11 +321,10 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr,
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
// fill back jumptable
|
||||
if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
|
||||
setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
|
||||
}
|
||||
if(db->always_test)
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
else
|
||||
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
|
||||
}
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
+31
-5
@@ -19,6 +19,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "dynarec_next.h"
|
||||
#include "custommem.h"
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
#include "elfloader.h"
|
||||
@@ -34,6 +35,9 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
if(!addr) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
} else if(addr<0x10000) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
}
|
||||
#endif
|
||||
void * jblock;
|
||||
@@ -52,9 +56,13 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
if(!block) {
|
||||
#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)");
|
||||
if(checkInHotPage(addr)) {
|
||||
dynarec_log(LOG_INFO, "Not trying to run a block from a Hotpage at %p\n", (void*)addr);
|
||||
} else {
|
||||
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), RIP=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)", (void*)*x3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//tableupdate(native_epilog, addr, table);
|
||||
@@ -62,6 +70,12 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
#ifdef HAVE_TRACE
|
||||
if(box64_dynarec_log && !block->isize) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, NULL block at %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
}
|
||||
#endif
|
||||
return native_epilog;
|
||||
}
|
||||
if(!(jblock=block->block)) {
|
||||
@@ -129,16 +143,22 @@ void DynaRun(x64emu_t* emu)
|
||||
JUMPBUFF jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
JUMPBUFF *old_jmpbuf = emu->jmpbuf;
|
||||
#ifdef RV64
|
||||
uintptr_t old_savesp = emu->xSPSave;
|
||||
#endif
|
||||
emu->flags.jmpbuf_ready = 0;
|
||||
|
||||
while(!(emu->quit)) {
|
||||
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
|
||||
emu->jmpbuf = jmpbuf;
|
||||
#ifdef RV64
|
||||
emu->old_savedsp = emu->xSPSave;
|
||||
#endif
|
||||
emu->flags.jmpbuf_ready = 1;
|
||||
#ifdef ANDROID
|
||||
if((skip=sigsetjmp(*(JUMPBUFF*)emu->jmpbuf, 1)))
|
||||
if((skip=sigsetjmp(*(JUMPBUFF*)emu->jmpbuf, 1)))
|
||||
#else
|
||||
if((skip=sigsetjmp(emu->jmpbuf, 1)))
|
||||
if((skip=sigsetjmp(emu->jmpbuf, 1)))
|
||||
#endif
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", emu->segs[_FS]);
|
||||
@@ -174,6 +194,9 @@ void DynaRun(x64emu_t* 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);
|
||||
extern int running32bits;
|
||||
if(emu->segs[_CS]==0x23)
|
||||
running32bits = 1;
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
@@ -192,4 +215,7 @@ void DynaRun(x64emu_t* emu)
|
||||
}
|
||||
// clear the setjmp
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
#ifdef RV64
|
||||
emu->xSPSave = old_savesp;
|
||||
#endif
|
||||
}
|
||||
@@ -15,18 +15,24 @@
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
#elif defined(LA464)
|
||||
// Limit here is defined by LD litteral, that is 19bits
|
||||
#define MAXBLOCK_SIZE ((1<<19)-200)
|
||||
#elif defined(LA64)
|
||||
|
||||
#define instruction_native_t instruction_la464_t
|
||||
#define dynarec_native_t dynarec_la464_t
|
||||
#define instruction_native_t instruction_la64_t
|
||||
#define dynarec_native_t dynarec_la64_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION()
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE()
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
|
||||
|
||||
#include "la464/la464_printer.h"
|
||||
#include "la464/dynarec_la464_private.h"
|
||||
#include "la464/dynarec_la464_functions.h"
|
||||
#include "la64/la64_printer.h"
|
||||
#include "la64/dynarec_la64_private.h"
|
||||
#include "la64/dynarec_la64_functions.h"
|
||||
// Limit here is unconditionnal jump, that is signed 28bits
|
||||
#define MAXBLOCK_SIZE ((1 << 27) - 200)
|
||||
#elif defined(RV64)
|
||||
|
||||
#define instruction_native_t instruction_rv64_t
|
||||
@@ -41,6 +47,8 @@
|
||||
#include "rv64/rv64_printer.h"
|
||||
#include "rv64/dynarec_rv64_private.h"
|
||||
#include "rv64/dynarec_rv64_functions.h"
|
||||
// Limit here is unconditionnal jump, that is signed 21bits
|
||||
#define MAXBLOCK_SIZE ((1<<20)-200)
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/dynarec_arm64_helper.h"
|
||||
#elif defined(LA464)
|
||||
#include "la464/dynarec_la464_helper.h"
|
||||
#elif defined(LA64)
|
||||
#include "la64/dynarec_la64_helper.h"
|
||||
#elif defined(RV64)
|
||||
#include "rv64/dynarec_rv64_helper.h"
|
||||
#else
|
||||
|
||||
@@ -72,8 +72,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*)dynaRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
printf_log(LOG_NONE, "Warning, overallocating next\n");
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -97,15 +96,14 @@ uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
void add_jump(dynarec_native_t *dyn, int ninst) {
|
||||
// add slots
|
||||
if(dyn->jmp_sz == dyn->jmp_cap) {
|
||||
dyn->jmp_cap += 64;
|
||||
dyn->jmps = (int*)dynaRealloc(dyn->jmps, dyn->jmp_cap*sizeof(int));
|
||||
printf_log(LOG_NONE, "Warning, overallocating jmps\n");
|
||||
}
|
||||
dyn->jmps[dyn->jmp_sz++] = ninst;
|
||||
}
|
||||
int get_first_jump(dynarec_native_t *dyn, int next) {
|
||||
for(int i=0; i<dyn->jmp_sz; ++i)
|
||||
if(dyn->insts[dyn->jmps[i]].x64.jmp == next)
|
||||
return i;
|
||||
return dyn->jmps[i];
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -289,15 +287,10 @@ int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
|
||||
idx = i;
|
||||
// not found, add it
|
||||
if(idx==-1) {
|
||||
if(dyn->table64size == dyn->table64cap) {
|
||||
dyn->table64cap+=16;
|
||||
if(pass<3) // do not resize on pass3, it's not the same type of memory anymore
|
||||
dyn->table64 = (uint64_t*)dynaRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
|
||||
}
|
||||
idx = dyn->table64size++;
|
||||
if(idx < dyn->table64cap)
|
||||
dyn->table64[idx] = val;
|
||||
else
|
||||
else if(pass==3)
|
||||
printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap);
|
||||
}
|
||||
// calculate offset
|
||||
@@ -305,23 +298,35 @@ int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
|
||||
return delta;
|
||||
}
|
||||
|
||||
static void fillPredecessors(dynarec_native_t* dyn)
|
||||
static void recurse_mark_alive(dynarec_native_t* dyn, int i)
|
||||
{
|
||||
if(dyn->insts[i].x64.alive)
|
||||
return;
|
||||
dyn->insts[i].x64.alive = 1;
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1)
|
||||
recurse_mark_alive(dyn, dyn->insts[i].x64.jmp_insts);
|
||||
if(i<dyn->size-1 && dyn->insts[i].x64.has_next)
|
||||
recurse_mark_alive(dyn, i+1);
|
||||
}
|
||||
|
||||
static int sizePredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to allocate the array
|
||||
// mark alive...
|
||||
recurse_mark_alive(dyn, 0);
|
||||
// first compute the jumps
|
||||
int jmpto;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x64.jmp && (dyn->insts[i].x64.jmp_insts!=-1)) {
|
||||
if(dyn->insts[i].x64.alive && dyn->insts[i].x64.jmp && ((jmpto=dyn->insts[i].x64.jmp_insts)!=-1)) {
|
||||
pred_sz++;
|
||||
dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz++;
|
||||
dyn->insts[jmpto].pred_sz++;
|
||||
}
|
||||
}
|
||||
// remove "has_next" from orphan branch
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(!dyn->insts[i].x64.has_next) {
|
||||
if(dyn->insts[i+1].x64.has_next && !dyn->insts[i+1].pred_sz)
|
||||
dyn->insts[i+1].x64.has_next = 0;
|
||||
}
|
||||
if(dyn->insts[i].x64.has_next && !dyn->insts[i+1].x64.alive)
|
||||
dyn->insts[i].x64.has_next = 0;
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
@@ -330,8 +335,10 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
int alloc_size = pred_sz;
|
||||
dyn->predecessor = (int*)dynaMalloc(pred_sz*sizeof(int));
|
||||
return pred_sz;
|
||||
}
|
||||
static void fillPredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
@@ -340,7 +347,7 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
for(int i=0; i<dyn->size; ++i) if(dyn->insts[i].x64.alive) {
|
||||
if((i!=dyn->size-1) && dyn->insts[i].x64.has_next)
|
||||
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
|
||||
if(dyn->insts[i].x64.jmp && (dyn->insts[i].x64.jmp_insts!=-1)) {
|
||||
@@ -355,14 +362,10 @@ static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x64.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SUBSET)) {
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SUBSET || dyn->insts[ninst].x64.state_flags==SF_SET || dyn->insts[ninst].x64.state_flags==SF_SET_NODF)) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
}
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SET)) {
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x64.set_flags; // SF_SET will compute all flags, it's not SUBSET!
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x64.set_flags);
|
||||
}
|
||||
@@ -398,25 +401,24 @@ static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
static int static_jmps[MAX_INSTS+2];
|
||||
static uintptr_t static_next[MAX_INSTS+2];
|
||||
static uint64_t static_table64[(MAX_INSTS+3)/4];
|
||||
static instruction_native_t static_insts[MAX_INSTS+2] = {0};
|
||||
// TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory
|
||||
|
||||
void CancelBlock64(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_native_t* helper = (dynarec_native_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(helper) {
|
||||
dynaFree(helper->next);
|
||||
dynaFree(helper->jmps);
|
||||
dynaFree(helper->insts);
|
||||
dynaFree(helper->predecessor);
|
||||
if(helper->table64 && (helper->table64!=(uint64_t*)helper->tablestart))
|
||||
dynaFree(helper->table64);
|
||||
if(helper->dynablock && helper->dynablock->actual_block) {
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
helper->dynablock->actual_block = NULL;
|
||||
}
|
||||
}
|
||||
current_helper = NULL;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
@@ -458,15 +460,11 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
A .. A+8*n : Table64: n 64bits values
|
||||
B .. B+7 : dynablock_t* : self (as part of JmpNext, that simulate another block)
|
||||
B+8 .. B+15 : 2 Native code for jmpnext (or jmp epilog in case of empty block)
|
||||
B+16 .. B+23 : jmpnext (or jmp_epilog) address
|
||||
B+16 .. B+23 : jmpnext (or jmp_epilog) address. jumpnext is used when the block needs testing
|
||||
B+24 .. B+31 : empty (in case an architecture needs more than 2 opcodes)
|
||||
B+32 .. B+32+sz : instsize (compressed array with each instruction length on x64 and native side)
|
||||
|
||||
*/
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Canceling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
@@ -483,10 +481,21 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 128;
|
||||
helper.insts = (instruction_native_t*)dynaCalloc(helper.cap, sizeof(instruction_native_t));
|
||||
helper.cap = MAX_INSTS;
|
||||
helper.insts = static_insts;
|
||||
helper.jmps = static_jmps;
|
||||
helper.jmp_cap = MAX_INSTS;
|
||||
helper.next = static_next;
|
||||
helper.next_cap = MAX_INSTS;
|
||||
helper.table64 = static_table64;
|
||||
helper.table64cap = sizeof(static_table64)/sizeof(uint64_t);
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
@@ -495,12 +504,11 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// protect the block of it goes over the 1st page
|
||||
if((addr&~box64_pagesize)!=(end&~box64_pagesize)) // need to protect some other pages too
|
||||
if((addr&~(box64_pagesize-1))!=(end&~(box64_pagesize-1))) // need to protect some other pages too
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
// compute hash signature
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
@@ -508,10 +516,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
for(int ii=0; ii<helper.jmp_sz; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
if(j<start || j>=end || j==helper.insts[i].x64.addr) {
|
||||
if(j==helper.insts[i].x64.addr) // if there is a loop on some opcode, make the block "always to tested"
|
||||
helper.always_test = 1;
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
@@ -544,30 +552,51 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
if(k!=-1) {
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no need for next and jmps anymore
|
||||
dynaFree(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
dynaFree(helper.jmps);
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// fill predecessors with the jump address
|
||||
int alloc_size = sizePredecessors(&helper);
|
||||
helper.predecessor = (int*)alloca(alloc_size*sizeof(int));
|
||||
fillPredecessors(&helper);
|
||||
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
// remove fpu stuff on non-executed code
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz)
|
||||
fpu_reset_ninst(&helper, ii++);
|
||||
i = ii;
|
||||
}
|
||||
|
||||
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
native_pass1(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// pass 2, instruction size
|
||||
native_pass2(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass2\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// 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...
|
||||
@@ -593,7 +622,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
helper.table64cap = helper.table64size;
|
||||
dynaFree(helper.table64);
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(box64_dynarec_dump) {
|
||||
@@ -608,14 +636,15 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.table64size = 0; // reset table64 (but not the cap)
|
||||
helper.insts_size = 0; // reset
|
||||
native_pass3(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
dynaFree(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
@@ -634,7 +663,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// Check if something changed, to abort if it is
|
||||
if((block->hash != hash)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
AddHotPage(addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -653,15 +681,24 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// ok, free the helper now
|
||||
//dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, insts_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size);
|
||||
AddHotPage(addr);
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
block->dirty = 1;
|
||||
block->always_test = 1;
|
||||
}
|
||||
if(block->always_test) {
|
||||
dynarec_log(LOG_DEBUG, "Note: block marked as always dirty %p:%ld\n", block->x64_addr, block->x64_size);
|
||||
}
|
||||
current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
#if STEP == 0
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 0x1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits)
|
||||
{
|
||||
int ok = 1;
|
||||
@@ -34,7 +40,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t init_addr = addr;
|
||||
rex_t rex;
|
||||
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int rep = 0; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int need_epilog = 1;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->f.pending = 0;
|
||||
@@ -43,6 +49,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
#endif
|
||||
fpu_reset(dyn);
|
||||
ARCH_INIT();
|
||||
int reset_n = -1;
|
||||
@@ -50,7 +59,27 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with box64_dynarec_bigblock==2, else it needs 3
|
||||
// ok, go now
|
||||
INIT;
|
||||
#if STEP == 0
|
||||
uintptr_t cur_page = (addr)&~box64_pagesize;
|
||||
#endif
|
||||
while(ok) {
|
||||
#if STEP == 0
|
||||
if(cur_page != ((addr)&~box64_pagesize)) {
|
||||
cur_page = (addr)&~box64_pagesize;
|
||||
if(!(getProtection(addr)&PROT_READ)) {
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// This test is here to prevent things like TABLE64 to be out of range
|
||||
// native_size is not exact at this point, but it should be larger, not smaller, and not by a huge margin anyway
|
||||
// so it's good enough to avoid overflow in relative to PC data fectching
|
||||
if((dyn->native_size >= MAXBLOCK_SIZE) || (ninst >= MAX_INSTS)) {
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
ip = addr;
|
||||
if (reset_n!=-1) {
|
||||
dyn->last_ip = 0;
|
||||
@@ -73,9 +102,11 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
} else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
|
||||
}
|
||||
#if STEP > 0
|
||||
else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
|
||||
dyn->last_ip = 0; // reset IP if some jump are coming here
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
#endif
|
||||
NEW_INST;
|
||||
#if STEP == 0
|
||||
if(ninst && dyn->insts[ninst-1].x64.barrier_next) {
|
||||
@@ -91,9 +122,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
}
|
||||
if(box64_dynarec_test) {
|
||||
MESSAGE(LOG_DUMP, "TEST INIT ----\n");
|
||||
MESSAGE(LOG_DUMP, "TEST STEP ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE(x64test_init, 1, x5);
|
||||
GO_TRACE(x64test_step, 1, x5);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
@@ -132,23 +163,25 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
|
||||
addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
|
||||
|
||||
if(dyn->abort)
|
||||
return ip;
|
||||
INST_EPILOG;
|
||||
|
||||
int next = ninst+1;
|
||||
#if STEP > 0
|
||||
if(!dyn->insts[ninst].x64.has_next && dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts!=-1)
|
||||
next = dyn->insts[ninst].x64.jmp_insts;
|
||||
#endif
|
||||
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT)
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
}
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLAGS) {
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->last_ip = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
@@ -157,8 +190,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
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))) {
|
||||
if(ii<dyn->size && !dyn->insts[ii].x64.alive) {
|
||||
while(ii<dyn->size && !dyn->insts[ii].x64.alive) {
|
||||
// may need to skip opcodes to advance
|
||||
++ninst;
|
||||
NEW_INST;
|
||||
@@ -180,10 +213,17 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
}
|
||||
#else
|
||||
// check if block need to be stopped, because it's a 00 00 opcode (unreadeable is already checked earlier)
|
||||
if((ok>0) && !dyn->forward && !(*(uint8_t*)addr) && !(*(uint8_t*)(addr+1))) {
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00");
|
||||
ok = 0;
|
||||
need_epilog = 1;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog) {
|
||||
if(dyn->forward_to == addr && !need_epilog && ok>=0) {
|
||||
// we made it!
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
reset_n = get_first_jump(dyn, addr);
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p (ninst %d - %d)\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to, reset_n, ninst);
|
||||
if(dyn->insts[dyn->forward_ninst].x64.has_callret && !dyn->insts[dyn->forward_ninst].x64.has_next)
|
||||
dyn->insts[dyn->forward_ninst].x64.has_next = 1; // this block actually continue
|
||||
dyn->forward = 0;
|
||||
@@ -219,7 +259,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
// and pred table is not ready yet
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
}
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst+1, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
|
||||
} else if(next && (next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
@@ -262,12 +302,15 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if((ok>0) && dyn->insts[ninst].x64.has_callret)
|
||||
reset_n = -2;
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && (((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)addr))
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
if((ok>0) && (((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)addr))
|
||||
|| (addr>=box64_nodynarec_start && addr<box64_nodynarec_end)))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
if((ok>0) && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 0
|
||||
@@ -297,7 +340,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
++ninst;
|
||||
NOTEST(x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
jump_to_next(dyn, addr, 0, ninst, rex.is32bits);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ 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(void) EXPORTDYN;
|
||||
#define native_next la464_next
|
||||
#define native_prolog la464_prolog
|
||||
#define native_epilog la464_epilog
|
||||
#elif defined(LA64)
|
||||
void la64_next(void) EXPORTDYN;
|
||||
void la64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void la64_epilog(void) EXPORTDYN;
|
||||
#define native_next la64_next
|
||||
#define native_prolog la64_prolog
|
||||
#define native_epilog la64_epilog
|
||||
#elif defined(RV64)
|
||||
void rv64_next(void) EXPORTDYN;
|
||||
void rv64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
|
||||
@@ -24,17 +24,22 @@
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
#define SF_DF 8
|
||||
#define SF_SET_DF (SF_SET|SF_DF)
|
||||
#define SF_NODF 16
|
||||
#define SF_SET_NODF (SF_SET|SF_NODF)
|
||||
|
||||
typedef struct instruction_x64_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint8_t jmp_cond; // 1 of conditionnal jump
|
||||
uint8_t has_next; // does this opcode can continue to the next?
|
||||
uint8_t jmp_cond:1; // 1 of conditionnal jump
|
||||
uint8_t has_next:1; // does this opcode can continue to the next?
|
||||
uint8_t has_callret:1; // this instruction have an optimised call setup
|
||||
uint8_t alive:1; // this opcode gets executed (0 if dead code in that block)
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
uint8_t barrier_next; // next instruction needs a barrier
|
||||
uint8_t has_callret; // this instruction have an optimised call setup
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
uint8_t use_flags; // 0 or combination of X_?F
|
||||
uint8_t set_flags; // 0 or combination of X_?F
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,814 @@
|
||||
#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 "la64_emitter.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 "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
#include "bitutils.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wb1, wback, wb2, gback;
|
||||
uint8_t eb1, eb2;
|
||||
uint8_t gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int s0, s1;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(gback);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x01:
|
||||
// TODO:, /0 is SGDT. While 0F 01 D0 is XGETBV, etc...
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
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();
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
} else {
|
||||
switch((nextop>>3)&7) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("SYSCALL");
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL();
|
||||
CALL_S(x64Syscall, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
TABLE64(x3, addr); // expected return address
|
||||
BNE_MARK(xRIP, x3);
|
||||
LD_W(w1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZ_NEXT(w1);
|
||||
MARK;
|
||||
LOAD_XEMU_REM();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VOR_V(v0, v1, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVUPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
INST_NAME("MOVHLPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
VEXTRINS_D(v0, v1, 1);
|
||||
} else {
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
SMREAD();
|
||||
GETEX(q1, 0, 0);
|
||||
VEXTRINS_D(v0, q1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVLPS Ex,Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
|
||||
VEXTRINS_D(v1, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VILVL_W(v0, q0, v0);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("UNPCKHPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VILVH_W(v0, q0, v0);
|
||||
break;
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
INST_NAME("MOVLHPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
}
|
||||
VILVL_D(v0, v1, v0); // v0[127:64] = v1[63:0]
|
||||
break;
|
||||
case 0x17:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVHPS Ex,Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
|
||||
VEXTRINS_D(v1, v0, 0x01);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXTRINS_D(v1, v0, 0x01);
|
||||
FST_D(v1, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
nextop = F8;
|
||||
if ((nextop & 0xC0) == 0xC0) {
|
||||
INST_NAME("NOP (multibyte)");
|
||||
} else
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
INST_NAME("PREFETCHh Ed");
|
||||
FAKEED;
|
||||
break;
|
||||
default:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
FAKEED;
|
||||
}
|
||||
break;
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
case 0x28:
|
||||
INST_NAME("MOVAPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VOR_V(v0, v1, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if (opcode == 0x2F) {
|
||||
INST_NAME("COMISS Gx, Ex");
|
||||
} else {
|
||||
INST_NAME("UCOMISS Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGX(d0, 0);
|
||||
GETEXSS(v0, 0, 0);
|
||||
CLEAR_FLAGS(x2);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_S(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_S(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_S(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
IFX (X_ALL) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
break;
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
MV(gd, ed); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
} \
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
|
||||
#undef GO
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VFSQRT_S(v0, q0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
VFRSQRT_S(q1, q0);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VAND_V(v0, v0, q0);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("ANDNPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VANDN_V(v0, v0, q0);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("ORPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VOR_V(v0, v0, q0);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("XORPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG && ((nextop & 7) + (rex.b << 3) == gd)) {
|
||||
// special case for XORPS Gx, Gx
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VXOR_V(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("ADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFADD_S(v0, v0, q0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFMUL_S(v0, v0, q0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
VFCVTL_D_S(q1, q0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFSUB_S(v0, v0, q0);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr + i32_, 1); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
|
||||
if (la64_lbt) \
|
||||
BEQZ_safe(x1, i32); \
|
||||
else \
|
||||
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 + i32_, 0, ninst, rex.is32bits); \
|
||||
} 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); \
|
||||
if (la64_lbt) \
|
||||
BNEZ_safe(x1, i32); \
|
||||
else \
|
||||
B##YES##_safe(x1, i32); \
|
||||
}
|
||||
|
||||
GOCOND(0x80, "J", "Id");
|
||||
|
||||
#undef GO
|
||||
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x3, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
S##YES(x3, x1); \
|
||||
} \
|
||||
nextop = F8; \
|
||||
if (MODREG) { \
|
||||
if (rex.rex) { \
|
||||
eb1 = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
eb2 = 0; \
|
||||
} else { \
|
||||
ed = (nextop & 7); \
|
||||
eb2 = (ed >> 2) * 8; \
|
||||
eb1 = TO_LA64(ed & 3); \
|
||||
} \
|
||||
BSTRINS_D(eb1, x3, eb2 + 7, eb2); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0); \
|
||||
ST_B(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
#undef GO
|
||||
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
NOTEST(x1);
|
||||
MV(A1, xRAX);
|
||||
CALL_(my_cpuid, -1, 0);
|
||||
// BX and DX are not synchronized durring the call, so need to force the update
|
||||
LD_D(xRDX, xEmu, offsetof(x64emu_t, regs[_DX]));
|
||||
LD_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w); // r1 = (gd>>5)
|
||||
ALSL_D(x3, wback, x1, 2 + rex.w); // (&ed) += r1*4;
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRLxw(x4, ed, x2);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (box64_dynarec_test) {
|
||||
// avoid noise during test
|
||||
CLEAR_FLAGS(x3);
|
||||
}
|
||||
if (rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
X64_MUL_D(gd, ed);
|
||||
}
|
||||
MULH_D(x3, gd, ed);
|
||||
MUL_D(gd, gd, ed);
|
||||
IFX (X_PEND) {
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_CF | X_OF, !la64_lbt) {
|
||||
SRAI_D(x4, gd, 63);
|
||||
XOR(x3, x3, x4);
|
||||
SNEZ(x3, x3);
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
BSTRINS_D(xFlags, x3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
X64_MUL_W(gd, ed);
|
||||
}
|
||||
MUL_D(gd, gd, ed);
|
||||
SRLI_D(x3, gd, 32);
|
||||
SLLI_W(gd, gd, 0);
|
||||
IFX (X_PEND) {
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x4, d_imul32);
|
||||
} else IFX (X_CF | X_OF) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_CF | X_OF, !la64_lbt) {
|
||||
SRAI_W(x4, gd, 31);
|
||||
SUB_D(x3, x3, x4);
|
||||
SNEZ(x3, x3);
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
BSTRINS_D(xFlags, x3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
eb1 = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
}
|
||||
BSTRPICK_D(gd, eb1, eb2 * 8 + 7, eb2 * 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_BU(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xB7:
|
||||
INST_NAME("MOVZX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
BSTRPICK_D(gd, ed, 15, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_HU(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 0x1f;
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
ADDI_D(x4, xZR, -1);
|
||||
BSTRINS_D(ed, x4, u8, u8);
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
BSTRINS_D(ed, xZR, u8, u8);
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ed = x4;
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x3, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x3, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
// gd is undefined if ed is all zeros, don't worry.
|
||||
if (rex.w)
|
||||
CTZ_D(gd, ed);
|
||||
else
|
||||
CTZ_W(gd, ed);
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x3, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x3);
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ed = x4;
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x3, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x3, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x3, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x3);
|
||||
}
|
||||
if (rex.w)
|
||||
CLZ_D(gd, ed);
|
||||
else
|
||||
CLZ_W(gd, ed);
|
||||
ADDI_D(x1, xZR, rex.w ? 63 : 31);
|
||||
SUB_D(gd, x1, gd);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
wback = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop & 7);
|
||||
wb2 = (wback >> 2) * 8;
|
||||
wback = TO_LA64(wback & 3);
|
||||
}
|
||||
BSTRPICK_D(gd, wback, wb2 + 7, wb2);
|
||||
EXT_W_B(gd, gd);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_B(gd, ed, fixedaddress);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
break;
|
||||
case 0xBF:
|
||||
INST_NAME("MOVSX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
EXT_W_H(gd, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_H(gd, ed, fixedaddress);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
u8 = F8;
|
||||
if (v0 == v1) {
|
||||
VSHUF4I_W(v0, v0, u8);
|
||||
} else {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VSHUF4I_W(v0, v0, u8);
|
||||
VSHUF4I_W(q1, v1, u8);
|
||||
VEXTRINS_D(v0, q1, 0x11); // v0[127:64] = q1[127:64]
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = TO_LA64((opcode & 7) + (rex.b << 3));
|
||||
REVBxw(gd, gd);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_64(dynarec_la64_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 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);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
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, TO_LA64((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD_D(x4, ed, x4);
|
||||
LDxw(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,534 @@
|
||||
#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 "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66(dynarec_la64_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;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
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 0x0F:
|
||||
switch (rep) {
|
||||
case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
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 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, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
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;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
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 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;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
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 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 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 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 = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
if (ed != gd) {
|
||||
BSTRINS_D(ed, gd, 15, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
ST_H(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = TO_LA64((opcode & 0x07) + (rex.b << 3));
|
||||
if (gd == xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
INST_NAME("XCHG AX, Reg");
|
||||
MV(x2, xRAX);
|
||||
BSTRINS_D(xRAX, gd, 15, 0);
|
||||
BSTRINS_D(gd, x2, 15, 0);
|
||||
}
|
||||
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
|
||||
ST_H(xRAX, xRDI, 0);
|
||||
ADDI_D(xRDI, xRDI, 2);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
ST_H(xRAX, xRDI, 0);
|
||||
ADDI_D(xRDI, xRDI, -2);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
GETDIR(x3, x1, 2);
|
||||
ST_H(xRAX, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = TO_LA64((opcode & 7) + (rex.b << 3));
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
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_DF);
|
||||
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_DF);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror16, 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 & 15)); }
|
||||
UFLAG_OP12(ed, x2)
|
||||
if (MODREG) {
|
||||
SLLI_D(ed, ed, 48 + (u8 & 15));
|
||||
SRLI_D(ed, ed, 48);
|
||||
} else {
|
||||
SLLI_D(ed, ed, u8 & 15);
|
||||
}
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR 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 & 15)); }
|
||||
UFLAG_OP12(ed, x2)
|
||||
SRLI_D(ed, ed, u8 & 15);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BSTRINS_D(ed, x1, 15, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
ST_H(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(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (box64_dynarec_safeflags > 1) MAYSETFLAGS();
|
||||
GETEW(x1, 0);
|
||||
emit_shr16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if (opcode == 0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (box64_dynarec_safeflags > 1)
|
||||
MAYSETFLAGS();
|
||||
GETEW(x1, 0);
|
||||
emit_shl16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7:
|
||||
if (opcode == 0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (box64_dynarec_safeflags > 1)
|
||||
MAYSETFLAGS();
|
||||
GETSEW(x1, 0);
|
||||
emit_sar16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,806 @@
|
||||
#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 "la64_emitter.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 "bitutils.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8, s8;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2, gback;
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1, d2;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
}
|
||||
VEXTRINS_D(v0, v1, 0x10);
|
||||
break;
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
case 0x28:
|
||||
INST_NAME("MOVAPD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VOR_V(v0, v1, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if (opcode == 0x2F) {
|
||||
INST_NAME("COMISD Gx, Ex");
|
||||
} else {
|
||||
INST_NAME("UCOMISD Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGX(d0, 0);
|
||||
GETEXSD(v0, 0, 0);
|
||||
|
||||
CLEAR_FLAGS(x3);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_D(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_D(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_D(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 0x38: // SSSE3 opcodes
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0x00:
|
||||
INST_NAME("PSHUFB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDI(v0, 0b0000010001111); // broadcast 0b10001111 as byte
|
||||
VAND_V(v0, v0, q1);
|
||||
VMINI_BU(v0, v0, 0x1f);
|
||||
VXOR_V(v1, v1, v1);
|
||||
VSHUF_B(q0, v1, q0, v0);
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("PHADDW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_H(v0, q1, q0);
|
||||
VPICKOD_H(v1, q1, q0);
|
||||
VADD_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x02:
|
||||
INST_NAME("PHADDD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_W(v0, q1, q0);
|
||||
VPICKOD_W(v1, q1, q0);
|
||||
VADD_W(q0, v0, v1);
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("PHADDSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_H(v0, q1, q0);
|
||||
VPICKOD_H(v1, q1, q0);
|
||||
VSADD_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PMADDUBSW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXT2XV_HU_BU(v0, q0);
|
||||
VEXT2XV_H_B(v1, q1);
|
||||
XVMUL_H(v0, v0, v1);
|
||||
XVPERMI_Q(v1, v0, 1); // v1[127:0] = v0[255:128];
|
||||
VPICKEV_H(q0, v1, v0);
|
||||
VPICKOD_H(v0, v1, v0);
|
||||
VSADD_H(q0, v0, q0);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("PHSUBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_H(v0, q1, q0);
|
||||
VPICKOD_H(v1, q1, q0);
|
||||
VSUB_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x06:
|
||||
INST_NAME("PHSUBD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_W(v0, q1, q0);
|
||||
VPICKOD_W(v1, q1, q0);
|
||||
VSUB_D(q0, v0, v1);
|
||||
break;
|
||||
case 0x07:
|
||||
INST_NAME("PHSUBSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_H(v0, q1, q0);
|
||||
VPICKOD_H(v1, q1, q0);
|
||||
VSSUB_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("PSIGNB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VSIGNCOV_B(q0, q1, q0);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("PSIGNW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VSIGNCOV_H(q0, q1, q0);
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("PSIGND Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VSIGNCOV_W(q0, q1, q0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VAND_V(v0, v0, q0);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("ANDNPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VANDN_V(v0, v0, q0);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("ORPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VOR_V(v0, v0, q0);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("XORPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG && ((nextop & 7) + (rex.b << 3) == gd)) {
|
||||
// special case for XORPD Gx, Gx
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VXOR_V(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPD2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// TODO: is there any way to support !box64_dynarec_fastround?
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCVT_S_D(q0, v1, v1);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VEXTRINS_D(v0, q0, 0);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_B(v0, q0, v0);
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PUNPCKLWD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_H(v0, q0, v0);
|
||||
break;
|
||||
case 0x62:
|
||||
INST_NAME("PUNPCKLDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_W(v0, q0, v0);
|
||||
break;
|
||||
case 0x64:
|
||||
INST_NAME("PCMPGTB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VSLT_B(v0, v1, v0);
|
||||
break;
|
||||
case 0x65:
|
||||
INST_NAME("PCMPGTW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VSLT_H(v0, v1, v0);
|
||||
break;
|
||||
case 0x66:
|
||||
INST_NAME("PCMPGTD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VSLT_W(v0, v1, v0);
|
||||
break;
|
||||
case 0x67:
|
||||
INST_NAME("PACKUSWB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VLDI(q0, 0b0010011111111); // broadcast 0xff as 16-bit elements to all lanes
|
||||
if (v0 == v1) {
|
||||
VMAXI_H(v0, v0, 0);
|
||||
VMIN_H(v0, v0, q0);
|
||||
VPICKEV_B(v0, v0, v0);
|
||||
} else {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VMAXI_H(v0, v0, 0);
|
||||
VMAXI_H(q1, v1, 0);
|
||||
VMIN_H(v0, v0, q0);
|
||||
VMIN_H(q1, q1, q0);
|
||||
VPICKEV_B(v0, q1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x68:
|
||||
INST_NAME("PUNPCKHBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_B(q0, q1, q0);
|
||||
break;
|
||||
case 0x69:
|
||||
INST_NAME("PUNPCKHWD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_H(q0, q1, q0);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUNPCKHDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_W(q0, q1, q0);
|
||||
break;
|
||||
case 0x6C:
|
||||
INST_NAME("PUNPCKLQDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
}
|
||||
VILVL_D(v0, v1, v0); // v0[127:64] = v1[63:0]
|
||||
break;
|
||||
case 0x6D:
|
||||
INST_NAME("PUNPCKHQDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 8, 0);
|
||||
FLD_D(v1, ed, fixedaddress + 8);
|
||||
VEXTRINS_D(v1, v1, 0x10);
|
||||
}
|
||||
VILVH_D(v0, v1, v0);
|
||||
break;
|
||||
case 0x6E:
|
||||
INST_NAME("MOVD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(v1, ed);
|
||||
} else {
|
||||
MOVGR2FR_W(v1, ed);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLDxw(v1, ed, fixedaddress);
|
||||
}
|
||||
VXOR_V(v0, v0, v0);
|
||||
if (rex.w) {
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
} else {
|
||||
VEXTRINS_W(v0, v1, 0); // v0[31:0] = v1[31:0]
|
||||
}
|
||||
break;
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQA Gx,Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
GETGX_empty(v0);
|
||||
VOR_V(v0, v1, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFD Gx,Ex,Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
u8 = F8;
|
||||
VSHUF4I_W(v0, v1, u8);
|
||||
break;
|
||||
case 0x71:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLW Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 15) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else if (u8) {
|
||||
VSRLI_H(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAW Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8 > 15) u8 = 15;
|
||||
if (u8) {
|
||||
VSRAI_H(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLW Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 15) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
VSLLI_H(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x72:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLD Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 31) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else if (u8) {
|
||||
VSRLI_W(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAD Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8 > 31) u8 = 31;
|
||||
if (u8) {
|
||||
VSRAI_W(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLD Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 31) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
VSLLI_W(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x73:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLQ Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 63) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
VSRLI_D(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("PSRLDQ Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 15) {
|
||||
XVOR_V(q0, q0, q0);
|
||||
} else {
|
||||
VBSRL_V(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLQ Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 63) {
|
||||
XVOR_V(q0, q0, q0);
|
||||
} else {
|
||||
VSLLI_D(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("PSLLDQ Ex, Ib");
|
||||
GETEX(q0, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 15) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else if (u8 > 0) {
|
||||
VBSLL_V(q0, q0, u8);
|
||||
}
|
||||
PUTEX(q0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x76:
|
||||
INST_NAME("PCMPEQD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSEQ_W(v0, v0, q0);
|
||||
break;
|
||||
case 0x7E:
|
||||
INST_NAME("MOVD Ed,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if (rex.w) {
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
MOVFR2GR_D(ed, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
} else {
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
MOVFR2GR_S(ed, v0);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_S(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQA Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 0);
|
||||
GETSGW(x2);
|
||||
MUL_W(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
BSTRPICK_D(x2, x2, 15, 0);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
eb1 = ed;
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
}
|
||||
if (eb2) {
|
||||
SRLI_D(x1, eb1, eb2 * 8);
|
||||
EXT_W_B(x1, x1);
|
||||
} else {
|
||||
EXT_W_B(x1, eb1);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_B(x1, ed, fixedaddress);
|
||||
}
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
break;
|
||||
case 0xD4:
|
||||
INST_NAME("PADDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VADD_D(v0, v0, q0);
|
||||
break;
|
||||
case 0xD5:
|
||||
INST_NAME("PMULLW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VMUL_H(q0, q0, q1);
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
|
||||
VXOR_V(v1, v1, v1);
|
||||
VEXTRINS_D(v1, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xDB:
|
||||
INST_NAME("PAND Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VAND_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("PANDN Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VANDN_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xE4:
|
||||
INST_NAME("PMULHUW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VMUH_HU(v0, v0, v1);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("POR Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VOR_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG && ((nextop & 7) + (rex.b << 3) == gd)) {
|
||||
// special case for PXOR Gx, Gx
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VXOR_V(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("PSUBB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSUB_B(v0, v0, q0);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("PSUBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSUB_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("PSUBD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSUB_W(v0, v0, q0);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("PSUBQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSUB_D(v0, v0, q0);
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("PADDB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VADD_B(v0, v0, q0);
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("PADDW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VADD_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("PADDD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VADD_W(v0, v0, q0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,631 @@
|
||||
#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 "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_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_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_XOR_B(s1, s2);
|
||||
}
|
||||
|
||||
XOR(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(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 XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
ADDI_D(s3, xZR, c & 0xff);
|
||||
X64_XOR_B(s1, s3);
|
||||
}
|
||||
XORI(s1, s1, c & 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
XORI(s1, s1, c & 0xff);
|
||||
ANDI(s1, s1, 0xff);
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_PEND) {
|
||||
ST_B(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_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_XOR_W(s1, s2);
|
||||
}
|
||||
|
||||
XOR(s1, s1, s2);
|
||||
BSTRINS_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_ZF | X_SF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
}
|
||||
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_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w ? d_xor64 : d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_XOR_D(s1, s2);
|
||||
else
|
||||
X64_XOR_W(s1, s2);
|
||||
}
|
||||
XOR(s1, s1, s2);
|
||||
if (!rex.w && s1 != s2) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
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_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, rex.w ? d_xor64 : d_xor32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
MOV64xw(s3, c);
|
||||
if (rex.w)
|
||||
X64_XOR_D(s1, s3);
|
||||
else
|
||||
X64_XOR_W(s1, s3);
|
||||
}
|
||||
|
||||
if (c >= 0 && c <= 4095) {
|
||||
XORI(s1, s1, c);
|
||||
} else {
|
||||
IFX (X_ALL) {
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
}
|
||||
XOR(s1, s1, s3);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
if (c >= 0 && c <= 4095) {
|
||||
XORI(s1, s1, c);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
XOR(s1, s1, s3);
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(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_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA(X_ALL, la64_lbt) {
|
||||
X64_AND_B(s1, s2);
|
||||
}
|
||||
|
||||
AND(s1, s1, s2);
|
||||
|
||||
IFX(X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
SRLI_D(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_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
|
||||
IFXA(X_ALL, la64_lbt) {
|
||||
MOV32w(s3, c);
|
||||
X64_AND_B(s1, s3);
|
||||
}
|
||||
|
||||
ANDI(s1, s1, c&0xff);
|
||||
|
||||
IFX(X_PEND) {
|
||||
ST_D(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
SRLI_D(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_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_AND_W(s1, s2);
|
||||
}
|
||||
|
||||
AND(s1, s1, s2); // res = s1 & s2
|
||||
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(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_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
|
||||
IFXA(X_ALL, la64_lbt) {
|
||||
if (rex.w)
|
||||
X64_AND_D(s1, s2);
|
||||
else
|
||||
X64_AND_W(s1, s2);
|
||||
}
|
||||
|
||||
AND(s1, s1, s2); // res = s1 & s2
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
SRLI_D(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_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA(X_ALL, la64_lbt) {
|
||||
MOV64xw(s3, c);
|
||||
if (rex.w)
|
||||
X64_AND_D(s1, s3);
|
||||
else
|
||||
X64_AND_W(s1, s3);
|
||||
}
|
||||
|
||||
if (c >= 0 && c <= 4095) {
|
||||
ANDI(s1, s1, c);
|
||||
} else {
|
||||
IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c);
|
||||
AND(s1, s1, s3); // res = s1 & s2
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
SRLI_D(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 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_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_OR_W(s1, s2);
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_D(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(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_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
if (rex.w)
|
||||
X64_OR_D(s1, s2);
|
||||
else
|
||||
X64_OR_W(s1, s2);
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if(la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(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);
|
||||
}
|
||||
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_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w ? d_or64 : d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA(X_ALL, la64_lbt) {
|
||||
MOV64xw(s3, c);
|
||||
if (rex.w)
|
||||
X64_OR_D(s1, s3);
|
||||
else
|
||||
X64_OR_W(s1, s3);
|
||||
}
|
||||
|
||||
if (c >= 0 && c <= 4095) {
|
||||
ORI(s1, s1, c);
|
||||
} else {
|
||||
IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c);
|
||||
OR(s1, s1, s3);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(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_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_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_OR_B(s1, s2);
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(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_la64_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
@@ -0,0 +1,750 @@
|
||||
#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 "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
// emit SHL16 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
// s2 is not 0 here and is 1..1f/3f
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_SLL_H(s1, s2);
|
||||
}
|
||||
SLL_D(s1, s1, s2);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SLL_D(s1, s1, s2);
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF | X_OF) {
|
||||
SRLI_D(s5, s1, 16);
|
||||
ANDI(s5, s5, 1); // LSB == F_CF
|
||||
IFX (X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
|
||||
SLLI_D(s1, s1, 48);
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
SRLI_D(s1, s1, 48);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
ADDI_D(s3, s2, -1);
|
||||
BNEZ(s3, 4 + 4 * 4);
|
||||
SRLI_D(s3, s1, 15);
|
||||
XOR(s3, s3, s5);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
// s2 is not 0 here and is 1..1f/3f
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SLL_D(s1, s2);
|
||||
else
|
||||
X64_SLL_W(s1, s2);
|
||||
}
|
||||
SLL_D(s1, s1, s2);
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF | X_OF) {
|
||||
ADDI_D(s5, s2, rex.w?-64:-32);
|
||||
SUB_D(s5, xZR, s5);
|
||||
SRL_W(s3, s1, s5);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX(X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
|
||||
SLL_D(s1, s1, s2);
|
||||
|
||||
IFX(X_SF) {
|
||||
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_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
ADDI_D(s3, s2, -1);
|
||||
BNEZ(s3, 4 + 4 * 4);
|
||||
SRLIxw(s3, s1, rex.w?63:31);
|
||||
XOR(s3, s3, s5);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
} else {
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
}
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if(la64_lbt) {
|
||||
IFX(X_PEND) {} else { MOV64x(s3, c); }
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SLL_D(s1, s3);
|
||||
else
|
||||
X64_SLL_W(s1, s3);
|
||||
}
|
||||
|
||||
SLLIxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF | X_OF) {
|
||||
if (c > 0) {
|
||||
SRLI_D(s3, s1, (rex.w ? 64 : 32) - c);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX(X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rex.w) {
|
||||
SLLI_D(s1, s1, c);
|
||||
} else {
|
||||
SLLI_W(s1, s1, c);
|
||||
}
|
||||
|
||||
IFX(X_SF) {
|
||||
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_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
if (c == 1) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s5);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR8 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_SRL_B(s1, s2);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s3, s2, -1);
|
||||
SRA_D(s3, s1, s3);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
// OF flag is set to the most-significant bit of the original operand
|
||||
ADDI_D(s3, xZR, 1);
|
||||
BNE(s2, s3, 4 + 3 * 4);
|
||||
SRLI_D(s3, s1, 7);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
// SF should be unset
|
||||
IFX (X_PEND) {
|
||||
ST_B(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 SHR16 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_SRL_H(s1, s2);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s3, s2, -1);
|
||||
SRA_D(s3, s1, s3);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
// OF flag is set to the most-significant bit of the original operand
|
||||
ADDI_D(s3, xZR, 1);
|
||||
BNE(s2, s3, 4 + 3 * 4);
|
||||
SRLI_D(s3, s1, 15);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
// SF should be unset
|
||||
IFX (X_PEND) {
|
||||
ST_H(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 SHR32 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shr64 : d_shr32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SRL_D(s1, s2);
|
||||
else
|
||||
X64_SRL_W(s1, s2);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s3, s2, -1);
|
||||
SRA_D(s3, s1, s3);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
// OF flag is set to the most-significant bit of the original operand
|
||||
ADDI_D(s3, xZR, 1);
|
||||
BNE(s2, s3, 4 + 4 * 4);
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
|
||||
IFX (X_SF) {
|
||||
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 SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
} else
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shr64 : d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_PEND) {} else { MOV64x(s3, c); }
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SRL_D(s1, s3);
|
||||
else
|
||||
X64_SRL_W(s1, s3);
|
||||
}
|
||||
|
||||
SRLIxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
} else {
|
||||
// no need to shift
|
||||
ANDI(s3, s1, 1); // LSB == F_CF
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
// OF flag is set to the most-significant bit of the original operand
|
||||
if (c == 1) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
|
||||
if (rex.w) {
|
||||
SRLI_D(s1, s1, c);
|
||||
} else {
|
||||
SRLI_W(s1, s1, c);
|
||||
}
|
||||
|
||||
IFX(X_SF) {
|
||||
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 SAR16 instruction, from s1, shift s2 (!0 and and'd already), store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_SRA_H(s1, s2);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s3, s2, -1);
|
||||
SRA_D(s3, s1, s3);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
// For the SAR instruction, the OF flag is cleared for all 1-bit shifts.
|
||||
// OF nop
|
||||
IFX (X_SF) {
|
||||
// SF is the same as the original operand
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(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 SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
} else
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_sar64 : d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_PEND) {} else { MOV64x(s3, c); }
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SRA_D(s1, s3);
|
||||
else
|
||||
X64_SRA_W(s1, s3);
|
||||
}
|
||||
|
||||
SRAIxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
} else {
|
||||
// no need to shift
|
||||
ANDI(s3, s1, 1); // LSB == F_CF
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
|
||||
if (rex.w) {
|
||||
SRAI_D(s1, s1, c);
|
||||
} else {
|
||||
SRAI_W(s1, s1, c);
|
||||
}
|
||||
|
||||
// SRAI_W sign-extends, so test sign bit before clearing upper bits
|
||||
IFX(X_SF) {
|
||||
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 ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX (X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_ror64 : d_ror32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ROTRI_D(s1, c);
|
||||
else
|
||||
X64_ROTRI_W(s1, c);
|
||||
}
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, c);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set to the exclusive OR of the two most-significant bits of the result
|
||||
if (c == 1) {
|
||||
SRLI_D(s3, s1, rex.w ? 62 : 30);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_rol64 : d_rol32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ROTL_D(s1, s2);
|
||||
else
|
||||
X64_ROTL_W(s1, s2);
|
||||
}
|
||||
}
|
||||
|
||||
if (rex.w) {
|
||||
ANDI(s4, s2, 0x3f);
|
||||
} else {
|
||||
ANDI(s4, s2, 0x1f);
|
||||
}
|
||||
|
||||
SLLxw(s3, s1, s4);
|
||||
NEG_D(s4, s4);
|
||||
ADDI_D(s4, s4, rex.w ? 64 : 32);
|
||||
SRLxw(s1, s1, s4);
|
||||
OR(s1, s3, s1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF | X_OF) {
|
||||
ANDI(s4, s1, 1); // LSB == F_CF
|
||||
IFX (X_CF) OR(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set to the exclusive OR of the CF bit (after the rotate) and the most-significant bit of the result.
|
||||
ADDI_D(s3, xZR, 1);
|
||||
BNE_NEXT(s2, s3);
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s4); // s3: MSB, s4: CF bit
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
#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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
|
||||
// emit CMP8 instruction, from cmp s1, s2, using s3, s4, s5 and s6 as scratch
|
||||
void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_B(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
SUB_D(s6, s1, s2);
|
||||
ST_B(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
// for later flag calculation
|
||||
NOR(s5, xZR, s1);
|
||||
}
|
||||
|
||||
// It's a cmp, we can't store the result back to s1.
|
||||
SUB_D(s6, s1, s2);
|
||||
ANDI(s6, s6, 0xff);
|
||||
IFX_PENDOR0 {
|
||||
ST_B(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI_D(s3, s6, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
CALC_SUB_FLAGS(s5, s2, s6, s3, s4, 8);
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s6, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s6, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_B(s1, xZR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
SRLI_D(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 CMP16 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_H(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
SUB_D(s6, s1, s2);
|
||||
ST_H(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
// for later flag calculation
|
||||
NOR(s5, xZR, s1);
|
||||
}
|
||||
|
||||
// It's a cmp, we can't store the result back to s1.
|
||||
SUB_D(s6, s1, s2);
|
||||
IFX(X_ALL) {
|
||||
BSTRPICK_D(s6, s6, 15, 0);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
ST_H(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI_D(s3, s6, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
CALC_SUB_FLAGS(s5, s2, s6, s3, s4, 16);
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s6, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s6, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_H(s1, xZR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
SRLI_D(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 CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SUB_D(s1, s2);
|
||||
else
|
||||
X64_SUB_W(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
SUBxw(s6, s1, s2);
|
||||
SDxw(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
// for later flag calculation
|
||||
NOR(s5, xZR, s1);
|
||||
}
|
||||
|
||||
// It's a cmp, we can't store the result back to s1.
|
||||
SUBxw(s6, s1, s2);
|
||||
IFX_PENDOR0 {
|
||||
SDxw(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BGE(s6, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s6);
|
||||
}
|
||||
CALC_SUB_FLAGS(s5, s2, s6, s3, s4, rex.w?64:32);
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s6, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s6, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1, 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
ST_D(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_D(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_D(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SUB_D(s1, xZR);
|
||||
else
|
||||
X64_SUB_W(s1, xZR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
if (rex.w) {
|
||||
BGE(s1, xZR, 8);
|
||||
} else {
|
||||
SRLI_D(s3, s1, 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 TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_AND_B(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
AND(s3, s1, s2);
|
||||
ST_D(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
AND(s3, s1, s2); // res = s1 & s2
|
||||
|
||||
IFX_PENDOR0 {
|
||||
ST_D(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI_D(s4, s3, 7);
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_AND_H(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
AND(s3, s1, s2);
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
CLEAR_FLAGS(s3);
|
||||
AND(s3, s1, s2); // res = s1 & s2
|
||||
|
||||
IFX_PENDOR0 {
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s4, s3, 15);
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
X64_AND_D(s1, s2);
|
||||
else
|
||||
X64_AND_W(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
AND(s3, s1, s2);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
AND(s3, s1, s2); // res = s1 & s2
|
||||
|
||||
IFX_PENDOR0 {
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF | X_ZF) {
|
||||
if (!rex.w) ZEROUP(s3);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI_D(s4, s3, rex.w?63:31);
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
MOV64xw(s3, c);
|
||||
if (rex.w)
|
||||
X64_AND_D(s1, s3);
|
||||
else
|
||||
X64_AND_W(s1, s3);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (c >= 0 && c <= 4095) {
|
||||
ANDI(s3, s1, c);
|
||||
} else {
|
||||
IFX(X_ALL) { } else MOV64xw(s3, c);
|
||||
AND(s3, s1, s3);
|
||||
}
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
if (c >= 0 && c <= 4095) {
|
||||
ANDI(s3, s1, c);
|
||||
} else {
|
||||
IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c);
|
||||
AND(s3, s1, s3);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
SRLI_D(s4, s3, rex.w ? 63 : 31);
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
#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 "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_F0(dynarec_la64_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, eb1, eb2, gb1, gb2;
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j64);
|
||||
|
||||
while ((opcode == 0xF2) || (opcode == 0xF3)) {
|
||||
rep = opcode - 0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
switch (opcode) {
|
||||
case 0x01:
|
||||
INST_NAME("LOCK ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if ((nextop & 0xC0) == 0xC0) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
ADDxw(x4, x1, gd);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND) {
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4, x5);
|
||||
}
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xB1:
|
||||
switch (rep) {
|
||||
case 0:
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5, x6); }
|
||||
MV(x1, ed); // save value
|
||||
SUB_D(x2, x1, xRAX);
|
||||
BNE_MARK2(x2, xZR);
|
||||
MV(ed, gd);
|
||||
MARK2;
|
||||
MVxw(xRAX, x1);
|
||||
} else {
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
MV(x4, gd);
|
||||
LLxw(x1, wback, 0);
|
||||
SUBxw(x3, x1, xRAX);
|
||||
BNEZ_MARK(x3);
|
||||
// EAX == Ed
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
MARK;
|
||||
UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6); }
|
||||
MVxw(xRAX, x1);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC1:
|
||||
switch (rep) {
|
||||
case 0:
|
||||
INST_NAME("LOCK XADD Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
MVxw(x1, ed);
|
||||
MVxw(ed, gd);
|
||||
MVxw(gd, x1);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
ADDxw(x4, x1, gd);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX(X_ALL | X_PEND) {
|
||||
MVxw(x2, x1);
|
||||
emit_add32(dyn, ninst, rex, x2, gd, x3, x4, x5);
|
||||
}
|
||||
MVxw(gd, x1);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("LOCK SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
SUB_D(x4, x1, gd);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4, x5);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // ADD
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("LOCK ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if (MODREG) {
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64 < -2048 || i64 >= 2048) {
|
||||
MOV64xw(x3, i64);
|
||||
}
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
if (i64 >= -2048 && i64 < 2048) {
|
||||
ADDIxw(x4, x1, i64);
|
||||
} else {
|
||||
ADDxw(x4, x1, x3);
|
||||
}
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX(X_ALL | X_PEND) {
|
||||
emit_add32c(dyn, ninst, rex, x1, i64, x3, x4, x5, x6);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 5: // SUB
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("LOCK SUB Ed, Id");
|
||||
} else {
|
||||
INST_NAME("LOCK SUB Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if (MODREG) {
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = xRAX + (nextop & 7) + (rex.b << 3);
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64 <= -2048 || i64 > 2048) {
|
||||
MOV64xw(x3, i64);
|
||||
}
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
if (i64 > -2048 && i64 <= 2048) {
|
||||
ADDIxw(x4, x1, -i64);
|
||||
} else {
|
||||
SUBxw(x4, x1, x3);
|
||||
}
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5, x6);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x87:
|
||||
INST_NAME("LOCK XCHG Ed, Gd");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGD;
|
||||
GETED(0);
|
||||
MV(x1, gd);
|
||||
MV(gd, ed);
|
||||
MV(ed, x1);
|
||||
} else {
|
||||
SMDMB();
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
MV(x4, gd);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
MVxw(gd, x1);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
#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 "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t u8;
|
||||
uint64_t u64, j64;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VXOR_V(v0, v0, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 8, 0);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
}
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
break;
|
||||
case 0x11:
|
||||
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);
|
||||
VEXTRINS_D(d0, v0, 0); // d0[63:0] = v0[63:0]
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d1, ed);
|
||||
FFINT_D_L(d1, d1);
|
||||
} else {
|
||||
MOVGR2FR_W(d1, ed);
|
||||
FFINT_D_W(d1, d1);
|
||||
}
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINTRZ_L_D(d1, q0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINTRZ_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
if (rex.w) {
|
||||
FTINT_L_D(d1, q0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINT_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FADD_D(d0, v0, v1);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMUL_D(d0, v0, v1);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d1, d0);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FSUB_D(d0, v0, v1);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FDIV_D(d0, v0, v1);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, v0, v1, cLE);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
MARK;
|
||||
VEXTRINS_D(v0, v1, 0);
|
||||
MARK2;
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 1);
|
||||
u8 = F8;
|
||||
switch (u8 & 7) {
|
||||
case 0: FCMP_D(fcc0, v0, v1, cEQ); break; // Equal
|
||||
case 1: FCMP_D(fcc0, v0, v1, cLT); break; // Less than
|
||||
case 2: FCMP_D(fcc0, v0, v1, cLE); break; // Less or equal
|
||||
case 3: FCMP_D(fcc0, v0, v1, cUN); break; // NaN
|
||||
case 4: FCMP_D(fcc0, v0, v1, cUNE); break; // Not Equal or unordered
|
||||
case 5: FCMP_D(fcc0, v1, v0, cULE); break; // Greater or equal or unordered
|
||||
case 6: FCMP_D(fcc0, v1, v0, cULT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: FCMP_D(fcc0, v0, v1, cOR); break; // not NaN
|
||||
}
|
||||
MOVCF2GR(x2, fcc0);
|
||||
NEG_D(x2, x2);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_D(q1, x2);
|
||||
VEXTRINS_D(v0, q1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
#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 "la64_emitter.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 "bitutils.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, gback;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
int64_t j64;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
VXOR_V(v0, v0, v0);
|
||||
FLD_S(v1, ed, fixedaddress);
|
||||
}
|
||||
VEXTRINS_W(v0, v1, 0);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if (MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
|
||||
VEXTRINS_W(q0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_S(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("NOP / ENDBR32 / ENDBR64");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SS Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_D(d1, ed);
|
||||
if(rex.w) {
|
||||
FFINT_S_L(d1, d1);
|
||||
} else {
|
||||
FFINT_S_W(d1, d1);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINTRZ_L_S(d1, d0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINTRZ_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRT_S(d1, d0);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADD_S(d1, v0, d0);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMUL_S(d1, v0, d0);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUB_S(d1, v0, d0);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d0, 1);
|
||||
GETEXSS(d1, 0, 0);
|
||||
FCMP_S(fcc0, d0, d1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d1, d0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
MARK;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FMOV_S(v1, d1);
|
||||
VEXTRINS_W(d0, v1, 0);
|
||||
MARK2;
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIV_S(d1, v0, d0);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d0, 1);
|
||||
GETEXSS(d1, 0, 0);
|
||||
FCMP_S(fcc0, d0, d1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d1, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
MARK;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FMOV_S(v1, d1);
|
||||
VEXTRINS_W(d0, v1, 0);
|
||||
MARK2;
|
||||
break;
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
GETGX_empty(v0);
|
||||
VOR_V(v0, v1, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
VXOR_V(v0, v0, v0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
}
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 1);
|
||||
u8 = F8;
|
||||
switch (u8 & 7) {
|
||||
case 0: FCMP_S(fcc0, v0, v1, cEQ); break; // Equal
|
||||
case 1: FCMP_S(fcc0, v0, v1, cLT); break; // Less than
|
||||
case 2: FCMP_S(fcc0, v0, v1, cLE); break; // Less or equal
|
||||
case 3: FCMP_S(fcc0, v0, v1, cUN); break; // NaN
|
||||
case 4: FCMP_S(fcc0, v0, v1, cUNE); break; // Not Equal or unordered
|
||||
case 5: FCMP_S(fcc0, v1, v0, cULE); break; // Greater or equal or unordered
|
||||
case 6: FCMP_S(fcc0, v1, v0, cULT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: FCMP_S(fcc0, v0, v1, cOR); break; // not NaN
|
||||
}
|
||||
MOVCF2GR(x2, fcc0);
|
||||
NEG_D(x2, x2);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_W(q1, x2);
|
||||
VEXTRINS_W(v0, q1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
#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 "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 "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_la64_t* dyn)
|
||||
{
|
||||
return SCRATCH0 + dyn->lsx.fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_la64_t* dyn)
|
||||
{
|
||||
dyn->lsx.fpu_scratch = 0;
|
||||
}
|
||||
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg(dynarec_la64_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
dyn->lsx.fpuused[reg] = 0;
|
||||
if (dyn->lsx.lsxcache[reg].t != LSX_CACHE_ST_F && dyn->lsx.lsxcache[reg].t != LSX_CACHE_ST_D && dyn->lsx.lsxcache[reg].t != LSX_CACHE_ST_I64)
|
||||
dyn->lsx.lsxcache[reg].v = 0;
|
||||
}
|
||||
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_la64_t* dyn, int t, int xmm)
|
||||
{
|
||||
int i;
|
||||
if (xmm > 7) {
|
||||
i = XMM8 + xmm - 8;
|
||||
} else {
|
||||
i = XMM0 + xmm;
|
||||
}
|
||||
dyn->lsx.fpuused[i] = 1;
|
||||
dyn->lsx.lsxcache[i].t = t;
|
||||
dyn->lsx.lsxcache[i].n = xmm;
|
||||
dyn->lsx.news |= (1 << i);
|
||||
return i;
|
||||
}
|
||||
|
||||
// Reset fpu regs counter
|
||||
static void fpu_reset_reg_lsxcache(lsxcache_t* lsx)
|
||||
{
|
||||
lsx->fpu_reg = 0;
|
||||
for (int i = 0; i < 24; ++i) {
|
||||
lsx->fpuused[i] = 0;
|
||||
lsx->lsxcache[i].v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void fpu_reset_reg(dynarec_la64_t* dyn)
|
||||
{
|
||||
fpu_reset_reg_lsxcache(&dyn->lsx);
|
||||
}
|
||||
|
||||
static int isCacheEmpty(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
if (dyn->insts[ninst].lsx.stack_next) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < 24; ++i)
|
||||
if (dyn->insts[ninst].lsx.lsxcache[i].v) { // there is something at ninst for i
|
||||
if (!(
|
||||
(dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_ST_F
|
||||
|| dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_ST_D
|
||||
|| dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_ST_I64)
|
||||
&& dyn->insts[ninst].lsx.lsxcache[i].n < dyn->insts[ninst].lsx.stack_pop))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fpuCacheNeedsTransform(dynarec_la64_t* dyn, int ninst)
|
||||
{
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if (i2 < 0)
|
||||
return 1;
|
||||
if ((dyn->insts[i2].x64.barrier & BARRIER_FLOAT))
|
||||
// if the barrier as already been apply, no transform needed
|
||||
return ((dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? 0 : (isCacheEmpty(dyn, ninst) ? 0 : 1);
|
||||
int ret = 0;
|
||||
if (!i2) { // just purge
|
||||
if (dyn->insts[ninst].lsx.stack_next) {
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < 24 && !ret; ++i)
|
||||
if (dyn->insts[ninst].lsx.lsxcache[i].v) { // there is something at ninst for i
|
||||
if (!(
|
||||
(dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_ST_F
|
||||
|| dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_ST_D
|
||||
|| dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_ST_I64)
|
||||
&& dyn->insts[ninst].lsx.lsxcache[i].n < dyn->insts[ninst].lsx.stack_pop))
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Check if ninst can be compatible to i2
|
||||
if (dyn->insts[ninst].lsx.stack_next != dyn->insts[i2].lsx.stack - dyn->insts[i2].lsx.stack_push) {
|
||||
return 1;
|
||||
}
|
||||
lsxcache_t cache_i2 = dyn->insts[i2].lsx;
|
||||
lsxcacheUnwind(&cache_i2);
|
||||
|
||||
for (int i = 0; i < 24; ++i) {
|
||||
if (dyn->insts[ninst].lsx.lsxcache[i].v) { // there is something at ninst for i
|
||||
if (!cache_i2.lsxcache[i].v) { // but there is nothing at i2 for i
|
||||
ret = 1;
|
||||
} else if (dyn->insts[ninst].lsx.lsxcache[i].v != cache_i2.lsxcache[i].v) { // there is something different
|
||||
if (dyn->insts[ninst].lsx.lsxcache[i].n != cache_i2.lsxcache[i].n) { // not the same x64 reg
|
||||
ret = 1;
|
||||
} else if (dyn->insts[ninst].lsx.lsxcache[i].t == LSX_CACHE_XMMR && cache_i2.lsxcache[i].t == LSX_CACHE_XMMW) { /* nothing */
|
||||
} else
|
||||
ret = 1;
|
||||
}
|
||||
} else if (cache_i2.lsxcache[i].v)
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lsxcacheUnwind(lsxcache_t* cache)
|
||||
{
|
||||
if (cache->swapped) {
|
||||
// unswap
|
||||
int a = -1;
|
||||
int b = -1;
|
||||
for (int j = 0; j < 24 && ((a == -1) || (b == -1)); ++j)
|
||||
if ((cache->lsxcache[j].t == LSX_CACHE_ST_D || cache->lsxcache[j].t == LSX_CACHE_ST_F || cache->lsxcache[j].t == LSX_CACHE_ST_I64)) {
|
||||
if (cache->lsxcache[j].n == cache->combined1)
|
||||
a = j;
|
||||
else if (cache->lsxcache[j].n == cache->combined2)
|
||||
b = j;
|
||||
}
|
||||
if (a != -1 && b != -1) {
|
||||
int tmp = cache->lsxcache[a].n;
|
||||
cache->lsxcache[a].n = cache->lsxcache[b].n;
|
||||
cache->lsxcache[b].n = tmp;
|
||||
}
|
||||
cache->swapped = 0;
|
||||
cache->combined1 = cache->combined2 = 0;
|
||||
}
|
||||
if (cache->news) {
|
||||
// reove the newly created lsxcache
|
||||
for (int i = 0; i < 24; ++i)
|
||||
if (cache->news & (1 << i))
|
||||
cache->lsxcache[i].v = 0;
|
||||
cache->news = 0;
|
||||
}
|
||||
if (cache->stack_push) {
|
||||
// unpush
|
||||
for (int j = 0; j < 24; ++j) {
|
||||
if ((cache->lsxcache[j].t == LSX_CACHE_ST_D || cache->lsxcache[j].t == LSX_CACHE_ST_F || cache->lsxcache[j].t == LSX_CACHE_ST_I64)) {
|
||||
if (cache->lsxcache[j].n < cache->stack_push)
|
||||
cache->lsxcache[j].v = 0;
|
||||
else
|
||||
cache->lsxcache[j].n -= cache->stack_push;
|
||||
}
|
||||
}
|
||||
cache->x87stack -= cache->stack_push;
|
||||
cache->stack -= cache->stack_push;
|
||||
cache->stack_push = 0;
|
||||
}
|
||||
cache->x87stack += cache->stack_pop;
|
||||
cache->stack_next = cache->stack;
|
||||
cache->stack_pop = 0;
|
||||
cache->barrier = 0;
|
||||
// And now, rebuild the x87cache info with lsxcache
|
||||
cache->mmxcount = 0;
|
||||
cache->fpu_scratch = 0;
|
||||
cache->fpu_extra_qscratch = 0;
|
||||
cache->fpu_reg = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
cache->x87cache[i] = -1;
|
||||
cache->mmxcache[i] = -1;
|
||||
cache->x87reg[i] = 0;
|
||||
cache->ssecache[i * 2].v = -1;
|
||||
cache->ssecache[i * 2 + 1].v = -1;
|
||||
}
|
||||
int x87reg = 0;
|
||||
for (int i = 0; i < 24; ++i) {
|
||||
if (cache->lsxcache[i].v) {
|
||||
cache->fpuused[i] = 1;
|
||||
switch (cache->lsxcache[i].t) {
|
||||
case LSX_CACHE_MM:
|
||||
cache->mmxcache[cache->lsxcache[i].n] = i;
|
||||
++cache->mmxcount;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case LSX_CACHE_XMMR:
|
||||
case LSX_CACHE_XMMW:
|
||||
cache->ssecache[cache->lsxcache[i].n].reg = i;
|
||||
cache->ssecache[cache->lsxcache[i].n].write = (cache->lsxcache[i].t == LSX_CACHE_XMMW) ? 1 : 0;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case LSX_CACHE_ST_F:
|
||||
case LSX_CACHE_ST_D:
|
||||
case LSX_CACHE_ST_I64:
|
||||
cache->x87cache[x87reg] = cache->lsxcache[i].n;
|
||||
cache->x87reg[x87reg] = i;
|
||||
++x87reg;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case LSX_CACHE_SCR:
|
||||
cache->fpuused[i] = 0;
|
||||
cache->lsxcache[i].v = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cache->fpuused[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
static char buff[20];
|
||||
switch (t) {
|
||||
case LSX_CACHE_ST_D: sprintf(buff, "ST%d", n); break;
|
||||
case LSX_CACHE_ST_F: sprintf(buff, "st%d", n); break;
|
||||
case LSX_CACHE_ST_I64: sprintf(buff, "STi%d", n); break;
|
||||
case LSX_CACHE_MM: sprintf(buff, "MM%d", n); break;
|
||||
case LSX_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
|
||||
case LSX_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
|
||||
case LSX_CACHE_SCR: sprintf(buff, "Scratch"); break;
|
||||
case LSX_CACHE_NONE: buff[0] = '\0'; break;
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
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].lsx.lsxcache[ii].t) {
|
||||
case LSX_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_ST_I64: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_NONE:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (dyn->lsx.stack || dyn->insts[ninst].lsx.stack_next || dyn->insts[ninst].lsx.x87stack)
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->lsx.stack, dyn->insts[ninst].lsx.stack_next, dyn->insts[ninst].lsx.stack_push, dyn->insts[ninst].lsx.stack_pop, dyn->insts[ninst].lsx.x87stack);
|
||||
if (dyn->insts[ninst].lsx.combined1 || dyn->insts[ninst].lsx.combined2)
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].lsx.swapped ? "SWP" : "CMB", dyn->insts[ninst].lsx.combined1, dyn->insts[ninst].lsx.combined2);
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump > 1) ? "\e[m" : "");
|
||||
}
|
||||
}
|
||||
|
||||
// will go badly if address is unaligned
|
||||
static uint8_t extract_byte(uint32_t val, void* address)
|
||||
{
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
return (val>>idx)&0xff;
|
||||
}
|
||||
|
||||
static uint32_t insert_byte(uint32_t val, uint8_t b, void* address)
|
||||
{
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
val&=~(0xff<<idx);
|
||||
val|=(((uint32_t)b)<<idx);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint16_t extract_half(uint32_t val, void* address)
|
||||
{
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
return (val>>idx)&0xffff;
|
||||
}
|
||||
|
||||
static uint32_t insert_half(uint32_t val, uint16_t h, void* address)
|
||||
{
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
val&=~(0xffff<<idx);
|
||||
val|=(((uint32_t)h)<<idx);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t la64_lock_xchg_b_slow(void* addr, uint8_t val)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint32_t* aligned = (uint32_t*)(((uintptr_t)addr)&~3);
|
||||
do {
|
||||
ret = *aligned;
|
||||
} while(la64_lock_cas_d(aligned, ret, insert_byte(ret, val, addr)));
|
||||
return extract_byte(ret, addr);
|
||||
}
|
||||
|
||||
int la64_lock_cas_b_slow(void* addr, uint8_t ref, uint8_t val)
|
||||
{
|
||||
uint32_t* aligned = (uint32_t*)(((uintptr_t)addr)&~3);
|
||||
uint32_t tmp = *aligned;
|
||||
return la64_lock_cas_d(aligned, ref, insert_byte(tmp, val, addr));
|
||||
}
|
||||
|
||||
int la64_lock_cas_h_slow(void* addr, uint16_t ref, uint16_t val)
|
||||
{
|
||||
uint32_t* aligned = (uint32_t*)(((uintptr_t)addr)&~3);
|
||||
uint32_t tmp = *aligned;
|
||||
return la64_lock_cas_d(aligned, ref, insert_half(tmp, val, addr));
|
||||
}
|
||||
|
||||
void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode)
|
||||
{
|
||||
dynarec_log(LOG_NONE, "\t%08x\t%s\n", opcode, la64_print(opcode, (uintptr_t)dyn->block));
|
||||
}
|
||||
|
||||
static void sse_reset(lsxcache_t* lsx)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
lsx->ssecache[i].v = -1;
|
||||
}
|
||||
|
||||
void fpu_reset(dynarec_la64_t* dyn)
|
||||
{
|
||||
// TODO: x87 and mmx
|
||||
sse_reset(&dyn->lsx);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
void fpu_reset_ninst(dynarec_la64_t* dyn, int ninst)
|
||||
{
|
||||
// TODO: x87 and mmx
|
||||
sse_reset(&dyn->insts[ninst].lsx);
|
||||
fpu_reset_reg_lsxcache(&dyn->insts[ninst].lsx);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef __DYNAREC_LA64_FUNCTIONS_H__
|
||||
#define __DYNAREC_LA64_FUNCTIONS_H__
|
||||
|
||||
#include "../dynarec_native_functions.h"
|
||||
|
||||
#define SCRATCH0 24
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynarec_la64_s dynarec_la64_t;
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_la64_t* dyn);
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_la64_t* dyn);
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_la64_t* dyn, int t, int xmm);
|
||||
// Free a FPU/MMX/XMM reg
|
||||
void fpu_free_reg(dynarec_la64_t* dyn, int reg);
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_la64_t* dyn);
|
||||
|
||||
// FPU Cache transformation (for loops) // Specific, need to be written by backend
|
||||
int fpuCacheNeedsTransform(dynarec_la64_t* dyn, int ninst);
|
||||
|
||||
// Undo the changes of a lsxcache to get the status before the instruction
|
||||
void lsxcacheUnwind(lsxcache_t* cache);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
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);
|
||||
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_native_t* dyn);
|
||||
void fpu_reset_ninst(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
#endif //__DYNAREC_LA64_FUNCTIONS_H__
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "la64_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block;
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
uintptr_t diff = (intptr_t)next - (intptr_t)addr;
|
||||
PCADDU12I(x2, SPLIT20(diff));
|
||||
LD_D(x2, x2, SPLIT12(diff));
|
||||
BR(x2);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#define INIT uintptr_t sav_addr = addr
|
||||
#define FINI \
|
||||
dyn->isize = addr - sav_addr; \
|
||||
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 MESSAGE(A, ...)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; \
|
||||
dyn->f.dfnone = 1; \
|
||||
dyn->f.pending = SF_SET
|
||||
#define SETFLAGS(A, B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = B; \
|
||||
dyn->f.pending = (B) & SF_SET_PENDING; \
|
||||
dyn->f.dfnone = ((B) & SF_SET) ? 1 : 0;
|
||||
#define EMIT(A) dyn->native_size += 4
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
|
||||
#define BARRIER(A) \
|
||||
if (A != BARRIER_MAYBE) { \
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); \
|
||||
dyn->insts[ninst].x64.barrier = A; \
|
||||
} else \
|
||||
dyn->insts[ninst].barrier_maybe = 1
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
dyn->insts[ninst].x64.addr = ip; \
|
||||
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
|
||||
dyn->lsx.swapped = 0; \
|
||||
dyn->lsx.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if (ninst) { dyn->insts[ninst - 1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst - 1].x64.addr; }
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].lsx = dyn->lsx; \
|
||||
dyn->insts[ninst].x64.has_next = (ok > 0) ? 1 : 0;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
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), \
|
||||
PKip(10), PKip(11), PKip(12), \
|
||||
PKip(13), PKip(14)); \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
|
||||
dyn->lsx.swapped = 0; \
|
||||
dyn->lsx.barrier = 0
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].lsx = dyn->lsx; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
|
||||
#define INST_NAME(name)
|
||||
@@ -0,0 +1,26 @@
|
||||
#define INIT dyn->native_size = 0
|
||||
#define FINI \
|
||||
if (ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst - 1].address + dyn->insts[ninst - 1].size); \
|
||||
dyn->insts_size += 1 + ((dyn->insts[ninst].x64.size > (dyn->insts[ninst].size / 4)) ? dyn->insts[ninst].x64.size : (dyn->insts[ninst].size / 4)) / 15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) \
|
||||
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); \
|
||||
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), 2); \
|
||||
EMIT(0); \
|
||||
EMIT(0); \
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
if (ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x64.size, dyn->insts[ninst].size / 4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#define EMIT(A) \
|
||||
do { \
|
||||
if (box64_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
|
||||
if ((uintptr_t)dyn->block < dyn->tablestart) \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; \
|
||||
dyn->native_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4; \
|
||||
} while (0)
|
||||
|
||||
#define MESSAGE(A, ...) \
|
||||
if (box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if (ninst) \
|
||||
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) 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)); \
|
||||
PCADDU12I(A, SPLIT20(val64offset)); \
|
||||
LD_D(A, A, SPLIT12(val64offset)); \
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
#ifndef __DYNAREC_LA64_PRIVATE_H_
|
||||
#define __DYNAREC_LA64_PRIVATE_H_
|
||||
|
||||
#include "../dynarec_private.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
#define LSX_CACHE_NONE 0
|
||||
#define LSX_CACHE_ST_D 1
|
||||
#define LSX_CACHE_ST_F 2
|
||||
#define LSX_CACHE_ST_I64 3
|
||||
#define LSX_CACHE_MM 4
|
||||
#define LSX_CACHE_XMMW 5
|
||||
#define LSX_CACHE_XMMR 6
|
||||
#define LSX_CACHE_SCR 7
|
||||
|
||||
typedef union lsx_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
uint8_t t : 4; // reg type
|
||||
uint8_t n : 4; // reg number
|
||||
};
|
||||
} lsx_cache_t;
|
||||
|
||||
typedef union sse_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
uint8_t reg : 7;
|
||||
uint8_t write : 1;
|
||||
};
|
||||
} sse_cache_t;
|
||||
|
||||
typedef struct lsxcache_s {
|
||||
// LSX cache
|
||||
lsx_cache_t lsxcache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
int8_t stack_push;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8]; // cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int8_t freed[8]; // set when FFREE is used, -1 else
|
||||
int8_t mmxcache[8]; // cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[16]; // cache status for the 16 SSE(2) registers
|
||||
int8_t fpuused[24]; // all 0..24 double reg from fpu, used by x87, sse and mmx
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch; // scratch counter
|
||||
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
} lsxcache_t;
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if deferred flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_la64_s {
|
||||
instruction_x64_t x64;
|
||||
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 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[3];
|
||||
uintptr_t markf[2];
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
uint8_t barrier_maybe;
|
||||
uint8_t will_write;
|
||||
uint8_t last_write;
|
||||
flagcache_t f_exit; // flags status at end of instruction
|
||||
lsxcache_t lsx; // lsxcache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_la64_t;
|
||||
|
||||
typedef struct dynarec_la64_s {
|
||||
instruction_la64_t* insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in bytes of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emitted
|
||||
uintptr_t native_start; // start of the arm code
|
||||
size_t native_size; // size of emitted arm code
|
||||
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state) TODO: move to a cache something
|
||||
uint64_t* table64; // table of 64bits values
|
||||
int table64size;// size of table (will be appended at end of executable code)
|
||||
int table64cap;
|
||||
uintptr_t tablestart;
|
||||
uintptr_t jmp_next; // address of the jump_next address
|
||||
flagcache_t f;
|
||||
lsxcache_t lsx;
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
int* jmps; // variable array of jump instructions
|
||||
int jmp_sz;
|
||||
int jmp_cap;
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uint8_t always_test;
|
||||
uint8_t abort;
|
||||
} dynarec_la64_t;
|
||||
|
||||
void add_next(dynarec_la64_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_la64_t *dyn, uintptr_t addr);
|
||||
void add_jump(dynarec_la64_t *dyn, int ninst);
|
||||
int get_first_jump(dynarec_la64_t *dyn, int next);
|
||||
int is_nops(dynarec_la64_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_la64_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
int Table64(dynarec_la64_t *dyn, uint64_t val, int pass); // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#define GO_TRACE(A, B, s0) \
|
||||
GETIP(addr); \
|
||||
MV(A1, xRIP); \
|
||||
STORE_XEMU_CALL(); \
|
||||
MOV64x(A2, B); \
|
||||
CALL(A, -1); \
|
||||
LOAD_XEMU_CALL()
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,66 @@
|
||||
//la64 epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global la64_epilog
|
||||
.global la64_epilog_fast
|
||||
|
||||
la64_epilog:
|
||||
// update register -> emu
|
||||
st.d $r12, $r4, (8 * 0)
|
||||
st.d $r13, $r4, (8 * 1)
|
||||
st.d $r14, $r4, (8 * 2)
|
||||
st.d $r15, $r4, (8 * 3)
|
||||
st.d $r16, $r4, (8 * 4)
|
||||
st.d $r17, $r4, (8 * 5)
|
||||
st.d $r18, $r4, (8 * 6)
|
||||
st.d $r19, $r4, (8 * 7)
|
||||
st.d $r23, $r4, (8 * 8)
|
||||
st.d $r24, $r4, (8 * 9)
|
||||
st.d $r25, $r4, (8 * 10)
|
||||
st.d $r26, $r4, (8 * 11)
|
||||
st.d $r27, $r4, (8 * 12)
|
||||
st.d $r28, $r4, (8 * 13)
|
||||
st.d $r29, $r4, (8 * 14)
|
||||
st.d $r30, $r4, (8 * 15)
|
||||
// restore xFlags from LBT.eflags
|
||||
la.global $r12, la64_lbt
|
||||
ldptr.d $r12, $r12, 0
|
||||
beqz $r12, 1f
|
||||
ori $r13, $r0, 0b100011010101
|
||||
andn $r31, $r31, $r13
|
||||
x86mfflag $r13, 0b111111
|
||||
or $r31, $r31, $r13
|
||||
1:
|
||||
st.d $r31, $r4, (8 * 16) // xFlags
|
||||
st.d $r20, $r4, (8 * 17) // put back reg value in emu, including EIP (so $r20 must be EIP now)
|
||||
// fallback to epilog_fast now, just restoring saved regs
|
||||
la64_epilog_fast:
|
||||
addi.d $sp, $r22, 0 // restore save sp from xSavedSP
|
||||
// restore all used register
|
||||
ld.d $r1, $sp, (8 * 0) // load ra
|
||||
ld.d $r22, $sp, (8 * 1) // load fp
|
||||
ld.d $r23, $sp, (8 * 2)
|
||||
ld.d $r24, $sp, (8 * 3)
|
||||
ld.d $r25, $sp, (8 * 4)
|
||||
ld.d $r26, $sp, (8 * 5)
|
||||
ld.d $r27, $sp, (8 * 6)
|
||||
ld.d $r28, $sp, (8 * 7)
|
||||
ld.d $r29, $sp, (8 * 8)
|
||||
ld.d $r30, $sp, (8 * 9)
|
||||
ld.d $r31, $sp, (8 * 10)
|
||||
fld.d $f24, $sp, (8 * 11)
|
||||
fld.d $f25, $sp, (8 * 12)
|
||||
fld.d $f26, $sp, (8 * 13)
|
||||
fld.d $f27, $sp, (8 * 14)
|
||||
fld.d $f28, $sp, (8 * 15)
|
||||
fld.d $f29, $sp, (8 * 16)
|
||||
fld.d $f30, $sp, (8 * 17)
|
||||
fld.d $f31, $sp, (8 * 18)
|
||||
addi.d $sp, $sp, (8 * 19)
|
||||
// end, return
|
||||
ret
|
||||
@@ -0,0 +1,216 @@
|
||||
// LA64 lock helper
|
||||
// there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global la64_lock_xchg_b
|
||||
.global la64_lock_xchg_dd
|
||||
.global la64_lock_xchg_d
|
||||
.global la64_lock_storeifnull
|
||||
.global la64_lock_storeifnull_d
|
||||
.global la64_lock_storeifref
|
||||
.global la64_lock_storeifref_d
|
||||
.global la64_lock_storeifref2_d
|
||||
.global la64_lock_storeb
|
||||
.global la64_lock_incif0
|
||||
.global la64_lock_decifnot0
|
||||
.global la64_lock_store
|
||||
.global la64_lock_store_dd
|
||||
.global la64_lock_cas_b
|
||||
.global la64_lock_cas_h
|
||||
.global la64_lock_cas_d
|
||||
.global la64_lock_cas_dd
|
||||
.global la64_lock_cas_dq
|
||||
.global la64_lock_get_b
|
||||
.global la64_lock_get_d
|
||||
.global la64_lock_get_dd
|
||||
|
||||
la64_lock_xchg_b:
|
||||
.word 0x385e1486 // amswap_db.b $a2, $a1, $a0
|
||||
move $a0, $a2
|
||||
ret
|
||||
|
||||
la64_lock_xchg_dd:
|
||||
// address is a0, value is a1, return old value in a0
|
||||
amswap_db.d $a2, $a1, $a0
|
||||
move $a0, $a2
|
||||
ret
|
||||
|
||||
la64_lock_xchg_d:
|
||||
// address is a0, value is a1, return old value in a0
|
||||
amswap_db.w $a2, $a1, $a0
|
||||
move $a0, $a2
|
||||
ret
|
||||
|
||||
la64_lock_storeifnull:
|
||||
// address is a0, value is a1, a1 store to a0 only if [a0] is 0. return old [a0] value
|
||||
dbar 0
|
||||
1:
|
||||
move $a3, $a1
|
||||
ll.d $a2, $a0, 0
|
||||
bnez $a2, 2f
|
||||
sc.d $a3, $a0, 0
|
||||
beqz $a3, 1b
|
||||
2:
|
||||
move $a0, $a2
|
||||
ret
|
||||
|
||||
la64_lock_storeifnull_d:
|
||||
// address is a0, value is a1, a1 store to a0 only if [a0] is 0. return old [a0] value
|
||||
dbar 0
|
||||
move $a3, $a1
|
||||
1:
|
||||
ll.w $a2, $a0, 0
|
||||
bnez $a2, 2f
|
||||
sc.w $a3, $a0, 0
|
||||
beqz $a3, 1b
|
||||
2:
|
||||
move $a0, $a2
|
||||
ret
|
||||
|
||||
la64_lock_storeifref:
|
||||
// address is a0, value is a1, a1 store to a0 only if [a0] is a2. return new [a0] value (so a1 or old value)
|
||||
dbar 0
|
||||
1:
|
||||
move $a4, $a1
|
||||
ll.d $a3, $a0, 0
|
||||
bne $a2, $a3, 2f
|
||||
sc.d $a4, $a0, 0
|
||||
beqz $a4, 1b
|
||||
move $a0, $a1
|
||||
ret
|
||||
2:
|
||||
move $a0, $a3
|
||||
ret
|
||||
|
||||
la64_lock_storeifref_d:
|
||||
// address is a0, value is a1, a1 store to a0 only if [a0] is a2. return new [a0] value (so a1 or old value)
|
||||
dbar 0
|
||||
1:
|
||||
move $a4, $a1
|
||||
ll.w $a3, $a0, 0
|
||||
bne $a2, $a3, 2f
|
||||
sc.w $a4, $a0, 0
|
||||
beqz $a4, 1b
|
||||
move $a0, $a1
|
||||
ret
|
||||
2:
|
||||
move $a0, $a3
|
||||
ret
|
||||
|
||||
la64_lock_storeifref2_d:
|
||||
// address is a0, value is a1, a1 store to a0 only if [a0] is a2. return old [a0] value
|
||||
dbar 0
|
||||
1:
|
||||
move $a4, $a1
|
||||
ll.w $a3, $a0, 0
|
||||
bne $a2, $a3, 2f
|
||||
sc.w $a4, $a0, 0
|
||||
beqz $a4, 1b
|
||||
2:
|
||||
move $a0, $a3
|
||||
ret
|
||||
|
||||
la64_lock_storeb:
|
||||
st.b $a1, $a0, 0
|
||||
dbar 0
|
||||
ret
|
||||
|
||||
la64_lock_decifnot0:
|
||||
dbar 0
|
||||
1:
|
||||
ll.w $a1, $a0, 0
|
||||
beqz $a1, 2f
|
||||
addi.d $a1, $a1, -1
|
||||
move $a2, $a1
|
||||
sc.w $a2, $a0, 0
|
||||
beqz $a2, 1b
|
||||
2:
|
||||
move $a0, $a1
|
||||
ret
|
||||
|
||||
la64_lock_incif0:
|
||||
dbar 0
|
||||
1:
|
||||
ll.w $a1, $a0, 0
|
||||
bnez $a1, 2f
|
||||
addi.d $a1, $a1, 1
|
||||
move $a2, $a1
|
||||
sc.w $a2, $a0, 0
|
||||
beqz $a2, 1b
|
||||
2:
|
||||
move $a0, $a1
|
||||
ret
|
||||
|
||||
la64_lock_store:
|
||||
st.w $a1, $a0, 0
|
||||
dbar 0
|
||||
ret
|
||||
|
||||
la64_lock_store_dd:
|
||||
st.d $a1, $a0, 0
|
||||
dbar 0
|
||||
ret
|
||||
|
||||
la64_lock_cas_b:
|
||||
ext.w.b $a3, $a1
|
||||
.word 0x385a1885 // amcas_db.b $a1, $a2, $a0
|
||||
xor $a0, $a1, $a3
|
||||
sltu $a0, $zero, $a0
|
||||
ret
|
||||
|
||||
la64_lock_cas_h:
|
||||
ext.w.h $a3, $a1
|
||||
.word 0x385a9885 // amcas_db.h $a1, $a2, $a0
|
||||
xor $a0, $a1, $a3
|
||||
sltu $a0, $zero, $a0
|
||||
ret
|
||||
|
||||
la64_lock_cas_d:
|
||||
ll.w $a3, $a0, 0
|
||||
bne $a3, $a1, 1f
|
||||
sc.w $a2, $a0, 0
|
||||
xori $a0, $a2, 1 // sc return success in $a2, overwriting it! 0 = fail, 1 = success
|
||||
ret
|
||||
1:
|
||||
li.d $a0, 1
|
||||
ret
|
||||
|
||||
la64_lock_cas_dd:
|
||||
ll.d $a3, $a0, 0
|
||||
bne $a3, $a1, 1f
|
||||
sc.d $a2, $a0, 0
|
||||
xori $a0, $a2, 1
|
||||
1:
|
||||
ret
|
||||
li.d $a0, 1
|
||||
ret
|
||||
|
||||
la64_lock_cas_dq:
|
||||
ll.d $a4, $a0, 0
|
||||
bne $a4, $a2, 1f
|
||||
sc.d $a1, $a0, 0
|
||||
beqz $a1, 1f
|
||||
st.d $a3, $a0, 8
|
||||
xori $a0, $a1, 1
|
||||
ret
|
||||
1:
|
||||
li.d $a0, 1
|
||||
ret
|
||||
|
||||
la64_lock_get_b:
|
||||
dbar 0
|
||||
ld.b $a0, $a0, 0
|
||||
ret
|
||||
|
||||
la64_lock_get_d:
|
||||
dbar 0
|
||||
ld.w $a0, $a0, 0
|
||||
ret
|
||||
|
||||
la64_lock_get_dd:
|
||||
dbar 0
|
||||
ld.d $a0, $a0, 0
|
||||
ret
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef __LA64_LOCK__H__
|
||||
#define __LA64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
|
||||
extern int la64_lamcas;
|
||||
extern int la64_lam_bh;
|
||||
|
||||
// Atomically store val at [p] if old [p] is ref. Return 0 if OK, 1 is not. p needs to be aligned
|
||||
extern int
|
||||
la64_lock_cas_d(void* p, int32_t ref, int32_t val);
|
||||
|
||||
// Atomically store val at [p] if old [p] is ref. Return 0 if OK, 1 is not. p needs to be aligned
|
||||
extern int la64_lock_cas_dd(void* p, int64_t ref, int64_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t la64_lock_xchg_dd(void* p, uintptr_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t la64_lock_xchg_d(void* p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern uint32_t la64_lock_storeifnull_d(void* p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* la64_lock_storeifnull(void* p, void* val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* la64_lock_storeifref(void* p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t la64_lock_storeifref_d(void* p, uint32_t val, uint32_t ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t la64_lock_storeifref2_d(void* p, uint32_t val, uint32_t ref);
|
||||
|
||||
// decrement atomically the byte at [p] (but only if p not 0)
|
||||
extern void la64_lock_decifnot0b(void* p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void la64_lock_storeb(void* p, uint8_t b);
|
||||
|
||||
// increment atomically the int at [p] only if it was 0. Return the old value of [p]
|
||||
extern int la64_lock_incif0(void* p);
|
||||
|
||||
// decrement atomically the int at [p] (but only if p not 0)
|
||||
extern int la64_lock_decifnot0(void* p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void la64_lock_store(void* p, uint32_t v);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void la64_lock_store_dd(void* p, uint64_t v);
|
||||
|
||||
// (mostly) Atomically store val1 and val2 at [p] if old [p] is ref. Return 0 if OK, 1 is not. p needs to be aligned
|
||||
extern int la64_lock_cas_dq(void* p, uint64_t ref, uint64_t val1, uint64_t val2);
|
||||
|
||||
// atomic get (with memory barrier)
|
||||
extern uint32_t la64_lock_get_b(void* p);
|
||||
|
||||
// atomic get (with memory barrier)
|
||||
extern uint32_t la64_lock_get_d(void* p);
|
||||
|
||||
// atomic get (with memory barrier)
|
||||
extern void* la64_lock_get_dd(void* p);
|
||||
|
||||
uint8_t la64_lock_xchg_b(void* addr, uint8_t v);
|
||||
extern int la64_lock_cas_b(void* p, uint8_t ref, uint8_t val);
|
||||
extern int la64_lock_cas_h(void* p, uint16_t ref, uint16_t val);
|
||||
|
||||
// Not defined in assembler but in dynarec_la64_functions
|
||||
uint8_t la64_lock_xchg_b_slow(void* addr, uint8_t v);
|
||||
extern int la64_lock_cas_b_slow(void* p, uint8_t ref, uint8_t val);
|
||||
extern int la64_lock_cas_h_slow(void* p, uint16_t ref, uint16_t val);
|
||||
|
||||
#endif //__LA64_LOCK__H__
|
||||
@@ -0,0 +1,52 @@
|
||||
//la64 update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern LinkNext
|
||||
|
||||
.global la64_next
|
||||
|
||||
.8byte 0 // NULL pointer before la64_next, for getDB
|
||||
la64_next:
|
||||
// emu is a0
|
||||
// IP address is a1
|
||||
addi.d $sp, $sp, -(8 * 12)
|
||||
st.d $a0, $sp, 0
|
||||
st.d $a1, $sp, 8
|
||||
st.d $r11, $sp, 16
|
||||
st.d $r12, $sp, 24
|
||||
st.d $r13, $sp, 32
|
||||
st.d $r14, $sp, 40
|
||||
st.d $r15, $sp, 48
|
||||
st.d $r16, $sp, 56
|
||||
st.d $r17, $sp, 64
|
||||
st.d $r18, $sp, 72
|
||||
st.d $r19, $sp, 80
|
||||
st.d $r20, $sp, 88 // also save r20(rip) to allow change in LinkNext
|
||||
|
||||
move $a2, $ra // "from" is in ra, so put in a2
|
||||
addi.d $a3, $sp, 88 // a3 is address to change rip
|
||||
// call the function
|
||||
bl LinkNext
|
||||
// preserve return value
|
||||
move $a3, $a0
|
||||
// pop regs
|
||||
ld.d $a0, $sp, 0
|
||||
ld.d $a1, $sp, 8
|
||||
ld.d $r11, $sp, 16
|
||||
ld.d $r12, $sp, 24
|
||||
ld.d $r13, $sp, 32
|
||||
ld.d $r14, $sp, 40
|
||||
ld.d $r15, $sp, 48
|
||||
ld.d $r16, $sp, 56
|
||||
ld.d $r17, $sp, 64
|
||||
ld.d $r18, $sp, 72
|
||||
ld.d $r19, $sp, 80
|
||||
ld.d $r20, $sp, 88
|
||||
addi.d $sp, $sp, (8 * 12)
|
||||
// return offset is jump address
|
||||
jr $a3
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
#ifndef _LA64_PRINTER_H_
|
||||
#define _LA64_PRINTER_H_
|
||||
|
||||
const char* la64_print(uint32_t opcode, uint64_t addr);
|
||||
|
||||
#endif //_LA64_PRINTER_H_
|
||||
@@ -0,0 +1,71 @@
|
||||
//loongarch prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern la64_lbt
|
||||
|
||||
.global la64_prolog
|
||||
la64_prolog:
|
||||
//save all 18 used register
|
||||
addi.d $sp, $sp, -(8 * 19)
|
||||
st.d $r1, $sp, (8 * 0) //save ra
|
||||
st.d $r22, $sp, (8 * 1) //save fp
|
||||
// save s0 - s8
|
||||
st.d $r23, $sp, (8 * 2)
|
||||
st.d $r24, $sp, (8 * 3)
|
||||
st.d $r25, $sp, (8 * 4)
|
||||
st.d $r26, $sp, (8 * 5)
|
||||
st.d $r27, $sp, (8 * 6)
|
||||
st.d $r28, $sp, (8 * 7)
|
||||
st.d $r29, $sp, (8 * 8)
|
||||
st.d $r30, $sp, (8 * 9)
|
||||
st.d $r31, $sp, (8 * 10)
|
||||
// save fs0 - fs7
|
||||
fst.d $f24, $sp, (8 * 11)
|
||||
fst.d $f25, $sp, (8 * 12)
|
||||
fst.d $f26, $sp, (8 * 13)
|
||||
fst.d $f27, $sp, (8 * 14)
|
||||
fst.d $f28, $sp, (8 * 15)
|
||||
fst.d $f29, $sp, (8 * 16)
|
||||
fst.d $f30, $sp, (8 * 17)
|
||||
fst.d $f31, $sp, (8 * 18)
|
||||
// setup emu -> register
|
||||
ld.d $r12, $r4, (8 * 0)
|
||||
ld.d $r13, $r4, (8 * 1)
|
||||
ld.d $r14, $r4, (8 * 2)
|
||||
ld.d $r15, $r4, (8 * 3)
|
||||
ld.d $r16, $r4, (8 * 4)
|
||||
ld.d $r17, $r4, (8 * 5)
|
||||
ld.d $r18, $r4, (8 * 6)
|
||||
ld.d $r19, $r4, (8 * 7)
|
||||
ld.d $r23, $r4, (8 * 8)
|
||||
ld.d $r24, $r4, (8 * 9)
|
||||
ld.d $r25, $r4, (8 * 10)
|
||||
ld.d $r26, $r4, (8 * 11)
|
||||
ld.d $r27, $r4, (8 * 12)
|
||||
ld.d $r28, $r4, (8 * 13)
|
||||
ld.d $r29, $r4, (8 * 14)
|
||||
ld.d $r30, $r4, (8 * 15)
|
||||
ld.d $r31, $r4, (8 * 16) // xFlags
|
||||
ld.d $r20, $r4, (8 * 17) // xRIP
|
||||
// spill xFlags to LBT.eflags
|
||||
la.global $a6, la64_lbt
|
||||
ldptr.d $a6, $a6, 0
|
||||
beqz $a6, 1f
|
||||
x86mtflag $r31, 0b111111
|
||||
1:
|
||||
// push sentinel onto the stack
|
||||
st.d $r0, $sp, -16
|
||||
st.d $r0, $sp, -8
|
||||
addi.d $sp, $sp, -16
|
||||
// save old sp into xSavedSP
|
||||
addi.d $r22, $sp, 16
|
||||
// setup xMASK
|
||||
addi.w $r11, $r0, -1
|
||||
lu32i.d $r11, 0
|
||||
//jump to function
|
||||
jirl $r0, $a1, 0
|
||||
@@ -23,7 +23,7 @@
|
||||
#define native_lock_storeifref2_d(A, B, C) arm64_lock_storeifref2_d(A, B, C)
|
||||
#define native_lock_storeifnull(A, B) arm64_lock_storeifnull(A, B)
|
||||
#define native_lock_storeifnull_d(A, B) arm64_lock_storeifnull_d(A, B)
|
||||
#define native_lock_decifnot0b(A) arm64_lock_decifnot0b(A)
|
||||
// #define native_lock_decifnot0b(A) arm64_lock_decifnot0b(A)
|
||||
#define native_lock_storeb(A, B) arm64_lock_storeb(A, B)
|
||||
#define native_lock_incif0(A) arm64_lock_incif0(A)
|
||||
#define native_lock_decifnot0(A) arm64_lock_decifnot0(A)
|
||||
@@ -37,7 +37,7 @@
|
||||
#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
|
||||
// RV64 is quite strict (or at least strongly recommand) on what you can do between an LR and an SC
|
||||
// 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
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#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_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)
|
||||
@@ -57,11 +57,7 @@
|
||||
#define native_lock_store_dd(A, B) rv64_lock_store_dd(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)
|
||||
@@ -71,14 +67,63 @@
|
||||
#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_read_dq(A, B, C) \
|
||||
do { \
|
||||
*A = tmpcas = ((uint64_t*)(C))[0]; \
|
||||
*B = ((uint64_t*)(C))[1]; \
|
||||
} while (0)
|
||||
#define native_lock_write_dq(A, B, C) rv64_lock_cas_dq(C, A, tmpcas, B);
|
||||
#define native_lock_get_b(A) rv64_lock_get_b(A)
|
||||
#define native_lock_get_d(A) rv64_lock_get_d(A)
|
||||
#define native_lock_get_dd(A) rv64_lock_get_dd(A)
|
||||
|
||||
#elif defined(LA64)
|
||||
#include "la64/la64_lock.h"
|
||||
|
||||
#define USE_CAS
|
||||
// LA64 is quite strict (or at least strongly recommand) on what you can do between an LL and an SC
|
||||
// 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
|
||||
|
||||
#define native_lock_xchg_dd(A, B) la64_lock_xchg_dd(A, B)
|
||||
#define native_lock_xchg_d(A, B) la64_lock_xchg_d(A, B)
|
||||
#define native_lock_storeifref(A, B, C) la64_lock_storeifref(A, B, C)
|
||||
#define native_lock_storeifref_d(A, B, C) la64_lock_storeifref_d(A, B, C)
|
||||
#define native_lock_storeifref2_d(A, B, C) la64_lock_storeifref2_d(A, B, C)
|
||||
#define native_lock_storeifnull(A, B) la64_lock_storeifnull(A, B)
|
||||
#define native_lock_storeifnull_d(A, B) la64_lock_storeifnull_d(A, B)
|
||||
// #define native_lock_decifnot0b(A) la64_lock_decifnot0b(A)
|
||||
#define native_lock_storeb(A, B) la64_lock_storeb(A, B)
|
||||
#define native_lock_incif0(A) la64_lock_incif0(A)
|
||||
#define native_lock_decifnot0(A) la64_lock_decifnot0(A)
|
||||
#define native_lock_store(A, B) la64_lock_store(A, B)
|
||||
#define native_lock_store_dd(A, B) la64_lock_store_dd(A, B)
|
||||
#define native_lock_cas_d(A, B, C) la64_lock_cas_d(A, B, C)
|
||||
#define native_lock_cas_dd(A, B, C) la64_lock_cas_dd(A, B, C)
|
||||
#define native_lock_xchg_b(A, B) \
|
||||
la64_lam_bh ? la64_lock_xchg_b(A, B) : la64_lock_xchg_b_slow(A, B)
|
||||
#define native_lock_read_b(A) tmpcas=*(uint8_t*)(A)
|
||||
#define native_lock_write_b(A, B) \
|
||||
la64_lamcas ? la64_lock_cas_b(A, tmpcas, B) : la64_lock_cas_b_slow(A, tmpcas, B)
|
||||
#define native_lock_read_h(A) tmpcas=*(uint16_t*)(A)
|
||||
#define native_lock_write_h(A, B) \
|
||||
la64_lamcas ? la64_lock_cas_h(A, tmpcas, B) : la64_lock_cas_h_slow(A, tmpcas, B)
|
||||
#define native_lock_read_d(A) tmpcas=*(uint32_t*)(A)
|
||||
#define native_lock_write_d(A, B) la64_lock_cas_d(A, tmpcas, B)
|
||||
#define native_lock_read_dd(A) tmpcas=*(uint64_t*)(A)
|
||||
#define native_lock_write_dd(A, B) la64_lock_cas_dd(A, tmpcas, B)
|
||||
#define native_lock_read_dq(A, B, C) \
|
||||
do { \
|
||||
*A = tmpcas = ((uint64_t*)(C))[0]; \
|
||||
*B = ((uint64_t*)(C))[1]; \
|
||||
} while (0)
|
||||
#define native_lock_write_dq(A, B, C) la64_lock_cas_dq(C, A, tmpcas, B);
|
||||
#define native_lock_get_b(A) la64_lock_get_b(A)
|
||||
#define native_lock_get_d(A) la64_lock_get_d(A)
|
||||
#define native_lock_get_dd(A) la64_lock_get_dd(A)
|
||||
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
#endif //#define __NATIVE_LOCK__H__
|
||||
#endif //#define __NATIVE_LOCK__H__
|
||||
@@ -100,6 +100,25 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
i64 = F32S;
|
||||
emit_add32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x06:
|
||||
if (rex.is32bits) {
|
||||
INST_NAME("PUSH ES");
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
PUSH1_32(x1);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
if (rex.is32bits) {
|
||||
INST_NAME("POP ES");
|
||||
POP1_32(x1);
|
||||
SH(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("OR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -118,7 +137,6 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x0A:
|
||||
INST_NAME("OR Gb, Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -224,6 +242,27 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOV64xw(x1, i64);
|
||||
emit_adc32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x16:
|
||||
if (rex.is32bits) {
|
||||
INST_NAME("PUSH SS");
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
PUSH1_32(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
if (rex.is32bits) {
|
||||
INST_NAME("POP SS");
|
||||
SMREAD();
|
||||
POP1_32(x1);
|
||||
SH(x1, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
INST_NAME("SBB Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
@@ -281,7 +320,27 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOV64xw(x2, i64);
|
||||
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x1E:
|
||||
if (rex.is32bits) {
|
||||
INST_NAME("PUSH DS");
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
PUSH1_32(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x1F:
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POP DS");
|
||||
SMREAD();
|
||||
POP1_32(x1);
|
||||
SH(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
INST_NAME("AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -434,6 +493,9 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
i64 = F32S;
|
||||
emit_xor32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
case 0x36:
|
||||
INST_NAME("SS:");
|
||||
break;
|
||||
case 0x38:
|
||||
INST_NAME("CMP Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
|
||||
@@ -266,7 +266,7 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x6C:
|
||||
case 0x6D:
|
||||
INST_NAME(opcode == 0x6C ? "INSB" : "INSD");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_priv, -1);
|
||||
@@ -278,7 +278,7 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x6E:
|
||||
case 0x6F:
|
||||
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSD");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_priv, -1);
|
||||
@@ -289,6 +289,7 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
READFLAGS(F); \
|
||||
i8 = F8S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
@@ -302,7 +303,7 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
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); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
|
||||
@@ -491,10 +491,10 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
POP1z(xFlags);
|
||||
FLAGS_ADJUST_FROM11(xFlags, x2);
|
||||
FLAGS_ADJUST_FROM11(xFlags, xFlags, x2);
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
AND(xFlags, xFlags, x1);
|
||||
ORI(xFlags, xFlags, 0x2);
|
||||
ORI(xFlags, xFlags, 0x202);
|
||||
SET_DFNONE();
|
||||
if(box64_wine) { // should this be done all the time?
|
||||
ANDI(x1, xFlags, 1 << F_TF);
|
||||
@@ -590,16 +590,16 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LDxw(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, rex.w?8:4);
|
||||
SDxw(x1, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, rex.w?8:4);
|
||||
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(xRSI, xRSI, rex.w?8:4);
|
||||
SUBI(xRDI, xRDI, rex.w?8:4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
@@ -625,8 +625,8 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LBU(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, 1);
|
||||
LBU(x2, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, 1);
|
||||
ADDI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
@@ -634,8 +634,8 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LBU(x1, xRSI, 0);
|
||||
SUBI(xRSI, xRSI, 1);
|
||||
LBU(x2, xRDI, 0);
|
||||
SUBI(xRSI, xRSI, 1);
|
||||
SUBI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep==1) {BEQ_MARK3(x1, x2);} else {BNE_MARK3(x1, x2);}
|
||||
@@ -667,8 +667,8 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LDxw(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, rex.w ? 8 : 4);
|
||||
LDxw(x2, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, rex.w ? 8 : 4);
|
||||
ADDI(xRDI, xRDI, rex.w ? 8 : 4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep == 1) { BEQ_MARK3(x1, x2); } else { BNE_MARK3(x1, x2); }
|
||||
@@ -676,8 +676,8 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDxw(x1, xRSI, 0);
|
||||
SUBI(xRSI, xRSI, rex.w ? 8 : 4);
|
||||
LDxw(x2, xRDI, 0);
|
||||
SUBI(xRSI, xRSI, rex.w ? 8 : 4);
|
||||
SUBI(xRDI, xRDI, rex.w ? 8 : 4);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep == 1) { BEQ_MARK3(x1, x2); } else { BNE_MARK3(x1, x2); }
|
||||
|
||||
@@ -59,7 +59,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0:
|
||||
INST_NAME("ROL Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -69,70 +69,76 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 1:
|
||||
INST_NAME("ROR Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcl8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcr8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Eb, Ib");
|
||||
GETEB(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF{
|
||||
MOV32w(x4, u8); UFLAG_OP2(x4);
|
||||
};
|
||||
UFLAG_OP1(ed);
|
||||
SLLIW(ed, ed, u8);
|
||||
EBBACK(x5, 1);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl8);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_shl8c(dyn, ninst, ed, u8, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
} else {
|
||||
NOP();
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Eb, Ib");
|
||||
GETEB(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF{
|
||||
MOV32w(x4, u8); UFLAG_OP2(x4);
|
||||
};
|
||||
UFLAG_OP1(ed);
|
||||
if(u8) {
|
||||
SRLIW(ed, ed, u8);
|
||||
EBBACK(x5, 1);
|
||||
}
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr8);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_shr8c(dyn, ninst, ed, u8, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
} else {
|
||||
NOP();
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Eb, Ib");
|
||||
GETSEB(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF{
|
||||
MOV32w(x4, u8); UFLAG_OP2(x4);
|
||||
};
|
||||
UFLAG_OP1(ed);
|
||||
if(u8) {
|
||||
SRAIW(ed, ed, u8);
|
||||
EBBACK(x5, 1);
|
||||
}
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar8);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETSEB(x1, 1);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_sar8c(dyn, ninst, ed, u8, x4, x5, x6);
|
||||
EBBACK(x5, 0);
|
||||
} else {
|
||||
NOP();
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -144,46 +150,126 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
// flags are not affected if count is 0, we make it a nop if possible.
|
||||
if (u8) {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET_PENDING);
|
||||
GETED(1);
|
||||
F8;
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
if (MODREG && !rex.w) {
|
||||
GETED(1);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
FAKEED;
|
||||
}
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED(1);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
// flags are not affected if count is 0, we make it a nop if possible.
|
||||
if (u8) {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET_PENDING);
|
||||
GETED(1);
|
||||
F8;
|
||||
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
if (MODREG && !rex.w) {
|
||||
GETED(1);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
FAKEED;
|
||||
}
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
MOV32w(x2, u8);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
MOV32w(x2, u8);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4, x5);
|
||||
if(u8) WBACK;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
// flags are not affected if count is 0, we make it a nop if possible.
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
F8;
|
||||
emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4, x5);
|
||||
WBACK;
|
||||
} else {
|
||||
if (MODREG && !rex.w) {
|
||||
GETED(1);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
FAKEED;
|
||||
}
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
// flags are not affected if count is 0, we make it a nop if possible.
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
F8;
|
||||
emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
if (MODREG && !rex.w) {
|
||||
GETED(1);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
FAKEED;
|
||||
}
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
if(u8) { WBACK; }
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
// flags are not affected if count is 0, we make it a nop if possible.
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
F8;
|
||||
emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
if (MODREG && !rex.w) {
|
||||
GETED(1);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
FAKEED;
|
||||
}
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -191,11 +277,11 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("RETN");
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
//SETFLAGS(X_ALL, SF_SET_NODF); // Hack, set all flags (to an unknown state...)
|
||||
if(box64_dynarec_safeflags) {
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ninst, rex, i32);
|
||||
*need_epilog = 0;
|
||||
@@ -203,11 +289,11 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0xC3:
|
||||
INST_NAME("RET");
|
||||
// SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
// SETFLAGS(X_ALL, SF_SET_NODF); // Hack, set all flags (to an unknown state...)
|
||||
if(box64_dynarec_safeflags) {
|
||||
READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
|
||||
ret_to_epilog(dyn, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -285,7 +371,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
|
||||
case 0xCC:
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack, set all flags (to an unknown state...)
|
||||
SKIPTEST(x1);
|
||||
if(PK(0)=='S' && PK(1)=='C') {
|
||||
addr+=2;
|
||||
@@ -305,14 +391,13 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", GetNativeName(GetNativeFnc(ip)));
|
||||
x87_forget(dyn, ninst, x3, x4, 0);
|
||||
sse_purge07cache(dyn, ninst, x3);
|
||||
// disabling isSimpleWrapper because all signed value less than 64bits needs to be sign extended
|
||||
// and return value needs to be cleanned up
|
||||
tmp = 0;//isSimpleWrapper(*(wrapper_t*)(addr));
|
||||
// Partially support isSimpleWrapper
|
||||
tmp = isSimpleWrapper(*(wrapper_t*)(addr));
|
||||
if(isRetX87Wrapper(*(wrapper_t*)(addr)))
|
||||
// return value will be on the stack, so the stack depth needs to be updated
|
||||
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
|
||||
if(tmp<0 || tmp>1)
|
||||
tmp=0; //TODO: removed when FP is in place
|
||||
if (tmp < 0 || tmp > 1)
|
||||
tmp = 0; // TODO: removed when FP is in place
|
||||
if((box64_log<2 && !cycle_log) && tmp) {
|
||||
//GETIP(ip+3+8+8); // read the 0xCC
|
||||
call_n(dyn, ninst, *(void**)(addr+8), tmp);
|
||||
@@ -333,28 +418,33 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if 1
|
||||
INST_NAME("INT 3");
|
||||
// check if TRAP signal is handled
|
||||
LD(x1, xEmu, offsetof(x64emu_t, context));
|
||||
MOV64x(x2, offsetof(box64context_t, signals[SIGTRAP]));
|
||||
ADD(x2, x2, x1);
|
||||
LD(x3, x2, 0);
|
||||
CBNZ_NEXT(x3);
|
||||
MOV64x(x1, SIGTRAP);
|
||||
CALL_(raise, -1, 0);
|
||||
if(!box64_ignoreint3) {
|
||||
INST_NAME("INT 3");
|
||||
// check if TRAP signal is handled
|
||||
LD(x1, xEmu, offsetof(x64emu_t, context));
|
||||
MOV64x(x2, offsetof(box64context_t, signals[SIGTRAP]));
|
||||
ADD(x2, x2, x1);
|
||||
LD(x3, x2, 0);
|
||||
CBZ_NEXT(x3);
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_int3, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
}
|
||||
break;
|
||||
#else
|
||||
DEFAULT;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0xCD:
|
||||
u8 = F8;
|
||||
if (box64_wine && u8 == 0x2D) {
|
||||
INST_NAME("INT 2D");
|
||||
if (box64_wine && (u8==0x2D || u8==0x2C || u8==0x29)) {
|
||||
INST_NAME("INT 29/2c/2d");
|
||||
// lets do nothing
|
||||
MESSAGE(LOG_INFO, "INT 2D Windows anti-debug hack\n");
|
||||
MESSAGE(LOG_INFO, "INT 29/2c/2d Windows interruption\n");
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
MOV32w(x1, u8);
|
||||
CALL(native_int, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
} else if (u8 == 0x80) {
|
||||
INST_NAME("32bits SYSCALL");
|
||||
NOTEST(x1);
|
||||
@@ -372,7 +462,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
} else {
|
||||
INST_NAME("INT n");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_priv, -1);
|
||||
@@ -384,7 +474,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0xCF:
|
||||
INST_NAME("IRET");
|
||||
SETFLAGS(X_ALL, SF_SET); // Not a hack, EFLAGS are restored
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Not a hack, EFLAGS are restored
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
iret_to_epilog(dyn, ninst, rex.w);
|
||||
*need_epilog = 0;
|
||||
@@ -400,17 +490,13 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Eb, CL");
|
||||
ANDI(x2, xRCX, 7);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_PENDING);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 0);
|
||||
UFLAG_OP12(ed, x2);
|
||||
SLL(x3, ed, x2);
|
||||
SRLI(x4, x3, 8);
|
||||
OR(ed, x3, x4);
|
||||
EBBACK(x5, 1);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_rol8);
|
||||
CALL_(rol8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD0) {
|
||||
@@ -418,18 +504,43 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Eb, CL");
|
||||
ANDI(x2, xRCX, 7);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_PENDING);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 0);
|
||||
UFLAG_OP12(ed, x2);
|
||||
SRL(x3, ed, x2);
|
||||
SLLI(x4, ed, 8);
|
||||
SRL(x4, x4, x2);
|
||||
OR(ed, x3, x4);
|
||||
EBBACK(x5, 1);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_ror8);
|
||||
CALL_(ror8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("RCL Eb, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("RCL Eb, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 0);
|
||||
CALL_(rcl8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("RCR Eb, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("RCR Eb, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEB(x1, 0);
|
||||
CALL_(rcr8, ed, x3);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -438,47 +549,47 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Eb, CL");
|
||||
ANDI(x2, xRCX, 7);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETEB(x1, 0);
|
||||
UFLAG_OP12(ed, x2)
|
||||
SLL(ed, ed, x2);
|
||||
EBBACK(x5, 1);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl8);
|
||||
emit_shl8(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("SHR Eb, 1");
|
||||
MOV32w(x4, 1);
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Eb, CL");
|
||||
ANDI(x4, xRCX, 0x1F);
|
||||
ANDI(x2, xRCX, 0x1F);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETEB(x1, 0);
|
||||
UFLAG_OP12(ed, x4);
|
||||
SRLW(ed, ed, x4);
|
||||
EBBACK(x5, 1);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr8);
|
||||
emit_shr8(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("SAR Eb, 1");
|
||||
MOV32w(x4, 1);
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Eb, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETSEB(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
SRA(ed, ed, x4);
|
||||
EBBACK(x3, 1);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar8);
|
||||
emit_sar8(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EBBACK(x5, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -507,21 +618,23 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE("LOG_DUMP", "Need optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOV32w(x2, 1);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w ? ((void*)rcl64) : ((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOV32w(x2, 1);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -569,6 +682,28 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE("LOG_DUMP", "Need optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDI(x2, xRCX, rex.w?0x3f:0x1f);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w ? ((void*)rcl64) : ((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDI(x2, xRCX, rex.w?0x3f:0x1f);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, CL");
|
||||
@@ -603,11 +738,17 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, rex.w?d_sar64:d_sar32);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD7:
|
||||
INST_NAME("XLAT");
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
ADD(x1, xRBX, x1);
|
||||
LBU(x1, x1, 0);
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x1);
|
||||
break;
|
||||
case 0xD8:
|
||||
addr = dynarec64_D8(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
@@ -644,7 +785,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
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); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
@@ -704,7 +845,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
#endif
|
||||
switch(tmp) {
|
||||
case 3:
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state
|
||||
SKIPTEST(x1);
|
||||
BARRIER(BARRIER_FULL);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
@@ -718,13 +859,12 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// calling a native function
|
||||
sse_purge07cache(dyn, ninst, x3);
|
||||
if((box64_log<2 && !cycle_log) && dyn->insts[ninst].natcall) {
|
||||
// disabling isSimpleWrapper because all signed value less than 64bits needs to be sign extended
|
||||
// and return value needs to be cleanned up
|
||||
tmp=0;//isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2));
|
||||
if(tmp>1 || tmp<0)
|
||||
tmp=0; // float paramters not ready!
|
||||
// Partially support isSimpleWrapper
|
||||
tmp = isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall + 2));
|
||||
} else
|
||||
tmp=0;
|
||||
if (tmp < 0 || tmp > 1)
|
||||
tmp = 0; // TODO: removed when FP is in place
|
||||
if(dyn->insts[ninst].natcall && isRetX87Wrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2)))
|
||||
// return value will be on the stack, so the stack depth needs to be updated
|
||||
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
|
||||
@@ -764,49 +904,54 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if((box64_dynarec_safeflags>1) || (ninst && dyn->insts[ninst-1].x64.set_flags)) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
/*if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
}*/
|
||||
|
||||
if(rex.is32bits) {
|
||||
MOV32w(x2, addr);
|
||||
} else {
|
||||
TABLE64(x2, addr);
|
||||
}
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x3, x4);
|
||||
PUSH1z(x2);
|
||||
// TODO: Add support for CALLRET optim
|
||||
/*if(box64_dynarec_callret) {
|
||||
if(box64_dynarec_callret) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
AUIPC(x4, ((j64 + 0x800) >> 12) & 0xfffff);
|
||||
ADDI(x4, x4, j64 & 0xfff);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDR(x4, x4, 0);
|
||||
LD(x4, x4, 0);
|
||||
}
|
||||
PUSH1(x4);
|
||||
PUSH1(x2);
|
||||
} else */ //CALLRET optim disable for now.
|
||||
{
|
||||
ADDI(xSP, xSP, -16);
|
||||
SD(x4, xSP, 0);
|
||||
SD(x2, xSP, 8);
|
||||
} else {
|
||||
*ok = 0;
|
||||
*need_epilog = 0;
|
||||
}
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
jump_to_next(dyn, addr+i32, 0, ninst, rex.is32bits);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
BARRIER(BARRIER_MAYBE);
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); }
|
||||
if(opcode==0xE9) {
|
||||
INST_NAME("JMP Id");
|
||||
i32 = F32S;
|
||||
@@ -818,7 +963,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) {
|
||||
// out of the block
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
|
||||
jump_to_next(dyn, (uintptr_t)getAlternate((void*)(addr+i32)), 0, ninst);
|
||||
jump_to_next(dyn, (uintptr_t)getAlternate((void*)(addr+i32)), 0, ninst, rex.is32bits);
|
||||
} else {
|
||||
// inside the block
|
||||
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
|
||||
@@ -897,7 +1042,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 6:
|
||||
INST_NAME("DIV Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEB(x1, 0);
|
||||
CALL(div8, -1);
|
||||
break;
|
||||
@@ -905,12 +1050,10 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("IDIV Eb");
|
||||
SKIPTEST(x1);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEB(x1, 0);
|
||||
CALL(idiv8, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
@@ -984,32 +1127,73 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
if(!rex.w) {
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
SLLI(x3, xRDX, 32);
|
||||
AND(x2, xRAX, xMASK);
|
||||
OR(x3, x3, x2);
|
||||
if(MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ed = x4;
|
||||
if(ninst && (nextop==0xF0)
|
||||
&& dyn->insts[ninst-1].x64.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0xB8
|
||||
&& *(uint32_t*)(dyn->insts[ninst-1].x64.addr+1)==0) {
|
||||
// hack for some protection that check a divide by zero actualy trigger a divide by zero exception
|
||||
MESSAGE(LOG_INFO, "Divide by 0 hack\n");
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
} else {
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
SLLI(x3, xRDX, 32);
|
||||
AND(x2, xRAX, xMASK);
|
||||
OR(x3, x3, x2);
|
||||
if(MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ed = x4;
|
||||
}
|
||||
DIVU(x2, x3, ed);
|
||||
REMU(xRDX, x3, ed);
|
||||
AND(xRAX, x2, xMASK);
|
||||
ZEROUP(xRDX);
|
||||
}
|
||||
DIVU(x2, x3, ed);
|
||||
REMU(xRDX, x3, ed);
|
||||
AND(xRAX, x2, xMASK);
|
||||
ZEROUP(xRDX);
|
||||
} else {
|
||||
if(ninst
|
||||
&& 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();
|
||||
GETED(0);
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
DIVU(x2, xRAX, ed);
|
||||
REMU(xRDX, xRAX, ed);
|
||||
MV(xRAX, x2);
|
||||
} else {
|
||||
GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
BEQ_MARK(xRDX, xZR);
|
||||
if(ed!=x1) {MV(x1, ed);}
|
||||
CALL(div64, -1);
|
||||
@@ -1018,7 +1202,6 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
DIVU(x2, xRAX, ed);
|
||||
REMU(xRDX, xRAX, ed);
|
||||
MV(xRAX, x2);
|
||||
SET_DFNONE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1026,9 +1209,19 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("IDIV Ed");
|
||||
SKIPTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE()
|
||||
if(!rex.w) {
|
||||
SET_DFNONE()
|
||||
GETSED(0);
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
SLLI(x3, xRDX, 32);
|
||||
AND(x2, xRAX, xMASK);
|
||||
OR(x3, x3, x2);
|
||||
@@ -1041,13 +1234,32 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
&& 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()
|
||||
GETED(0);
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
DIV(x2, xRAX, ed);
|
||||
REM(xRDX, xRAX, ed);
|
||||
MV(xRAX, x2);
|
||||
} else {
|
||||
GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
//Need to see if RDX==0 and RAX not signed
|
||||
// or RDX==-1 and RAX signed
|
||||
BNE_MARK2(xRDX, xZR);
|
||||
@@ -1064,7 +1276,6 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
DIV(x2, xRAX, ed);
|
||||
REM(xRDX, xRAX, ed);
|
||||
MV(xRAX, x2);
|
||||
SET_DFNONE()
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1139,7 +1350,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDz(0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
@@ -1150,29 +1361,34 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
// TODO: Add suport for CALLRET optim
|
||||
/*if(box64_dynarec_callret) {
|
||||
if(box64_dynarec_callret) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
AUIPC(x4, ((j64 + 0x800) >> 12) & 0xfffff);
|
||||
ADDI(x4, x4, j64 & 0xfff);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
LD(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}*/
|
||||
ADDI(xSP, xSP, -16);
|
||||
SD(x4, xSP, 0);
|
||||
SD(xRIP, xSP, 8);
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETEDz(0);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
#include "bitutils.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
@@ -32,8 +33,9 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb2, gback;
|
||||
uint8_t wb1, wback, wb2, gback;
|
||||
uint8_t eb1, eb2;
|
||||
uint8_t gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
@@ -59,19 +61,49 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch (opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
// TODO:, /0 is SGDT. While 0F 01 D0 is XGETBV, etc...
|
||||
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(x3);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
if(MODREG) {
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
nextop = F8;
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0xF9:
|
||||
INST_NAME("RDTSCP");
|
||||
NOTEST(x1);
|
||||
if (box64_rdtsc) {
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
} else {
|
||||
CSRRS(x3, xZR, 0xC01); // RDTIME
|
||||
}
|
||||
if(box64_rdtsc_shift) {
|
||||
SRLI(x3, x3, box64_rdtsc_shift);
|
||||
}
|
||||
SRLI(xRDX, x3, 32);
|
||||
AND(xRAX, x3, xMASK); // wipe upper part
|
||||
MV(xRCX, xZR); // IA32_TSC, 0 for now
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
} else {
|
||||
switch((nextop>>3)&7) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("SYSCALL");
|
||||
NOTEST(x1);
|
||||
@@ -91,7 +123,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("WBINVD");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_ud, -1);
|
||||
@@ -103,7 +135,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
case 0x0B:
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(x3);
|
||||
CALL(native_ud, -1);
|
||||
@@ -378,15 +410,97 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
if (box64_rdtsc) {
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
} else {
|
||||
CSRRS(x3, xZR, 0xC01); // RDTIME
|
||||
}
|
||||
if(box64_rdtsc_shift) {
|
||||
SRLI(x3, x3, box64_rdtsc_shift);
|
||||
}
|
||||
SRLI(xRDX, x3, 32);
|
||||
AND(xRAX, x3, 32); // wipe upper part
|
||||
AND(xRAX, x3, xMASK); // wipe upper part
|
||||
break;
|
||||
case 0x38:
|
||||
// SSE3
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0x00:
|
||||
INST_NAME("PSHUFB Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM();
|
||||
GETEM(x2, 0);
|
||||
LD(x4, gback, gdoffset);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LB(x3, wback, fixedaddress + i);
|
||||
BGE(x3, xZR, 4 + 4 * 2);
|
||||
SB(xZR, gback, gdoffset + i);
|
||||
J(4 + 4 * 4);
|
||||
ANDI(x3, x3, 0x7);
|
||||
SLLI(x3, x3, 3);
|
||||
SRL(x3, x4, x3);
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
case 0xC8 ... 0xCD:
|
||||
u8 = nextop;
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
INST_NAME("SHA1NEXTE Gx, Ex");
|
||||
break;
|
||||
case 0xC9:
|
||||
INST_NAME("SHA1MSG1 Gx, Ex");
|
||||
break;
|
||||
case 0xCA:
|
||||
INST_NAME("SHA1MSG2 Gx, Ex");
|
||||
break;
|
||||
case 0xCB:
|
||||
INST_NAME("SHA256RNDS2 Gx, Ex");
|
||||
break;
|
||||
case 0xCC:
|
||||
INST_NAME("SHA256MSG1 Gx, Ex");
|
||||
break;
|
||||
case 0xCD:
|
||||
INST_NAME("SHA256MSG2 Gx, Ex");
|
||||
break;
|
||||
}
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x2) {
|
||||
MV(x2, ed);
|
||||
}
|
||||
}
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDI(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
sse_reflect_reg(dyn, ninst, 0);
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
CALL(sha1nexte, -1);
|
||||
break;
|
||||
case 0xC9:
|
||||
CALL(sha1msg1, -1);
|
||||
break;
|
||||
case 0xCA:
|
||||
CALL(sha1msg2, -1);
|
||||
break;
|
||||
case 0xCB:
|
||||
CALL(sha256rnds2, -1);
|
||||
break;
|
||||
case 0xCC:
|
||||
CALL(sha256msg1, -1);
|
||||
break;
|
||||
case 0xCD:
|
||||
CALL(sha256msg2, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gd, Ed");
|
||||
nextop = F8;
|
||||
@@ -409,6 +523,32 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x3A: // more SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xCC:
|
||||
INST_NAME("SHA1RNDS4 Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (wback != x2) MV(x2, wback);
|
||||
}
|
||||
u8 = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDI(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
MOV32w(x3, u8);
|
||||
CALL(sha1rnds4, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
@@ -860,6 +1000,10 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGM();
|
||||
if (MODREG) {
|
||||
ed = xRAX + (nextop & 7) + (rex.b << 3);
|
||||
if (!rex.w) {
|
||||
AND(x4, ed, xMASK);
|
||||
ed = x4;
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
LDxw(x4, ed, fixedaddress);
|
||||
@@ -875,6 +1019,21 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LD(x3, wback, fixedaddress);
|
||||
SD(x3, gback, gdoffset + 0);
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFW Gm, Em, Ib");
|
||||
nextop = F8;
|
||||
GETGM();
|
||||
GETEM(x2, 1);
|
||||
u8 = F8;
|
||||
LHU(x3, wback, fixedaddress + ((u8 >> (0 * 2)) & 3) * 2);
|
||||
LHU(x4, wback, fixedaddress + ((u8 >> (1 * 2)) & 3) * 2);
|
||||
LHU(x5, wback, fixedaddress + ((u8 >> (2 * 2)) & 3) * 2);
|
||||
LHU(x6, wback, fixedaddress + ((u8 >> (3 * 2)) & 3) * 2);
|
||||
SH(x3, gback, gdoffset + 0 * 2);
|
||||
SH(x4, gback, gdoffset + 1 * 2);
|
||||
SH(x5, gback, gdoffset + 2 * 2);
|
||||
SH(x6, gback, gdoffset + 3 * 2);
|
||||
break;
|
||||
case 0x71:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
@@ -1055,6 +1214,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SD(x3, wback, fixedaddress);
|
||||
break;
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
@@ -1067,7 +1227,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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 + i32_, 0, ninst); \
|
||||
jump_to_next(dyn, addr + i32_, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
@@ -1150,7 +1310,21 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4, x5);
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
|
||||
BEQ_NEXT(x3, xZR);
|
||||
emit_shld32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xAB:
|
||||
@@ -1181,6 +1355,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if(!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xAC:
|
||||
@@ -1194,6 +1370,20 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if (box64_dynarec_safeflags > 1)
|
||||
MAYSETFLAGS();
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
|
||||
BEQ_NEXT(x3, xZR);
|
||||
emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if ((nextop & 0xF8) == 0xE8) {
|
||||
@@ -1262,6 +1452,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
// TODO: Refine this
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
@@ -1285,6 +1476,15 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
// 32bits imul
|
||||
UFLAG_IF
|
||||
{
|
||||
SLLI(gd, gd, 32);
|
||||
SRAI(gd, gd, 32);
|
||||
if(MODREG) {
|
||||
SLLI(x1, ed, 32);
|
||||
ed = x1;
|
||||
} else {
|
||||
SLLI(ed, ed, 32);
|
||||
}
|
||||
SRAI(ed, ed, 32);
|
||||
MUL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
SRLI(x3, gd, 32);
|
||||
@@ -1328,6 +1528,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if(!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xB6:
|
||||
@@ -1406,6 +1608,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if(!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
@@ -1433,6 +1637,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if(!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
@@ -1455,6 +1661,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if(!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1489,6 +1697,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if(!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
@@ -1506,18 +1716,8 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if (rv64_zbb) {
|
||||
CTZxw(gd, ed);
|
||||
} else {
|
||||
NEG(x2, ed);
|
||||
AND(x2, x2, ed);
|
||||
TABLE64(x3, 0x03f79d71b4ca8b09ULL);
|
||||
MUL(x2, x2, x3);
|
||||
SRLI(x2, x2, 64 - 6);
|
||||
TABLE64(x1, (uintptr_t)&deBruijn64tab);
|
||||
ADD(x1, x1, x2);
|
||||
LBU(gd, x1, 0);
|
||||
}
|
||||
// gd is undefined if ed is all zeros, don't worry.
|
||||
CTZxw(gd, ed, rex.w, x1, x2);
|
||||
ANDI(xFlags, xFlags, ~(1 << F_ZF));
|
||||
break;
|
||||
case 0xBD:
|
||||
@@ -1536,43 +1736,9 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
ANDI(xFlags, xFlags, ~(1 << F_ZF));
|
||||
if (rv64_zbb) {
|
||||
MOV32w(x1, rex.w ? 63 : 31);
|
||||
CLZxw(gd, ed);
|
||||
SUB(gd, x1, gd);
|
||||
} else {
|
||||
if (ed != gd)
|
||||
u8 = gd;
|
||||
else
|
||||
u8 = x1;
|
||||
ADDI(u8, xZR, 0);
|
||||
if (rex.w) {
|
||||
MV(x2, ed);
|
||||
SRLI(x3, x2, 32);
|
||||
BEQZ(x3, 4 + 2 * 4);
|
||||
ADDI(u8, u8, 32);
|
||||
MV(x2, x3);
|
||||
} else {
|
||||
AND(x2, ed, xMASK);
|
||||
}
|
||||
SRLI(x3, x2, 16);
|
||||
BEQZ(x3, 4 + 2 * 4);
|
||||
ADDI(u8, u8, 16);
|
||||
MV(x2, x3);
|
||||
SRLI(x3, x2, 8);
|
||||
BEQZ(x3, 4 + 2 * 4);
|
||||
ADDI(u8, u8, 8);
|
||||
MV(x2, x3);
|
||||
SRLI(x3, x2, 4);
|
||||
BEQZ(x3, 4 + 2 * 4);
|
||||
ADDI(u8, u8, 4);
|
||||
MV(x2, x3);
|
||||
ANDI(x2, x2, 0b1111);
|
||||
TABLE64(x3, (uintptr_t)&lead0tab);
|
||||
ADD(x3, x3, x2);
|
||||
LBU(x2, x3, 0);
|
||||
ADD(gd, u8, x2);
|
||||
}
|
||||
CLZxw(gd, ed, rex.w, x1, x2, x3);
|
||||
ADDI(x1, xZR, rex.w ? 63 : 31);
|
||||
SUB(gd, x1, gd);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
@@ -1613,6 +1779,31 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (!rex.w)
|
||||
ZEROUP(gd);
|
||||
break;
|
||||
case 0xC0:
|
||||
INST_NAME("XADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
MV(x9, ed);
|
||||
emit_add8(dyn, ninst, ed, gd, x4, x5);
|
||||
MV(gd, x9);
|
||||
EBBACK(x5, 0);
|
||||
GBBACK(x5);
|
||||
break;
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(ed!=gd)
|
||||
MV(x9, ed);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x4, x5, x6);
|
||||
if(ed!=gd)
|
||||
MVxw(gd, x9);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -1637,11 +1828,11 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
switch (u8 & 7) {
|
||||
case 1:
|
||||
BEQ_MARK(x3, xZR);
|
||||
BEQ(x3, xZR, 8); // MARK2
|
||||
FLTS(x3, d0, d1);
|
||||
break; // Less than
|
||||
case 2:
|
||||
BEQ_MARK(x3, xZR);
|
||||
BEQ(x3, xZR, 8); // MARK2
|
||||
FLES(x3, d0, d1);
|
||||
break; // Less or equal
|
||||
case 3: XORI(x3, x3, 1); break; // NaN
|
||||
@@ -1711,7 +1902,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* BSWAP reg */
|
||||
case 0xCF:
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = xRAX + (opcode & 7) + (rex.b << 3);
|
||||
REV8xw(gd, gd, x1, x2, x3, x4);
|
||||
@@ -1740,6 +1931,25 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
AND(x1, x1, x2);
|
||||
SD(x1, gback, gdoffset);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("PSRAD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM();
|
||||
GETEM(x4, 0);
|
||||
LBU(x1, wback, fixedaddress);
|
||||
ADDI(x2, xZR, 31);
|
||||
if (rv64_zbb) {
|
||||
MINU(x1, x1, x2);
|
||||
} else {
|
||||
BLTU(x1, x2, 4 + 4);
|
||||
MV(x1, x2);
|
||||
}
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
LW(x3, gback, gdoffset + 4 * i);
|
||||
SRAW(x3, x3, x1);
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("PMULHW Gm,Em");
|
||||
nextop = F8;
|
||||
@@ -1753,24 +1963,6 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
}
|
||||
break;
|
||||
INST_NAME("PSUBSW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM();
|
||||
GETEM(x2, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LH(x3, gback, gdoffset + i * 2);
|
||||
LH(x4, wback, fixedaddress);
|
||||
SUBW(x3, x3, x4);
|
||||
LUI(x4, 0xFFFF8); // -32768
|
||||
BGE(x3, x4, 12);
|
||||
SH(x4, gback, gdoffset + i * 2);
|
||||
J(20); // continue
|
||||
LUI(x4, 8); // 32768
|
||||
BLT(x3, x4, 8);
|
||||
ADDIW(x3, x4, -1);
|
||||
SH(x4, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTQ Em, Gm");
|
||||
nextop = F8;
|
||||
|
||||
+319
-190
@@ -8,6 +8,7 @@
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "rv64_emitter.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -82,9 +83,18 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0x06:
|
||||
INST_NAME("PUSH ES");
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
PUSH1_16(x1);
|
||||
break;
|
||||
case 0x07:
|
||||
INST_NAME("POP ES");
|
||||
POP1_16(x1);
|
||||
SH(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
@@ -111,9 +121,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0x0F:
|
||||
switch(rep) {
|
||||
@@ -147,17 +155,10 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i16 = F16;
|
||||
SRLI(x6, xMASK, 16);
|
||||
AND(x1, xRAX, x6);
|
||||
ZEXTH(x1, xRAX);
|
||||
MOV32w(x2, i16);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
if (rv64_zbb) {
|
||||
ANDN(xRAX, xRAX, x6);
|
||||
} else {
|
||||
NOT(x6, x6);
|
||||
AND(xRAX, xRAX, x6);
|
||||
}
|
||||
OR(xRAX, xRAX, x1);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
@@ -179,6 +180,27 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ZEXTH(x1, xRAX);
|
||||
i16 = F16;
|
||||
MOV64xw(x2, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PUSH DS");
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
PUSH1_16(x1);
|
||||
break;
|
||||
case 0x1F:
|
||||
INST_NAME("POP DS");
|
||||
POP1_16(x1);
|
||||
SH(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -204,9 +226,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
@@ -233,27 +253,79 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
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;
|
||||
// try to determine ed and gd
|
||||
ed = 0;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
GETED(0);
|
||||
}
|
||||
if (ed == gd) {
|
||||
// optimize XOR Gw, Gw
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(x6, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
SRLI(ed, ed, 16);
|
||||
SLLI(ed, ed, 16);
|
||||
IFX(X_PEND) {
|
||||
SH(ed, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
// try to determine ed and gd
|
||||
ed = 0;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
GETED(0);
|
||||
}
|
||||
if (ed == gd) {
|
||||
// optimize XOR Gw, Gw
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
SET_DF(x6, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
SRLI(ed, ed, 16);
|
||||
SLLI(ed, ed, 16);
|
||||
IFX(X_PEND) {
|
||||
SH(ed, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
} else {
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
GWBACK;
|
||||
}
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
@@ -262,9 +334,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
@@ -475,14 +545,9 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(MODREG) {
|
||||
GETGD;
|
||||
GETED(0);
|
||||
ADDI(x1, gd, 0);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(gd, gd, x3);
|
||||
ZEXTH(x4, ed);
|
||||
OR(gd, gd, x4);
|
||||
AND(ed, ed, x3);
|
||||
ZEXTH(x4, x1);
|
||||
OR(ed, ed, x4);
|
||||
MV(x1, gd);
|
||||
INSH(gd, ed, x3, x4, 1, 1);
|
||||
INSH(ed, x1, x3, x4, 0, 1);
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -509,11 +574,13 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
NOT(x5, x5);
|
||||
SLLI(x5, x5, 16);
|
||||
SLLI(x6, x6, 16);
|
||||
// 0xffffffff0000ffff
|
||||
NOT(x5, x5);
|
||||
LR_W(x1, ed, 1, 0);
|
||||
ANDI(x4, ed, ~0b11);
|
||||
LR_W(x1, x4, 1, 0);
|
||||
AND(x3, x1, x5);
|
||||
OR(x3, x3, x6);
|
||||
SC_W(x3, x3, ed, 0, 1);
|
||||
SC_W(x3, x3, x4, 0, 1);
|
||||
BNEZ(x3, -4 * 4);
|
||||
SRLI(x1, x1, 16);
|
||||
ZEXTH(x1, x1);
|
||||
@@ -525,9 +592,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
MARK2;
|
||||
SMDMB();
|
||||
LUI(x5, 0xffff0);
|
||||
AND(gd, gd, x5);
|
||||
OR(gd, gd, x1);
|
||||
INSH(gd, x1, x3, x4, 1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
@@ -536,12 +601,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
if (ed != gd) {
|
||||
INSH(ed, gd, x2, x3, 1, 1);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
@@ -555,19 +616,26 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
if (ed != gd) {
|
||||
INSH(gd, ed, x2, x3, 1, 1);
|
||||
}
|
||||
} 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);
|
||||
INSH(gd, x1, x2, x3, 1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x8C:
|
||||
INST_NAME("MOV Ed, Seg");
|
||||
nextop = F8;
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, segs[(nextop & 0x38) >> 3]));
|
||||
if ((nextop & 0xC0) == 0xC0) { // reg <= seg
|
||||
INSH(xRAX + (nextop & 7) + (rex.b << 3), x3, x1, x2, 1, 0);
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SH(x3, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
@@ -583,29 +651,51 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
INSH(xRAX, gd, x3, x4, 1, 1);
|
||||
INSH(gd, x2, x3, x4, 0, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x98:
|
||||
INST_NAME("CBW");
|
||||
SLLI(x1, xRAX, 56);
|
||||
SRAI(x1, x1, 56);
|
||||
INSH(xRAX, x1, x2, x3, 1, 1);
|
||||
break;
|
||||
case 0x99:
|
||||
INST_NAME("CWD");
|
||||
SLLI(x1, xRAX, 48);
|
||||
SRAI(x1, x1, 48);
|
||||
SRLI(x1, x1, 48);
|
||||
SRLI(xRDX, xRDX, 16);
|
||||
SLLI(xRDX, xRDX, 16);
|
||||
OR(xRDX, xRDX, x1);
|
||||
break;
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
NOTEST(x1);
|
||||
READFLAGS(X_ALL);
|
||||
FLAGS_ADJUST_TO11(x3, xFlags, x2);
|
||||
PUSH1_16(x3);
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
POP1_16(x1);
|
||||
FLAGS_ADJUST_FROM11(x1, x1, x2);
|
||||
LUI(x2, 0xffff0);
|
||||
AND(xRAX, xRAX, x2);
|
||||
NOT(x2, x2);
|
||||
AND(x1, x1, x2);
|
||||
OR(xRAX, xRAX, x1);
|
||||
AND(xFlags, xFlags, x2);
|
||||
OR(xFlags, xFlags, x1);
|
||||
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);
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpretor only
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
@@ -614,9 +704,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (isLockAddress(u64)) lock = 1; else lock = 0;
|
||||
SMREADLOCK(lock);
|
||||
LHU(x2, x1, 0);
|
||||
LUI(x3, 0xffff0);
|
||||
AND(xRAX, xRAX, x3);
|
||||
OR(xRAX, xRAX, x2);
|
||||
INSH(xRAX, x2, x3, x4, 1, 0);
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
@@ -638,22 +726,22 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LH(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, 2);
|
||||
SH(x1, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, 2);
|
||||
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(xRSI, xRSI, 2);
|
||||
SUBI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSD");
|
||||
INST_NAME("MOVSW");
|
||||
GETDIR(x3, x1, 2);
|
||||
LH(x1, xRSI, 0);
|
||||
SH(x1, xRDI, 0);
|
||||
@@ -673,8 +761,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LHU(x1, xRSI, 0);
|
||||
ADDI(xRSI, xRSI, 2);
|
||||
LHU(x2, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, 2);
|
||||
ADDI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep == 1) { BEQ_MARK3(x1, x2); } else { BNE_MARK3(x1, x2); }
|
||||
@@ -682,8 +770,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
B_MARK3_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LHU(x1, xRSI, 0);
|
||||
SUBI(xRSI, xRSI, 2);
|
||||
LHU(x2, xRDI, 0);
|
||||
SUBI(xRSI, xRSI, 2);
|
||||
SUBI(xRDI, xRDI, 2);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
if (rep == 1) { BEQ_MARK3(x1, x2); } else { BNE_MARK3(x1, x2); }
|
||||
@@ -745,9 +833,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETDIR(x1, x2, 2);
|
||||
LHU(x2, xRSI, 0);
|
||||
ADD(xRSI, xRSI, x1);
|
||||
LUI(x1, 0xffff0);
|
||||
AND(xRAX, xRAX, x1);
|
||||
OR(xRAX, xRAX, x2);
|
||||
INSH(xRAX, x2, x3, x4, 1, 0);
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
@@ -786,13 +872,14 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETDIR(x3, x1, rex.w?8:2);
|
||||
if (rex.w) {
|
||||
LD(x2, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
ZEXTH(x1, xRAX);
|
||||
LHU(x2, xRDI, 0);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
}
|
||||
ADD(xRDI, xRDI, x3);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -806,21 +893,10 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
}
|
||||
}
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = xRAX + (opcode & 7) + (rex.b << 3);
|
||||
INSH(gd, x1, x2, x3, 1, 0);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
@@ -829,7 +905,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -839,7 +915,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -850,7 +926,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -861,7 +937,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -871,50 +947,42 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_shl16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
EWBACK;
|
||||
} else {
|
||||
SLLI(ed, ed, u8&0x1f);
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
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);
|
||||
INST_NAME("SHR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_shr16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
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);
|
||||
INST_NAME("SAR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETSEW(x1, 0);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_sar16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -923,13 +991,10 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
ed = xRAX + (nextop & 7) + (rex.b << 3);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
ORI(ed, ed, x1);
|
||||
INSH(ed, x1, x2, x3, 1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 2);
|
||||
u16 = F16;
|
||||
@@ -942,59 +1007,112 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROR Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("RCL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("RCL Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
MESSAGE("LOG_DUMP", "Need optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("RCR Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("RCR Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
}
|
||||
MESSAGE("LOG_DUMP", "Need optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1, 1);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
SRL(ed, ed, x4);
|
||||
emit_shr16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
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);
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
SLL(ed, ed, x4);
|
||||
ZEXTH(ed, ed);
|
||||
emit_shl16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
UFLAG_IF {MESSAGE(LOG_DUMP, "Need Optimization for flags\n");}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
GETSEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4);
|
||||
SRA(ed, ed, x4);
|
||||
ZEXTH(ed, ed);
|
||||
emit_sar16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -1019,7 +1137,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
NOT(ed, ed); // No flags affected
|
||||
MOV32w(x3, 0xffff);
|
||||
XOR(ed, ed, x3); // No flags affected
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -1032,41 +1151,51 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 0);
|
||||
ZEXTH(x2, xRAX);
|
||||
SLLI(x3, xRDX, 48);
|
||||
SRLI(x3, x3, 32);
|
||||
OR(x2, x2, x3);
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x6);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
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);
|
||||
INSH(xRAX, x3, x5, x6, 1, 1);
|
||||
INSH(xRDX, x4, x5, x6, 0, 1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
GETSEW(x1, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(x6);
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
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);
|
||||
INSH(xRAX, x3, x5, x6, 1, 1);
|
||||
INSH(xRDX, x4, x5, x6, 0, 1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "bitutils.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
|
||||
uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -36,7 +38,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int d0, d1, d2;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
|
||||
@@ -344,7 +346,36 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SW(x3, gback, gdoffset + 3 * 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("PHADDSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// tmp32s = GX->sw[i*2+0]+GX->sw[i*2+1];
|
||||
// GX->sw[i] = sat(tmp32s);
|
||||
LH(x3, gback, gdoffset + 2 * (i * 2 + 0));
|
||||
LH(x4, gback, gdoffset + 2 * (i * 2 + 1));
|
||||
ADDW(x3, x3, x4);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
}
|
||||
if (MODREG && gd == (nextop & 7) + (rex.b << 3)) {
|
||||
// GX->q[1] = GX->q[0];
|
||||
LD(x3, gback, gdoffset + 0);
|
||||
SD(x3, gback, gdoffset + 8);
|
||||
} else {
|
||||
GETEX(x2, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// tmp32s = EX->sw[i*2+0] + EX->sw[i*2+1];
|
||||
// GX->sw[4+i] = sat(tmp32s);
|
||||
LH(x3, wback, fixedaddress + 2 * (i * 2 + 0));
|
||||
LH(x4, wback, fixedaddress + 2 * (i * 2 + 1));
|
||||
ADDW(x3, x3, x4);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * (4 + i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PADDUBSW Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -372,7 +403,32 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("PHSUBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// GX->sw[i] = GX->sw[i*2+0] - GX->sw[i*2+1];
|
||||
LH(x3, gback, gdoffset + 2 * (i * 2 + 0));
|
||||
LH(x4, gback, gdoffset + 2 * (i * 2 + 1));
|
||||
SUBW(x3, x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
}
|
||||
if (MODREG && gd == (nextop & 7) + (rex.b << 3)) {
|
||||
// GX->q[1] = GX->q[0];
|
||||
LD(x3, gback, gdoffset + 0);
|
||||
SD(x3, gback, gdoffset + 8);
|
||||
} else {
|
||||
GETEX(x2, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// GX->sw[4+i] = EX->sw[i*2+0] - EX->sw[i*2+1];
|
||||
LH(x3, wback, fixedaddress + 2 * (i * 2 + 0));
|
||||
LH(x4, wback, fixedaddress + 2 * (i * 2 + 1));
|
||||
SUBW(x3, x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * (4 + i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("PSIGNB Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -447,6 +503,18 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// continue
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("PBLENDVPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LW(x3, xEmu, offsetof(x64emu_t, xmm[0]) + i * 4);
|
||||
BGE(x3, xZR, 4 + 4 * 2);
|
||||
LWU(x3, wback, fixedaddress + i * 4);
|
||||
SW(x3, gback, gdoffset + i * 4);
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("PTEST Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -522,7 +590,84 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SW(x4, gback, gdoffset + i * 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("PMOVSXBW Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
// GX->sw[i] = EX->sb[i];
|
||||
LB(x3, wback, fixedaddress + i);
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("PMOVSXBD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 3; i >= 0; --i) {
|
||||
// GX->sd[i] = EX->sb[i];
|
||||
LB(x3, wback, fixedaddress + i);
|
||||
SW(x3, gback, gdoffset + i * 4);
|
||||
}
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("PMOVSXBQ Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
// GX->sq[i] = EX->sb[i];
|
||||
LB(x3, wback, fixedaddress + i);
|
||||
SD(x3, gback, gdoffset + i * 8);
|
||||
}
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("PMOVSXWD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 3; i >= 0; --i) {
|
||||
// GX->sd[i] = EX->sw[i];
|
||||
LH(x3, wback, fixedaddress + i * 2);
|
||||
SW(x3, gback, gdoffset + i * 4);
|
||||
}
|
||||
break;
|
||||
case 0x24:
|
||||
INST_NAME("PMOVSXWQ Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
// GX->sq[i] = EX->sw[i];
|
||||
LH(x3, wback, fixedaddress + i * 2);
|
||||
SD(x3, gback, gdoffset + i * 8);
|
||||
}
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("PMOVSXDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
// GX->sq[i] = EX->sd[i];
|
||||
LW(x4, wback, fixedaddress + i * 4);
|
||||
SD(x4, gback, gdoffset + i * 8);
|
||||
}
|
||||
break;
|
||||
case 0x28:
|
||||
INST_NAME("PMULDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(x2, 0);
|
||||
GETGX();
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
LW(x3, wback, fixedaddress + i * 8);
|
||||
LW(x4, gback, gdoffset + i * 8);
|
||||
MUL(x3, x3, x4);
|
||||
SD(x3, gback, gdoffset + i * 8);
|
||||
}
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("PACKUSDW Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -754,6 +899,42 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SW(x3, gback, gdoffset + i * 4);
|
||||
}
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PCMPESTRI Gx, Ex, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
ADDI(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x1) {
|
||||
MV(x1, ed);
|
||||
}
|
||||
}
|
||||
// prepare rest arguments
|
||||
MV(x2, xRDX);
|
||||
MV(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
ZEROUP(x1);
|
||||
BNEZ_MARK(x1);
|
||||
MOV32w(xRCX, (u8 & 1) ? 8 : 16);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if (u8 & 0b1000000) {
|
||||
CLZxw(xRCX, x1, 0, x2, x3, x4);
|
||||
ADDI(x2, xZR, 31);
|
||||
SUB(xRCX, x2, xRCX);
|
||||
} else {
|
||||
CTZxw(xRCX, xRCX, 0, x1, x2);
|
||||
}
|
||||
break;
|
||||
case 0xDB:
|
||||
INST_NAME("AESIMC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
@@ -1073,6 +1254,29 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SW(ed, gback, gdoffset + 4 * (u8 & 0x3));
|
||||
}
|
||||
break;
|
||||
case 0x40:
|
||||
INST_NAME("DPPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d2 = fpu_get_scratch(dyn);
|
||||
FMVWX(d2, xZR);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
if (u8 & (1 << (i + 4))) {
|
||||
FLW(d0, gback, gdoffset + i * 4);
|
||||
FLW(d1, wback, fixedaddress + i * 4);
|
||||
FMULS(d0, d0, d1);
|
||||
FADDS(d2, d2, d0);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i)
|
||||
if (u8 & (1 << i))
|
||||
FSW(d2, gback, gdoffset + i * 4);
|
||||
else
|
||||
SW(xZR, gback, gdoffset + i * 4);
|
||||
break;
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -1276,8 +1480,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
FLW(d0, wback, fixedaddress + 4 * i);
|
||||
FCVTLS(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
SUB(x5, x5, x3);
|
||||
BEQZ(x5, 8);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000); // INT32_MIN
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
@@ -2002,6 +2205,54 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SSE_LOOP_MV_Q2(x3);
|
||||
if (!MODREG) SMWRITE2();
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
ANDI(gd, gd, 15);
|
||||
BEXT(x4, ed, gd, x6);
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x4);
|
||||
break;
|
||||
case 0xA4:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ew, Gw, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shld16c(dyn, ninst, rex, ed, gd, u8, x3, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
ANDI(gd, gd, 15);
|
||||
BEXT(x4, ed, gd, x6);
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x4);
|
||||
ADDI(x4, xZR, 1);
|
||||
SLL(x4, x4, gd);
|
||||
OR(ed, ed, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ew, Gw, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shrd16c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -2014,9 +2265,27 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ZEXTH(x2, x2);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
ANDI(gd, gd, 15);
|
||||
BEXT(x4, ed, gd, x3); // F_CF is 1
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x4);
|
||||
ADDI(x4, xZR, 1);
|
||||
SLL(x4, x4, gd);
|
||||
NOT(x4, x4);
|
||||
AND(ed, ed, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gw, Eb");
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
eb1 = xRAX + (nextop & 7) + (rex.b << 3);
|
||||
@@ -2040,6 +2309,159 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
AND(gd, gd, x5);
|
||||
OR(gd, gd, x1);
|
||||
break;
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 15;
|
||||
BEXTI(x3, ed, u8); // F_CF is 1
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 15);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
if (u8 <= 10) {
|
||||
ANDI(x6, ed, 1 << u8);
|
||||
BNE_MARK(x6, xZR);
|
||||
ANDI(xFlags, xFlags, ~(1 << F_CF));
|
||||
XORI(ed, ed, 1 << u8);
|
||||
} else {
|
||||
ORI(x6, xZR, 1);
|
||||
SLLI(x6, x6, u8);
|
||||
AND(x4, ed, x6);
|
||||
BNE_MARK(x4, xZR);
|
||||
ANDI(xFlags, xFlags, ~(1 << F_CF));
|
||||
XOR(ed, ed, x6);
|
||||
}
|
||||
EWBACK;
|
||||
MARK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 15);
|
||||
ANDI(xFlags, xFlags, ~(1 << F_CF));
|
||||
if (u8 <= 10) {
|
||||
ANDI(x6, ed, 1 << u8);
|
||||
BEQ_MARK(x6, xZR);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
XORI(ed, ed, 1 << u8);
|
||||
} else {
|
||||
ORI(x6, xZR, 1);
|
||||
SLLI(x6, x6, u8);
|
||||
AND(x6, ed, x6);
|
||||
BEQ_MARK(x6, xZR);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
XOR(ed, ed, x6);
|
||||
}
|
||||
EWBACK;
|
||||
MARK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 15;
|
||||
BEXTI(x3, ed, u8); // F_CF is 1
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x3);
|
||||
if (u8 <= 0x10) {
|
||||
XORI(ed, ed, (1LL << u8));
|
||||
} else {
|
||||
MOV64xw(x3, (1LL << u8));
|
||||
XOR(ed, ed, x3);
|
||||
}
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = xRAX + (nextop & 7) + (rex.b << 3);
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w);
|
||||
ADDSL(x3, wback, x1, 2 + rex.w, x1);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
if (rv64_zbs)
|
||||
BEXT_(x4, ed, gd);
|
||||
else {
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0xf);
|
||||
SRL(x4, ed, x2);
|
||||
ANDI(x4, x4, 1);
|
||||
}
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x4);
|
||||
ADDI(x4, xZR, 1);
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 15);
|
||||
SLL(x4, x4, x2);
|
||||
XOR(ed, ed, x4);
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gw, Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x5, 0);
|
||||
GETGW(x4);
|
||||
BNE_MARK(ed, xZR);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
// gd is undefined if ed is all zeros, don't worry.
|
||||
CTZxw(gd, ed, 0, x1, x2);
|
||||
ANDI(xFlags, xFlags, ~(1 << F_ZF));
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gw, Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x5, 0);
|
||||
GETGW(x4);
|
||||
BNE_MARK(ed, xZR);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
ANDI(xFlags, xFlags, ~(1 << F_ZF));
|
||||
CLZxw(gd, ed, 0, x1, x2, x3);
|
||||
ADDI(x1, xZR, rex.w ? 63 : 31);
|
||||
SUB(gd, x1, gd);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
nextop = F8;
|
||||
@@ -2067,6 +2489,18 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
AND(x1, x1, x5);
|
||||
OR(gd, gd, x1);
|
||||
break;
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
MV(x9, ed);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
MV(gd, x9);
|
||||
EWBACK;
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -2156,6 +2590,29 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SD(x3, gback, gdoffset + 0);
|
||||
SD(x4, gback, gdoffset + 8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* BSWAP reg */
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
if(rex.w) {
|
||||
REV8xw(gd, gd, x1, x2, x3, x4);
|
||||
} else {
|
||||
ANDI(x1, gd, 0xff);
|
||||
SLLI(x1, x1, 8);
|
||||
SRLI(x2, gd, 8);
|
||||
ANDI(x2, x2, 0xff);
|
||||
SRLI(x3, gd, 16);
|
||||
SLLI(x4, x3, 16);
|
||||
AND(x1, x4, x1);
|
||||
AND(gd, x1, x2);
|
||||
}
|
||||
break;
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -2503,17 +2960,11 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(x2, 0);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
// tmp32s = (int32_t)GX->sw[i] - EX->sw[i];
|
||||
// GX->sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
// GX->sw[i] = sat16(tmp32s);
|
||||
LH(x3, gback, gdoffset + 2 * i);
|
||||
LH(x4, wback, fixedaddress + 2 * i);
|
||||
SUBW(x3, x3, x4);
|
||||
LUI(x4, 0xFFFF8); // -32768
|
||||
BGE(x3, x4, 12);
|
||||
SH(x4, gback, gdoffset + 2 * i);
|
||||
J(20); // continue
|
||||
LUI(x4, 8); // 32768
|
||||
BLT(x3, x4, 8);
|
||||
ADDIW(x3, x4, -1);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
}
|
||||
break;
|
||||
@@ -2568,17 +3019,11 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(x2, 0);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
// tmp32s = (int32_t)GX->sw[i] + EX->sw[i];
|
||||
// GX->sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
// GX->sw[i] = sat16(tmp32s);
|
||||
LH(x3, gback, gdoffset + 2 * i);
|
||||
LH(x4, wback, fixedaddress + 2 * i);
|
||||
ADDW(x3, x3, x4);
|
||||
LUI(x4, 0xFFFF8); // -32768
|
||||
BGE(x3, x4, 12);
|
||||
SH(x4, gback, gdoffset + 2 * i);
|
||||
J(20); // continue
|
||||
LUI(x4, 8); // 32768
|
||||
BLT(x3, x4, 8);
|
||||
ADDIW(x3, x4, -1);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
}
|
||||
break;
|
||||
|
||||
Loaded 100 of 1186 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user