mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 02:08:35 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5daced4476 | ||
|
|
20cff3b264 | ||
|
|
37f5e4b7b0 | ||
|
|
70cdfdb2c2 | ||
|
|
50855a1e2b | ||
|
|
0b5002e8df | ||
|
|
4049ceacf0 | ||
|
|
5c60cf8f42 | ||
|
|
59b3eb1555 | ||
|
|
83935bc134 | ||
|
|
27a2d1f81d | ||
|
|
b71b00322e | ||
|
|
b640a570b3 | ||
|
|
9c5e8a541a | ||
|
|
6bee368bd2 | ||
|
|
3d48b55edb | ||
|
|
03d689bf56 | ||
|
|
b8171c2402 | ||
|
|
d338d4660e | ||
|
|
20807c208c | ||
|
|
23597f62fd | ||
|
|
27fd407318 | ||
|
|
22f67f2b20 | ||
|
|
74d9149095 | ||
|
|
37d91ce5ee | ||
|
|
59955e15bb | ||
|
|
5cc72d9d7a | ||
|
|
9f0814e08f | ||
|
|
89566077a7 | ||
|
|
0b046f594c | ||
|
|
93c68acd37 | ||
|
|
5177ca4732 | ||
|
|
e86a766cbe | ||
|
|
f60dea9b4b | ||
|
|
d7124fdd64 | ||
|
|
d74ec762c6 | ||
|
|
a7f9094034 | ||
|
|
6dfbebd2d4 | ||
|
|
6367180c2c | ||
|
|
81e0246b2a | ||
|
|
8a7a148bdd | ||
|
|
6c88bbda42 | ||
|
|
75cff5c584 | ||
|
|
fb0b267f53 | ||
|
|
d318afe1b9 | ||
|
|
5250c6e7a5 | ||
|
|
7e06f2bd28 | ||
|
|
25418aa192 | ||
|
|
07e9e5c344 | ||
|
|
5055f947eb | ||
|
|
4df6988c9f | ||
|
|
4e8f73c277 | ||
|
|
30d5c77188 | ||
|
|
ea513ac125 | ||
|
|
3795fe40fb | ||
|
|
2da641175c | ||
|
|
ec2f98e95a | ||
|
|
4c6be6cb23 | ||
|
|
78217d33fe | ||
|
|
c4eb274b9a | ||
|
|
61bbb76bdc | ||
|
|
13f5aea7d2 | ||
|
|
9cb238fd92 | ||
|
|
11a20e37c8 | ||
|
|
63ed07ac83 | ||
|
|
4b7d2eaabe | ||
|
|
74ee4280db | ||
|
|
11effee660 | ||
|
|
21c14f1c04 | ||
|
|
61add52ed5 | ||
|
|
e9f705df0c | ||
|
|
319a1a8ad6 | ||
|
|
be6e39cdeb | ||
|
|
49341072c8 | ||
|
|
a62e03fc7f | ||
|
|
3c563ba603 | ||
|
|
e8a2f7f9c9 | ||
|
|
1a49e47075 | ||
|
|
1d2083fe59 | ||
|
|
d04c270fa9 | ||
|
|
7fffe8dfb5 | ||
|
|
a46ad9dfe9 | ||
|
|
420eda69ff | ||
|
|
5735c8b7c8 | ||
|
|
827f0ee54e | ||
|
|
0b0a31c53c | ||
|
|
39aae76ddf | ||
|
|
f267770d75 | ||
|
|
082ecb92b1 | ||
|
|
fbba162d7c | ||
|
|
8851be9278 | ||
|
|
a111fcafee | ||
|
|
d96343fbb1 | ||
|
|
ae3412c1bf | ||
|
|
db0615cbb0 | ||
|
|
3835fe369e | ||
|
|
d07e3def9c | ||
|
|
d0c7da583d | ||
|
|
259ba9f554 | ||
|
|
2c3ac5ff08 | ||
|
|
d11def2d5b | ||
|
|
d166be5dcc | ||
|
|
30449e9255 | ||
|
|
b9bf3c344d | ||
|
|
3ee377b444 | ||
|
|
75ff158c4c | ||
|
|
66dafa5330 | ||
|
|
27860e6aee | ||
|
|
437900559a | ||
|
|
4e91870c51 | ||
|
|
b99d44309e | ||
|
|
e296745e82 | ||
|
|
157dd83ef3 | ||
|
|
d653d0ebef | ||
|
|
c51e58b34a | ||
|
|
1f7fd2afb0 | ||
|
|
4437c9b8b1 | ||
|
|
986c69cc3e | ||
|
|
868e020d59 | ||
|
|
45f85efc52 | ||
|
|
ef7005d9ea | ||
|
|
a95f10cb66 | ||
|
|
93cda37aa6 | ||
|
|
0684e43871 | ||
|
|
7de6142c98 | ||
|
|
ee03a07a17 | ||
|
|
c6a8c4472f | ||
|
|
397f1f1594 | ||
|
|
343ff5f1bc | ||
|
|
c5ddad2a1f | ||
|
|
630c40324c | ||
|
|
f9bc4a4170 | ||
|
|
84972663c5 | ||
|
|
72cbb140c8 | ||
|
|
a489cfe7d0 | ||
|
|
937d39e71c | ||
|
|
779d69f2ec | ||
|
|
55caa39c60 | ||
|
|
935b6d090f | ||
|
|
6ece2e87f2 | ||
|
|
bffb9ee4d1 | ||
|
|
f3bec61f27 | ||
|
|
78ae59d67b | ||
|
|
76f318d453 | ||
|
|
b00d767d1a | ||
|
|
2a30952898 | ||
|
|
89453f420d | ||
|
|
cf250c5661 | ||
|
|
a43469d7a5 | ||
|
|
430a408f0a | ||
|
|
c269865bb2 | ||
|
|
2f47bdff3a | ||
|
|
8f6ab59fc6 | ||
|
|
bc41dacc8c | ||
|
|
b1fc0735bb | ||
|
|
0c2de1f7f2 | ||
|
|
d58d619e84 | ||
|
|
abfb8c3b2f | ||
|
|
9ad27f276d | ||
|
|
e5afb47da8 | ||
|
|
66e4dafa8b | ||
|
|
f5ffcd0a04 | ||
|
|
77117b80ae | ||
|
|
a342e5c9ee | ||
|
|
2558cfa20b | ||
|
|
45378965aa | ||
|
|
e6f795ed9c | ||
|
|
2f0b5b2100 | ||
|
|
d3acacac95 | ||
|
|
a56756600a | ||
|
|
1b53452856 | ||
|
|
2cb3abdedb | ||
|
|
c78eea5fee | ||
|
|
e0c5937777 | ||
|
|
4e572b7b86 | ||
|
|
baf179bd46 | ||
|
|
1b16bc1a3b | ||
|
|
232ec8f9e1 | ||
|
|
48ff0ddebc | ||
|
|
40ff0e3688 | ||
|
|
970ba62254 | ||
|
|
02fc0325c8 | ||
|
|
0ee43100e1 | ||
|
|
8397d31268 | ||
|
|
ce74770e22 | ||
|
|
3787548a9a | ||
|
|
c4632305ca | ||
|
|
b4c92227b1 | ||
|
|
a028bd0e91 | ||
|
|
3ce98ac36a | ||
|
|
9c72206aae | ||
|
|
4d303a7c48 | ||
|
|
2a06231169 | ||
|
|
2ad3ee9151 | ||
|
|
557f76cb46 | ||
|
|
c1d62abf8c | ||
|
|
50069bcf69 | ||
|
|
e1eee0855a | ||
|
|
0f35bd7e3d | ||
|
|
7914fed533 | ||
|
|
1a478ee6ae | ||
|
|
7b23f2b5a7 | ||
|
|
ddd8ff7379 | ||
|
|
6650ba5b68 | ||
|
|
486ebebfc2 | ||
|
|
4f253fd85c | ||
|
|
4a2f139b1c | ||
|
|
c4e9a19fc9 | ||
|
|
b80b3304c3 | ||
|
|
7895d298c4 | ||
|
|
4238c8eb6f | ||
|
|
4c231eb087 | ||
|
|
c61543e47b | ||
|
|
a8e529c6c0 | ||
|
|
537c562c7c | ||
|
|
906dc9636d | ||
|
|
9f285eab00 | ||
|
|
d5da4d32ed | ||
|
|
967bccf7f3 | ||
|
|
ac9b13a54f | ||
|
|
685314c56e | ||
|
|
5d797f351d | ||
|
|
e3ab37bd05 | ||
|
|
58c9082b10 | ||
|
|
0b89f9d9b5 | ||
|
|
494430c6ff | ||
|
|
db3cc44adc | ||
|
|
e4dc7b5e3c | ||
|
|
806d23db92 | ||
|
|
851933bde9 | ||
|
|
c3b5282050 | ||
|
|
7df4af9983 | ||
|
|
729c25da67 | ||
|
|
51b5f8cfc2 | ||
|
|
34f858f1bd | ||
|
|
a3124f3001 | ||
|
|
9e6cf49acf | ||
|
|
0209199922 | ||
|
|
572cdff98b | ||
|
|
66a60835a7 | ||
|
|
6290f2b6a4 | ||
|
|
477a00df49 | ||
|
|
944a6f8c55 | ||
|
|
6a8433a019 | ||
|
|
9c5c904adf | ||
|
|
fbbb0544f7 | ||
|
|
cd3cea460c | ||
|
|
d5054d6cb8 | ||
|
|
18bd20f56d | ||
|
|
b192486245 | ||
|
|
6add5c1406 | ||
|
|
de761a83e9 | ||
|
|
a0017eac98 | ||
|
|
db0873caec | ||
|
|
f332ae2ba2 | ||
|
|
3f34d1e7e6 | ||
|
|
002d10833d | ||
|
|
a92a0263eb | ||
|
|
07c37e1c4d | ||
|
|
90efb9a7d8 | ||
|
|
454d538757 | ||
|
|
38f4831b24 | ||
|
|
e5ff132dc3 | ||
|
|
b4bc7c2e46 | ||
|
|
6f7a215578 | ||
|
|
5fb1da8cd6 | ||
|
|
86c7a8f354 | ||
|
|
9f69ee9310 | ||
|
|
9dd0bb4b40 | ||
|
|
e74c6438b7 | ||
|
|
ba0d84bd9e | ||
|
|
560bfed198 | ||
|
|
8f5d6e7be1 | ||
|
|
1e51dbdcae | ||
|
|
3bb457940a | ||
|
|
422a9f9d19 | ||
|
|
496fb4bebf | ||
|
|
1e771b2496 | ||
|
|
242228de83 | ||
|
|
ae8a2eb85e | ||
|
|
94b4f93540 | ||
|
|
92527ded34 | ||
|
|
b30ad56e97 | ||
|
|
cc07741a6c | ||
|
|
b40b2f1293 | ||
|
|
5da0996aee | ||
|
|
3ad88dc2e1 | ||
|
|
fef3a9702f | ||
|
|
77fdc0bafb | ||
|
|
f9d58352e9 | ||
|
|
e4eb6dcc3f | ||
|
|
a420817e62 | ||
|
|
793848f551 | ||
|
|
583b5b6e11 | ||
|
|
23807cdbe7 | ||
|
|
8396169efd | ||
|
|
384167084a | ||
|
|
04f21d33fe | ||
|
|
74276a3ff9 | ||
|
|
36738670ee | ||
|
|
c540e82aef | ||
|
|
0b689c4bd4 | ||
|
|
64a882ab38 | ||
|
|
f7a42e850b | ||
|
|
e5c9d55b8b | ||
|
|
2c188cfc35 | ||
|
|
eb3a37a5e6 | ||
|
|
eb49d3d97f | ||
|
|
b4f78a1cea | ||
|
|
e4e5cba58c | ||
|
|
a83b0accf8 | ||
|
|
c79152cb46 | ||
|
|
5524b62033 | ||
|
|
a99eed9a38 | ||
|
|
1a0a128272 | ||
|
|
92f5a7fe5f | ||
|
|
a4bbaa525c | ||
|
|
e2219d8fac | ||
|
|
4e5f1806dc | ||
|
|
ad64e829e5 | ||
|
|
36d1cd790a | ||
|
|
797bd01859 | ||
|
|
b5697f4107 | ||
|
|
b9bd355e12 | ||
|
|
7e886595c7 | ||
|
|
a4cc147ec4 | ||
|
|
40d820b27f | ||
|
|
fffc39881a | ||
|
|
b9fd03e3a2 | ||
|
|
0d261b6e90 | ||
|
|
6ff9276b1b | ||
|
|
f21db8d170 | ||
|
|
5905dc5639 | ||
|
|
49ce9e5bd5 | ||
|
|
2add381bf7 | ||
|
|
1eb97e51a2 | ||
|
|
31106cd00e | ||
|
|
e4c9577f32 | ||
|
|
e367134e7f | ||
|
|
a01ded9351 | ||
|
|
0708e6f9fd | ||
|
|
d79d0efad8 | ||
|
|
4de091016b | ||
|
|
65702d61c3 | ||
|
|
3f74c742c6 | ||
|
|
fc1f3419a6 | ||
|
|
bc19066a29 | ||
|
|
022a637136 | ||
|
|
ebae9d1db6 | ||
|
|
cd9b0358b3 | ||
|
|
12636eb321 | ||
|
|
1e7121e48f | ||
|
|
6f9ed4cc1e | ||
|
|
4e144ee147 | ||
|
|
c383d0313e | ||
|
|
1cc0874b0c | ||
|
|
b68905249e | ||
|
|
f39cedc9c5 | ||
|
|
16c3d08bb5 | ||
|
|
0f6603ed42 | ||
|
|
b238f4f1b8 | ||
|
|
55083ea13d | ||
|
|
fa94836a96 | ||
|
|
171d7b2144 | ||
|
|
0b5d30b9a8 | ||
|
|
4e3bb8861b | ||
|
|
31c8d836fc | ||
|
|
0b0fb69c9f | ||
|
|
babdc6961f | ||
|
|
36260684e4 | ||
|
|
c305b57c6f | ||
|
|
96b70f8737 | ||
|
|
e6ddae9f54 | ||
|
|
27fbe43d92 | ||
|
|
f79640e527 | ||
|
|
6f6fc3bc25 | ||
|
|
59d8dc6051 | ||
|
|
d36e574be1 | ||
|
|
77964a083f | ||
|
|
944776384a | ||
|
|
d51e72eca8 | ||
|
|
711b07a7d8 | ||
|
|
acec20bfc5 | ||
|
|
aab716ff6e | ||
|
|
2f7b82bef1 | ||
|
|
951808acd1 | ||
|
|
5b352263af | ||
|
|
7e98945d1d | ||
|
|
90b02b9a41 | ||
|
|
dc57589aac | ||
|
|
1f7ff4b968 | ||
|
|
9cd1d38751 | ||
|
|
91b7fa7eea | ||
|
|
ec1d5a6ac2 | ||
|
|
a793cd52c2 | ||
|
|
9e8d8193dc | ||
|
|
d50beea87b | ||
|
|
455bc1c4a2 | ||
|
|
76fda7910e | ||
|
|
67e8c97ca1 | ||
|
|
64367de6bf | ||
|
|
060b5d6bdb | ||
|
|
6d039e5df1 | ||
|
|
b32ea75869 | ||
|
|
499d038626 | ||
|
|
7fbbcd3468 | ||
|
|
4aa4f6f70d | ||
|
|
d1bb1d1e05 | ||
|
|
9e13288ed2 | ||
|
|
72cd18a8bc | ||
|
|
caf201fec9 | ||
|
|
2bb936b5fd | ||
|
|
d2df252722 | ||
|
|
bdc7138c7c | ||
|
|
023d96ec17 | ||
|
|
db05d0e664 | ||
|
|
777af102a5 | ||
|
|
2598e8c7e8 | ||
|
|
ba23a5e8e2 | ||
|
|
e852f2539f | ||
|
|
d69e4a9684 | ||
|
|
f204ae6900 | ||
|
|
6271ae2fd3 | ||
|
|
b38a33c00d | ||
|
|
1227cf2e6b | ||
|
|
ed8c6b2e82 | ||
|
|
2969b05414 | ||
|
|
af7eb3177f | ||
|
|
3a2f1727c3 | ||
|
|
ceea1465ab | ||
|
|
750a8775b9 | ||
|
|
ff1771d134 | ||
|
|
64d2204635 | ||
|
|
8ed77f3d93 | ||
|
|
b5108ce468 | ||
|
|
fb73285312 | ||
|
|
60693dc374 | ||
|
|
2617c97492 | ||
|
|
3c6704a909 | ||
|
|
554b84068b | ||
|
|
d74598aaa8 | ||
|
|
5b3259491b | ||
|
|
6fec414a72 | ||
|
|
80e10e696a | ||
|
|
9f3671b8ec | ||
|
|
3601698aa7 | ||
|
|
83a9d67e15 | ||
|
|
0b9b6322de | ||
|
|
199f00ebff | ||
|
|
d6806f0ecc | ||
|
|
e8b1004112 | ||
|
|
2595c1e98f | ||
|
|
5847f2f193 | ||
|
|
303bceba3f | ||
|
|
1cb3a71c05 | ||
|
|
09124eb6ef | ||
|
|
78bf553c62 | ||
|
|
da05e01235 | ||
|
|
e809d29035 | ||
|
|
d691d07bd9 | ||
|
|
b552ab5f8f | ||
|
|
c3294588f9 | ||
|
|
73e3a97009 | ||
|
|
986846bb7c | ||
|
|
43acf32c85 | ||
|
|
e99ca51299 | ||
|
|
e51e9c84a3 | ||
|
|
9cf3ceaa86 | ||
|
|
e0d9d9be29 | ||
|
|
e13e3cb1f2 | ||
|
|
491ab0e304 | ||
|
|
0e9d41ce15 | ||
|
|
fa5fbe6acd | ||
|
|
ba373ab4b3 | ||
|
|
8ee669331e | ||
|
|
98459539dc | ||
|
|
607c22d22a | ||
|
|
5e5e598a6b | ||
|
|
62cb8170cc | ||
|
|
39d0b82094 | ||
|
|
fa6868c5bd | ||
|
|
5ca4b91e00 | ||
|
|
5d881fd59d | ||
|
|
cec0f61e0e | ||
|
|
b277c76d6d | ||
|
|
5bbafe7562 | ||
|
|
ddd3bd602f | ||
|
|
5afc665420 | ||
|
|
b63f650694 | ||
|
|
61d01a4c2c | ||
|
|
3c670efe6f | ||
|
|
55ed7e9edb | ||
|
|
9c11c5671c | ||
|
|
5656decbde | ||
|
|
1b79a0c060 | ||
|
|
0db8df7757 | ||
|
|
8ef7ef3209 | ||
|
|
372739d07f | ||
|
|
34f949bf5d | ||
|
|
dd9743513e | ||
|
|
f6617364cd | ||
|
|
b5d45778c4 | ||
|
|
064c9222ed | ||
|
|
392502fd11 | ||
|
|
b5066f8ab4 | ||
|
|
e0ae94d742 | ||
|
|
bd47c3da04 | ||
|
|
bae1de053e | ||
|
|
1058aae561 | ||
|
|
c569c55494 | ||
|
|
744e2bb4ec |
No files matched your search
@@ -37,7 +37,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64]
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64, ARM64EC]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
exclude:
|
||||
- platform: ANDROID
|
||||
@@ -56,6 +56,12 @@ jobs:
|
||||
type: StaticBuild
|
||||
- platform: WOW64
|
||||
type: Box32
|
||||
- platform: ARM64EC
|
||||
type: Box32
|
||||
- platform: ARM64EC
|
||||
type: Trace
|
||||
- platform: ARM64EC
|
||||
type: StaticBuild
|
||||
- platform: ANDROID
|
||||
type: Trace
|
||||
- platform: TERMUX
|
||||
@@ -95,6 +101,9 @@ jobs:
|
||||
- platform: WOW64
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
- platform: ARM64EC
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: ${{ matrix.image || '' }}
|
||||
@@ -195,9 +204,17 @@ jobs:
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'WOW64' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1 -DNOBOX64=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20260311
|
||||
export LLVM_MINGW_VERSION=20260616
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'ARM64EC' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64EC=1 -DARM_DYNAREC=1 -DNOBOX64=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20260616
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
@@ -244,7 +261,7 @@ jobs:
|
||||
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3 libzydis-dev
|
||||
elif [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON" >> $GITHUB_ENV
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON -DBAD_SIGNAL=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=powerpc64le-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-powerpc64le-linux-gnu cmake make python3 libzydis-dev
|
||||
else
|
||||
|
||||
@@ -20,7 +20,7 @@ These use cases are **permitted** when making a contribution with the help of AI
|
||||
- Formatting code for consistency and readability (but do not overload code with comments)
|
||||
- Completing code segments based on established patterns
|
||||
- Drafting documentation for project components with which the contributor is already familiar
|
||||
- Writting Wrappers Callback handling and/or wrappers structures conversion when needed
|
||||
- Writing Wrappers Callback handling and/or wrappers structures conversion when needed
|
||||
|
||||
AI-generated code that has undergone extensive human editing may be accepted, provided you (1) fully understand the AI's initial output, (2) can debug any issues independently (with or without further AI assistance), and (3) are prepared to discuss it directly with human reviewers.
|
||||
|
||||
|
||||
+171
-109
@@ -5,6 +5,7 @@ cmake_policy(SET CMP0065 NEW)
|
||||
SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
|
||||
|
||||
option(NOBOX64 "Set to ON to NOT build the main box64 binary (usefull for building box64 dll only)" ${NOBOX64})
|
||||
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})
|
||||
@@ -44,12 +45,14 @@ option(BAD_PKILL "Set to ON to activate the workaround for incoherent pthread_ki
|
||||
option(SW64 "Set ON if targeting an SW64 based device" ${SW64})
|
||||
option(CI "Set to ON if running in CI" ${CI})
|
||||
option(WITH_MOLD "Set to ON to use with mold" ${WITH_MOLD})
|
||||
option(BOX32 "Set to ON to add Linux 32bits support (experimental, do not use)" ${BOX32})
|
||||
option(BOX32 "Set to ON to add Linux 32bits support" ${BOX32})
|
||||
option(BOX32_BINFMT "Also setup binfmt integration for box32" ${BOX32_BINFMT})
|
||||
option(LARCH64_ABI_1 "Set to ON if building for Loongarch64 ABI 1.0 system" ${LARCH64_ABI_1})
|
||||
option(GDBJIT "Set to ON to enable GDB JIT support" ${GDBJIT})
|
||||
option(WOW64 "Set to ON if you want a WOW64 PE build in addition")
|
||||
option(ARM64EC "Set to ON to build Box64EC PE DLL module (no emulation yet)" OFF)
|
||||
option(BOX64_KDE_PROFILE_PLUGIN "Build the Dolphin/KIO Box64 profile properties plugin when KF5 or KF6 is available" OFF)
|
||||
option(BUNDLE_X86_LIBS "Set to ON to download and install the x86 and x86_64 libraries bundle from the latest GitHub release during the install" OFF)
|
||||
|
||||
if(TERMUX)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
@@ -220,12 +223,12 @@ elseif(SD8G2)
|
||||
elseif(SD8EG5)
|
||||
add_definitions(-DSD8EG5)
|
||||
# NOTE
|
||||
# Even though Qualcomm Snapdragon 8 Elite Gen 5 relies on 3rd generation Oryon cores, it seems like the support for them
|
||||
# Even though Qualcomm Snapdragon 8 Elite Gen 5 relies on 3rd generation Oryon cores, it seems like the support for them
|
||||
# is not yet present in GCC and Clang, so for now we will use mostly the same optimization flags as SDORYON1, which houses
|
||||
# 1st generation Oryon cores. This should still be fine since the main difference between the
|
||||
# 1st generation Oryon cores. This should still be fine since the main difference between the
|
||||
# two is the presence of SVE and SVE2, which are not yet used in Box64's ARM64 dynarec.
|
||||
#
|
||||
# As noted in the SDORYON1 section, GCC 14 and Clang 19 support oryon-1 as a -mcpu/-mtune argument, however it seems like
|
||||
# As noted in the SDORYON1 section, GCC 14 and Clang 19 support oryon-1 as a -mcpu/-mtune argument, however it seems like
|
||||
# Fedora does not like them very much, so this option should be taken with a grain of salt. It worked in my test case just fine.
|
||||
set(CFLAGS -pipe -march=armv8.7-a+crypto+sm4+sha3+fp16+sve+sve2 -mtune=oryon-1)
|
||||
elseif(SDORYON1)
|
||||
@@ -262,8 +265,9 @@ elseif(LARCH64)
|
||||
set(ASMFLAGS -pipe -march=loongarch64)
|
||||
elseif(RV64)
|
||||
add_definitions(-DRV64)
|
||||
set(CFLAGS -pipe -march=rv64gc)
|
||||
set(CFLAGS -pipe -march=rv64gc -fno-tree-vectorize)
|
||||
set(ASMFLAGS -pipe -march=rv64gc)
|
||||
add_compile_options(-fno-tree-vectorize)
|
||||
elseif(PPC64LE)
|
||||
add_definitions(-DPPC64LE)
|
||||
set(CFLAGS -pipe -mcpu=power9)
|
||||
@@ -471,6 +475,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/syscall_user_dispatch.c"
|
||||
"${BOX64_ROOT}/src/libtools/decopcode.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/steamwebhelper.c"
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
"${BOX64_ROOT}/src/tools/box64stack.c"
|
||||
"${BOX64_ROOT}/src/tools/bridge.c"
|
||||
@@ -607,7 +612,6 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcuda.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairogobject.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrypto.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrypto3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
@@ -698,6 +702,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibnuma.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibopus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibomp.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpci.c"
|
||||
@@ -811,6 +816,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedmimalloc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedunwind.c"
|
||||
@@ -938,7 +944,6 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibrt.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibresolv.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedcrashhandler.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibgl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibglu.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibglxnvidia.c"
|
||||
@@ -1099,6 +1104,8 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_consts.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_mov_imm.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/updateflags_rv64.c"
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
@@ -1110,6 +1117,7 @@ if(RV64_DYNAREC)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/updateflags_rv64_pass.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_logic.c"
|
||||
@@ -1142,6 +1150,12 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f38_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c"
|
||||
@@ -1160,6 +1174,7 @@ if(LARCH64_DYNAREC)
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_native.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_arch.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_jmpnext.c"
|
||||
@@ -1176,11 +1191,16 @@ if(LARCH64_DYNAREC)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_native_pass.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_00_0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_1.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_2.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_00_3.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_660f.c"
|
||||
@@ -1331,53 +1351,60 @@ add_library(mainobj OBJECT ${OS_LINUX_SRC} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPE
|
||||
add_dependencies(mainobj generate_git_head_target)
|
||||
add_dependencies(mainobj generate_dynacache_hashes)
|
||||
|
||||
add_executable(${BOX64})
|
||||
target_link_libraries(${BOX64} mainobj)
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
if(BOX32)
|
||||
add_dependencies(${BOX64} WRAPPERS32)
|
||||
endif()
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
|
||||
if(STATICBUILD)
|
||||
#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 c)
|
||||
else()
|
||||
if(ANDROID)
|
||||
if(TERMUX)
|
||||
target_link_libraries(${BOX64} c m dl android-sysv-semaphore)
|
||||
if(NOT NOBOX64)
|
||||
add_executable(${BOX64})
|
||||
target_link_libraries(${BOX64} mainobj)
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
if(BOX32)
|
||||
add_dependencies(${BOX64} WRAPPERS32)
|
||||
endif()
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
|
||||
if(STATICBUILD)
|
||||
#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 c)
|
||||
else()
|
||||
if(ANDROID)
|
||||
if(TERMUX)
|
||||
target_link_libraries(${BOX64} c m dl android-sysv-semaphore)
|
||||
else()
|
||||
target_link_libraries(${BOX64} c m dl)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(${BOX64} c m dl)
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
|
||||
target_link_libraries(${BOX64} c m dl pthread resolv util c)
|
||||
endif()
|
||||
endif()
|
||||
if(DYNAREC)
|
||||
target_link_libraries(${BOX64} dynarec)
|
||||
endif()
|
||||
target_link_libraries(${BOX64} interpreter)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS} ")
|
||||
else()
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS} ")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
|
||||
target_link_libraries(${BOX64} c m dl pthread resolv util c)
|
||||
endif()
|
||||
endif()
|
||||
if(DYNAREC)
|
||||
target_link_libraries(${BOX64} dynarec)
|
||||
endif()
|
||||
target_link_libraries(${BOX64} interpreter)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS} ")
|
||||
else()
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS} ")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
if(WITH_MOLD) # --image-base requires -no-pie in mold!
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -lm ")
|
||||
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
# --image-base alone does not disable PIE with Clang/LLD.
|
||||
# Android requires PIE.
|
||||
if(NOT ANDROID)
|
||||
target_link_options(${BOX64} PUBLIC -no-pie)
|
||||
endif()
|
||||
if(WITH_MOLD)
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-lm ")
|
||||
endif()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
|
||||
else()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
endif()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
|
||||
else()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -1395,7 +1422,7 @@ if(_x86_64 OR _aarch64 OR _ppc64le)
|
||||
add_definitions(-DCONFIG_64BIT)
|
||||
endif()
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
if(NOT _x86 AND NOT _x86_64 AND NOT NOBOX64)
|
||||
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/share/box64)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/tests/box64-bash ${CMAKE_BINARY_DIR}/bin/box64-bash COPYONLY)
|
||||
@@ -1597,14 +1624,28 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
if(NOT NOBOX64)
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUNDLE_X86_LIBS)
|
||||
install(CODE "
|
||||
message(STATUS \"Installing the x86 and x86_64 libraries bundle\")
|
||||
execute_process(
|
||||
COMMAND \"${BOX64_ROOT}/box64-bundle-x86-libs.sh\" --install
|
||||
WORKING_DIRECTORY \"${BOX64_ROOT}\"
|
||||
RESULT_VARIABLE BUNDLE_X86_LIBS_RESULT)
|
||||
if(NOT BUNDLE_X86_LIBS_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR \"Failed to install the x86 and x86_64 libraries bundle\")
|
||||
endif()")
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "," DYNAREC_ASM_STR "${DYNAREC_ASM}")
|
||||
@@ -1616,7 +1657,7 @@ if(WOW64 AND ARM_DYNAREC)
|
||||
ExternalProject_Add(
|
||||
wowbox64
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/wow64"
|
||||
CMAKE_ARGS
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw.cmake
|
||||
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
|
||||
-DDYNAREC_ASM_STR=${DYNAREC_ASM_STR}
|
||||
@@ -1629,55 +1670,76 @@ if(WOW64 AND ARM_DYNAREC)
|
||||
add_dependencies(wowbox64 generate_git_head_target)
|
||||
endif()
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Box64 - Linux Userspace x86_64 Emulator with a twist")
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libandroid-sysv-semaphore")
|
||||
if(ARM64EC)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
box64ec
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/box64ec"
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw_arm64ec.cmake
|
||||
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
|
||||
-DINTERPRETER_STR=${INTERPRETER_STR}
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
BUILD_ALWAYS ON
|
||||
)
|
||||
add_dependencies(box64ec generate_git_head_target)
|
||||
endif()
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MAJOR\\s*")
|
||||
string(REGEX REPLACE "BOX64_MAJOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_MAJOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MINOR\\s*")
|
||||
string(REGEX REPLACE "BOX64_MINOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_MINOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_REVISION\\s*")
|
||||
string(REGEX REPLACE "BOX64_REVISION" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_REVISION ${TEMP_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX64_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${BOX64_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${BOX64_REVISION})
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
endif()
|
||||
if(_aarch64)
|
||||
if(TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "aarch64")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||
endif()
|
||||
elseif(_riscv64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "riscv64")
|
||||
elseif(_ppc64le)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "ppc64el")
|
||||
elseif(_x86_64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
|
||||
else()
|
||||
#probably wrong...
|
||||
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
endif()
|
||||
if(TERMUX)
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX "${TERMUX_PATH}/usr")
|
||||
endif()
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_${CMAKE_SYSTEM_NAME}-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
else()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Termux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
endif()
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_subdirectory(tests)
|
||||
if(NOT NOBOX64)
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Box64 - Linux Userspace x86_64 Emulator with a twist")
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libandroid-sysv-semaphore")
|
||||
endif()
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MAJOR\\s*")
|
||||
string(REGEX REPLACE "BOX64_MAJOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_MAJOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_MINOR\\s*")
|
||||
string(REGEX REPLACE "BOX64_MINOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_MINOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX64_ROOT}/src/box64version.h" TEMP_STRING REGEX "BOX64_REVISION\\s*")
|
||||
string(REGEX REPLACE "BOX64_REVISION" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX64_REVISION ${TEMP_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX64_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${BOX64_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${BOX64_REVISION})
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
endif()
|
||||
if(_aarch64)
|
||||
if(TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "aarch64")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||
endif()
|
||||
elseif(_riscv64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "riscv64")
|
||||
elseif(_ppc64le)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "ppc64el")
|
||||
elseif(_x86_64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
|
||||
else()
|
||||
#probably wrong...
|
||||
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
endif()
|
||||
if(TERMUX)
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX "${TERMUX_PATH}/usr")
|
||||
endif()
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_${CMAKE_SYSTEM_NAME}-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
else()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Termux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
endif()
|
||||
INCLUDE(CPack)
|
||||
endif()
|
||||
|
||||
if(NOT NOBOX64)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
+2
-1
@@ -28,4 +28,5 @@ Before submitting your PR:
|
||||
|
||||
# Coding guidelines
|
||||
|
||||
- Avoid adding third-party dependencies, extra files, extra headers, etc.
|
||||
- Avoid adding third-party dependencies, extra files, extra headers, etc.
|
||||
- New C source files must start with the license header `// SPDX-License-Identifier: MIT` or `# SPDX-License-Identifier: MIT` for Bash and Python scripts. Do not add headers to third-party files in `external/` or `src/include/`.
|
||||
@@ -55,17 +55,17 @@ Box64 requires 64-bit libraries on the host system, as it directly translates x8
|
||||
|
||||
**Notes**
|
||||
|
||||
1. Box32 is still experimental.
|
||||
1. Box32 is still experimental, but it's pretty stable now and can be used.
|
||||
2. Some shell scripts (such as the GOG game installer) may rely on `uname -m` to determine the current architecture. Please run them as `box64 script.sh` to allow Box64 to take over.
|
||||
|
||||
Note that DynaCache is now enabled by default (with compression). This will creates files in `~/.cache/box64` to save generated code for executed binaries and libraries, so launch time can be greatly reduced on second run. The files are compressed and will take up to 2Gb by default. You can disable DynaCache writting, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writting there
|
||||
Note that DynaCache is now enabled by default (with compression). This will creates files in `~/.cache/box64` to save generated code for executed binaries and libraries, so launch time can be greatly reduced on second run. The files are compressed and will take up to 2Gb by default. You can disable DynaCache writing, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writing there
|
||||
|
||||
```ini
|
||||
[*]
|
||||
BOX64_DYNACACHE=2
|
||||
```
|
||||
|
||||
(or 0 to completly disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
|
||||
(or 0 to completely disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
|
||||
|
||||
---
|
||||
|
||||
@@ -109,7 +109,7 @@ So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, mogery, ksco, xctan
|
||||
* For their major financial contribution: [Playtron](https://playtron.one), tohodakilla, 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 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 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), [SpacemiT](https://www.spacemit.com/), [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.
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
|
||||
* 代码贡献:rajdakin, mogery, ksco, xctan
|
||||
* 财务支持:[Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* 硬件捐赠和 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) 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)
|
||||
* 硬件捐赠:[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), [SpacemiT](https://www.spacemit.com/), [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/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ Box64 використовує бібліотеки Vulkan, але зауваж
|
||||
* За основний внесок у код: rajdakin, mogery, ksco, xctan
|
||||
* За великий фінансовий внесок: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
|
||||
* За внесок у апаратне забезпечення: [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)
|
||||
* За внесок у апаратне забезпечення: [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), [SpacemiT](https://www.spacemit.com/), [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/))
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_amd64.deb,6fe41d04ea9ef8c5c684b14585caa7a4a7e04ad6805d59cdd29016960b737123
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_i386.deb,6d72a7ac94c0e3faa32f7dc07a1f4bc8a782d0ab39defca6e9322dd06afd638f
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_amd64.deb,a9a5e1f53b7e27a3f2b8388929bb622d3c6c35a4e42ac166697444e5ed662fd5
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_i386.deb,15f81212576c500e47e72ff05b1b705ef62640ef0a1b8e2c34d848c16ee30728
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb,6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb,4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_amd64.deb,b49a24743eb2b6d1198c7cf014ee791bccd5d3223ed8a1e4769d899e1f894a5b
|
||||
|
||||
|
+137
-15
@@ -1,26 +1,143 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -ex
|
||||
set -e
|
||||
|
||||
trap cleanup_exit INT TERM EXIT
|
||||
|
||||
cleanup_exit()
|
||||
{
|
||||
echo "Running cleanup_exit..."
|
||||
log "Running cleanup_exit..."
|
||||
rm -rf /tmp/box64-bundle.*
|
||||
}
|
||||
|
||||
# progress messages are only printed with --debug
|
||||
log()
|
||||
{
|
||||
if [ -n "${verbose}" ]; then
|
||||
echo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat << EOF
|
||||
Usage: ${0} [OPTION]
|
||||
|
||||
Options:
|
||||
--build Build the x86 library bundle archives from Linux distribution
|
||||
packages.
|
||||
--install Install the x86 library bundle from the latest GitHub release.
|
||||
The bundle is only downloaded when at least one local file does
|
||||
not match the checksums of the latest release. It is extracted
|
||||
to the root of the file system or into DESTDIR when that
|
||||
environment variable is set.
|
||||
--debug Log every command that is run and every file that is extracted
|
||||
or archived. Without it, --build is silent unless it fails. Can
|
||||
be combined with --build or --install.
|
||||
--help Show this help message.
|
||||
EOF
|
||||
}
|
||||
|
||||
# parse the arguments before anything else so that --debug logs everything
|
||||
mode=""
|
||||
verbose=""
|
||||
quiet="q"
|
||||
for arg in "$@"; do
|
||||
case "${arg}" in
|
||||
--build|--install)
|
||||
mode="${arg}"
|
||||
;;
|
||||
--debug)
|
||||
set -x
|
||||
verbose="v"
|
||||
quiet=""
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "E: Unknown argument (${arg})"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ -z "${mode}" ]; then
|
||||
echo "E: A --build or --install argument is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
repo_url="https://github.com/ptitSeb/box64"
|
||||
|
||||
# compare the local files to the latest release and, on any mismatch, install it
|
||||
install_bundle()
|
||||
{
|
||||
# find the latest release
|
||||
release=$(basename "$(${curl} -Ls -o /dev/null -w '%{url_effective}' "${repo_url}/releases/latest")")
|
||||
case "${release}" in
|
||||
v*) ;;
|
||||
*)
|
||||
echo "E: Unable to determine the latest release"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
bundle_url="${repo_url}/releases/download/${release}/box64-bundle-x86-libs-${release}"
|
||||
bundle_checksums="${dir_tmp}/box64-bundle-x86-libs-${release}.sha256"
|
||||
bundle_archive="${dir_tmp}/box64-bundle-x86-libs-${release}.tar.gz"
|
||||
|
||||
# the checksum paths are relative to the root of the destination
|
||||
${curl_cmd} "${bundle_checksums}" "${bundle_url}.sha256"
|
||||
if [ ! -d "${dir_dest}" ]; then
|
||||
mkdir -p "${dir_dest}"
|
||||
fi
|
||||
cd "${dir_dest}"
|
||||
if ${sha256sum} --check --quiet "${bundle_checksums}" \
|
||||
> "${dir_tmp}/mismatches" 2> /dev/null; then
|
||||
echo "I: The x86 library bundle ${release} is already installed in ${dir_dest}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# a single mismatch means the whole bundle is downloaded and extracted again
|
||||
echo "I: $(wc -l < "${dir_tmp}/mismatches") file(s) do not match the latest bundle"
|
||||
if [ ! -w "${dir_dest}" ]; then
|
||||
echo "E: ${dir_dest} is not writable, run as root to install the x86 library bundle ${release}"
|
||||
exit 1
|
||||
fi
|
||||
${curl_cmd} "${bundle_archive}" "${bundle_url}.tar.gz"
|
||||
${tar} --extract --no-same-owner --file "${bundle_archive}" --directory "${dir_dest}"
|
||||
|
||||
# verify the installation
|
||||
cd "${dir_dest}"
|
||||
if ! ${sha256sum} --check --quiet "${bundle_checksums}"; then
|
||||
echo "E: Invalid checksums after installing the x86 library bundle ${release}"
|
||||
exit 1
|
||||
fi
|
||||
echo "I: Installed the x86 library bundle ${release} into ${dir_dest}"
|
||||
}
|
||||
|
||||
# we must have few tools
|
||||
awk=$(which awk) || { echo "E: You must have awk" && exit 1; }
|
||||
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
|
||||
curl=$(which curl) || { echo "E: You must have curl" && exit 1; }
|
||||
curl_cmd="${curl} --connect-timeout 5 --retry 5 --retry-delay 1 --create-dirs -fsSLo"
|
||||
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
|
||||
sha256sum=$(which sha256sum) || { echo "E: You must have sha256sum" && exit 1; }
|
||||
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
|
||||
tar=$(which tar) || { echo "E: You must have tar" && exit 1; }
|
||||
|
||||
current_dir=$(pwd)
|
||||
dir_tmp="$(mktemp -d /tmp/box64-bundle.XXXXXX)"
|
||||
dir_dest="${DESTDIR:-/}"
|
||||
|
||||
if [ "${mode}" = "--install" ]; then
|
||||
install_bundle
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# we must have few more tools to build the bundle
|
||||
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
|
||||
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
|
||||
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
|
||||
|
||||
# download the packages
|
||||
while IFS= read -r line; do
|
||||
@@ -41,7 +158,7 @@ while IFS= read -r line; do
|
||||
done < box64-bundle-x86-libs.csv
|
||||
|
||||
# generate the bundle packages archive
|
||||
tar -C "${dir_tmp}"/bundle-pkgs -czvf "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
|
||||
tar -C "${dir_tmp}"/bundle-pkgs -cz"${verbose}"f "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
|
||||
|
||||
# extract the packages
|
||||
cd "${dir_tmp}"/bundle-pkgs
|
||||
@@ -54,21 +171,26 @@ for file in *.deb *.eopkg *.rpm *.xbps; do
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
case "${extension}" in
|
||||
deb)
|
||||
echo "I: DEB (Debian) package detected (${file})"
|
||||
log "I: DEB (Debian) package detected (${file})"
|
||||
ar x "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
tar -xf data.tar*
|
||||
;;
|
||||
eopkg)
|
||||
echo "I: EOPKG (Solus Linux) package detected (${file})"
|
||||
${unzip} -o "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
log "I: EOPKG (Solus Linux) package detected (${file})"
|
||||
${unzip} -o"${quiet}" "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
tar -xf install.tar.xz
|
||||
;;
|
||||
rpm)
|
||||
echo "I: RPM (Fedora) detected (${file})"
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
|
||||
log "I: RPM (Fedora) detected (${file})"
|
||||
if [ -n "${verbose}" ]; then
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
|
||||
else
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" \
|
||||
| ${cpio} -idm --quiet 2> /dev/null
|
||||
fi
|
||||
;;
|
||||
xbps)
|
||||
echo "I: XBPS (Void Linux) package detected (${file})"
|
||||
log "I: XBPS (Void Linux) package detected (${file})"
|
||||
tar -xf "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
;;
|
||||
esac
|
||||
@@ -95,7 +217,7 @@ set -- libc libpthread librt libGL libX11 libasound libdl libm libbsd libutil \
|
||||
libxcb-xfixes libxcb-shape libxcb-shm libxcb-randr libxcb-image \
|
||||
libxcb-keysyms libxcb-xtest libxcb-glx libxcb-dri2 libxcb-dri3 libXtst libXt \
|
||||
libXcomposite libXdamage libXmu libxkbcommon libxkbcommon-x11 \
|
||||
libpulse-simple libpulse libvulkan ld-linux-x86-64 crashhandler \
|
||||
libpulse-simple libpulse libvulkan ld-linux-x86-64 \
|
||||
libtcmalloc_minimal libanl ld-linux libthread_db
|
||||
for file in "$@"; do
|
||||
rm -f "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu/"${file}".so*
|
||||
@@ -124,7 +246,7 @@ for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
|
||||
cd "${dir_lib}"
|
||||
for lib in lib*.so*; do
|
||||
lib_base="$(echo "${lib}" | awk -F'.' '{print $1"."$2}')"
|
||||
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null; then
|
||||
if ! ls "${dir_lib}/${lib_base}" > /dev/null 2>&1; then
|
||||
ln -s "${lib}" "${lib_base}"
|
||||
fi
|
||||
done
|
||||
@@ -136,4 +258,4 @@ find usr \( -type f -o -type l \) -exec "${sha256sum}" {} + \
|
||||
| LC_ALL=C sort --key 2 > "${current_dir}"/box64-bundle-x86-libs.sha256
|
||||
|
||||
# generate the bundle libraries archive
|
||||
tar -C "${dir_tmp}"/bundle-libs -czvf "${current_dir}"/box64-bundle-x86-libs.tar.gz .
|
||||
tar -C "${dir_tmp}"/bundle-libs -cz"${verbose}"f "${current_dir}"/box64-bundle-x86-libs.tar.gz .
|
||||
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
@@ -102,6 +103,7 @@ PROFILE_SETTINGS = {
|
||||
("BOX64_DYNAREC_BIGBLOCK", "0"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "2"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "2"),
|
||||
("BOX64_DYNAREC_CALLRET", "3"),
|
||||
),
|
||||
"safe": (
|
||||
("BOX64_DYNAREC_BIGBLOCK", "0"),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
Vendored
+195
-195
@@ -1,178 +1,178 @@
|
||||
box64 (0.4.4) unstable; urgency=low
|
||||
|
||||
This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
|
||||
=> A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
|
||||
=> DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
|
||||
=> You can use box64-configurator on the special `[*]` profile to change default values
|
||||
=> More improvements on emulation accuracy that help running more DRM'd games
|
||||
* This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
|
||||
* => A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
|
||||
* => DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
|
||||
* => You can use box64-configurator on the special `[*]` profile to change default values
|
||||
* => More improvements on emulation accuracy that help running more DRM'd games
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 2 Aug 2026 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 2 Aug 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.4.2) unstable; urgency=low
|
||||
|
||||
This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
|
||||
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
|
||||
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
|
||||
=> Support for SteamRT3 & new Proton 11
|
||||
=> New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
|
||||
* This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
|
||||
* => Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
|
||||
* => Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
|
||||
* => Support for SteamRT3 & new Proton 11
|
||||
* => New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.4.0) unstable; urgency=low
|
||||
|
||||
This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
|
||||
=> Improved compatibility accross all architecture, allowing more DRM protected game to run
|
||||
=> the prefix refactor helped removed lots of redundant source file, simplifying maintenance
|
||||
=> BOX32 is getting more and more stable, even if still not 100% ok. But Steam is more stable than before, runs on all architecture. And some gameoverlay UI works, on OpenGL games. gameoverlay (and fossilize) support for Vulkan is planned for later.
|
||||
* This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
|
||||
* => Improved compatibility accross all architecture, allowing more DRM protected game to run
|
||||
* => the prefix refactor helped removed lots of redundant source file, simplifying maintenance
|
||||
* => BOX32 is getting more and more stable, even if still not 100% ok. But Steam is more stable than before, runs on all architecture. And some gameoverlay UI works, on OpenGL games. gameoverlay (and fossilize) support for Vulkan is planned for later.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 3 Jan 2026 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 3 Jan 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.3.8) unstable; urgency=low
|
||||
|
||||
This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
|
||||
* This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
|
||||
|
||||
=> DynaCache for faster loading of program, and avoid runtime hicups
|
||||
=> Batter box32 compatibility (much less "Out of Memory" error)
|
||||
=> Unity3D games on Wayland are working now
|
||||
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
|
||||
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
|
||||
* => DynaCache for faster loading of program, and avoid runtime hicups
|
||||
* => Batter box32 compatibility (much less "Out of Memory" error)
|
||||
* => Unity3D games on Wayland are working now
|
||||
* => Volatile Metadata fully supported and handled, making games like Starfield to just work.
|
||||
* => More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.6) unstable; urgency=low
|
||||
|
||||
This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
* This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
|
||||
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
* => WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
* => it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
* => Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
* => The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
* => More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.4) unstable; urgency=low
|
||||
|
||||
* This version is Faster and more compatible
|
||||
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
* => On ARM64, Box64 now support more DRM types than before.
|
||||
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Please check CHAGELOG.md for more details
|
||||
* This version is Faster and more compatible
|
||||
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
* => On ARM64, Box64 now support more DRM types than before.
|
||||
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Please check CHAGELOG.md for more details
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.2) unstable; urgency=low
|
||||
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
* => Box32 is a build option for Box64, and is disabled by default
|
||||
* => Optionnal binfmt integration available for Box32
|
||||
* => Wrapped some basics libs, including graphics and sounds so a few games already works
|
||||
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
|
||||
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
|
||||
* => Available on the 3 Dynarec backend, with different implementations
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* +> Can lead to large speedup on certain cases
|
||||
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
|
||||
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
|
||||
* Some bugfix and improvment in the Signal handler and internal memory tracking
|
||||
* Improvment to TRAP signal generation and Handling
|
||||
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
|
||||
* Improved some x87 operations, like long double handling and infinity comparisons...
|
||||
* Dynarec: ARM64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes to many opcodes
|
||||
* Dynarec: LA64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
|
||||
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
|
||||
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
|
||||
* ElfLoader: Improved object fetching
|
||||
* New build profile for SD865 and ORYON
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Added a few syscalls
|
||||
* Some more Vulkan extensions wrapped
|
||||
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
* => Box32 is a build option for Box64, and is disabled by default
|
||||
* => Optionnal binfmt integration available for Box32
|
||||
* => Wrapped some basics libs, including graphics and sounds so a few games already works
|
||||
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
|
||||
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
|
||||
* => Available on the 3 Dynarec backend, with different implementations
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* +> Can lead to large speedup on certain cases
|
||||
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
|
||||
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
|
||||
* Some bugfix and improvment in the Signal handler and internal memory tracking
|
||||
* Improvment to TRAP signal generation and Handling
|
||||
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
|
||||
* Improved some x87 operations, like long double handling and infinity comparisons...
|
||||
* Dynarec: ARM64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes to many opcodes
|
||||
* Dynarec: LA64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
|
||||
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
|
||||
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
|
||||
* ElfLoader: Improved object fetching
|
||||
* New build profile for SD865 and ORYON
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Added a few syscalls
|
||||
* Some more Vulkan extensions wrapped
|
||||
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
|
||||
|
||||
box64 (0.3.0) unstable; urgency=low
|
||||
|
||||
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
|
||||
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
|
||||
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
|
||||
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
|
||||
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
|
||||
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
|
||||
* Dynarec: ARM64 some fixes to a few opcodes
|
||||
* Dynarec: LA64 many new opcodes added, and fixes.
|
||||
* Dynarec: RV64 some new opcodes added, many fixes.
|
||||
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
|
||||
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
|
||||
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
|
||||
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
|
||||
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
|
||||
* Dynarec: RV64 improved LOCK CMPXCHG handling
|
||||
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
|
||||
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
|
||||
* ElfLoader: Added a new type of relocation
|
||||
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
|
||||
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
|
||||
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
|
||||
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
|
||||
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
|
||||
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
|
||||
* Dynarec: ARM64 some fixes to a few opcodes
|
||||
* Dynarec: LA64 many new opcodes added, and fixes.
|
||||
* Dynarec: RV64 some new opcodes added, many fixes.
|
||||
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
|
||||
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
|
||||
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
|
||||
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
|
||||
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
|
||||
* Dynarec: RV64 improved LOCK CMPXCHG handling
|
||||
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
|
||||
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
|
||||
* ElfLoader: Added a new type of relocation
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
|
||||
|
||||
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.
|
||||
* 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
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
|
||||
box64 (0.2.6) unstable; urgency=low
|
||||
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: More opcodes on ARM64 & RV64
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
|
||||
* Dynarec: RV64: Many fixes, making Wow64 apps running
|
||||
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
|
||||
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
|
||||
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* CPU: Added full support for SHA extension
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Added some more syscalls
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* OS: New option to use mold for a high speed link
|
||||
* => More hadware support, more functions wrapped for an improve compatibity
|
||||
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
|
||||
* => Some work also to reduce the memory footprint
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: More opcodes on ARM64 & RV64
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
|
||||
* Dynarec: RV64: Many fixes, making Wow64 apps running
|
||||
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
|
||||
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
|
||||
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* CPU: Added full support for SHA extension
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Added some more syscalls
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* OS: New option to use mold for a high speed link
|
||||
* => More hadware support, more functions wrapped for an improve compatibity
|
||||
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
|
||||
* => Some work also to reduce the memory footprint
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
|
||||
box64 (0.2.4) unstable; urgency=low
|
||||
|
||||
@@ -199,74 +199,74 @@ box64 (0.2.4) unstable; urgency=low
|
||||
* => Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
|
||||
* => Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.2) unstable; urgency=low
|
||||
|
||||
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadaptor9 wrapping
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadaptor9 wrapping
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.0) unstable; urgency=low
|
||||
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved execv family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
|
||||
* Fix typos and arch type string by @archanox in #321
|
||||
* Fix grammar by @Jai-JAP in #326
|
||||
* Enable 64k page size by @martinmanyhats in #334
|
||||
* Align address when call mprotect by @wannacu in #336
|
||||
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
|
||||
* add 18.04 tegra X1 github actions by @theofficialgman in #345
|
||||
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
|
||||
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
|
||||
* Add SW64 base support by @wannacu in #382
|
||||
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
|
||||
* Create X64WINE.md by @WheezyE in #423
|
||||
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
|
||||
* Malloc override by @ptitSeb in #437
|
||||
* Remove dynablocklist by @ptitSeb in #438
|
||||
* Fix Pkgbuilds by @Jai-JAP in #452
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved execv family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
|
||||
* Fix typos and arch type string by @archanox in #321
|
||||
* Fix grammar by @Jai-JAP in #326
|
||||
* Enable 64k page size by @martinmanyhats in #334
|
||||
* Align address when call mprotect by @wannacu in #336
|
||||
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
|
||||
* add 18.04 tegra X1 github actions by @theofficialgman in #345
|
||||
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
|
||||
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
|
||||
* Add SW64 base support by @wannacu in #382
|
||||
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
|
||||
* Create X64WINE.md by @WheezyE in #423
|
||||
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
|
||||
* Malloc override by @ptitSeb in #437
|
||||
* Remove dynablocklist by @ptitSeb in #438
|
||||
* Fix Pkgbuilds by @Jai-JAP in #452
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
|
||||
|
||||
|
||||
+35
-5
@@ -4,9 +4,39 @@ The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-b
|
||||
|
||||
## Usage
|
||||
|
||||
### User
|
||||
|
||||
Add `--debug` to any command to log every command that is run, along with every file that `tar`, `cpio`, and `unzip` handle. Without it, `--build` is silent unless it fails.
|
||||
|
||||
Install the bundle from the latest [GitHub release](https://github.com/ptitSeb/box64/releases/latest). This only requires `coreutils`, `curl`, and `tar`.
|
||||
|
||||
```
|
||||
sudo ./box64-bundle-x86-libs.sh --install
|
||||
```
|
||||
|
||||
The bundle can also be installed as part of a Box64 installation by turning on the `BUNDLE_X86_LIBS` option. It is off by default. From the `build` directory of a [compiled Box64](COMPILE.md):
|
||||
|
||||
```
|
||||
cmake .. -D BUNDLE_X86_LIBS=ON
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Optionally set the environment variable `DESTDIR` to extract to a different location than `/`.
|
||||
|
||||
```
|
||||
DESTDIR=/tmp/box64 ./box64-bundle-x86-libs.sh --install
|
||||
```
|
||||
|
||||
```
|
||||
make install DESTDIR=/tmp/box64
|
||||
```
|
||||
|
||||
The checksums of the latest release are compared to the local files first. If every file matches, nothing is downloaded. If at least one file is missing or different, the whole bundle is downloaded, extracted, and then verified.
|
||||
|
||||
### Administrator
|
||||
|
||||
Install required dependencies for the bundle script.
|
||||
Build the bundle from Linux distribution packages. Install the required dependencies for the bundle script.
|
||||
|
||||
- Arch Linux
|
||||
```
|
||||
@@ -23,11 +53,11 @@ Install required dependencies for the bundle script.
|
||||
sudo dnf install binutils coreutils curl tar zstd
|
||||
```
|
||||
|
||||
Run `box64-bundle-x86-libs.sh`. This will create two archives:
|
||||
Run `box64-bundle-x86-libs.sh --build`. This will create two archives:
|
||||
- `box64-bundle-x86-libs.tar.gz` = All of the extracted library files in the directory structure of `usr/lib/box64-i386-linux-gnu` and `usr/lib/box64-x86_64-linux-gnu`.
|
||||
- `box64-bundle-x86-pkgs.tar.gz` = All of the Linux distribution packages used to extract the library files. This is only created for preservation purposes and is otherwise unused.
|
||||
|
||||
Extract the library archive. Box will automatically search these paths for library files to emulate.
|
||||
Extract the library archive manually. Box will automatically search these paths for library files to emulate.
|
||||
|
||||
```
|
||||
sudo tar --extract --no-same-owner --file box64-bundle-x86-libs.tar.gz --directory /
|
||||
@@ -48,13 +78,13 @@ Preference of operating system packages that provide a library:
|
||||
2. DEBs from Debian 11 provide 5 years of updates.
|
||||
3. EOPKG from Solus provide old variants of obscure 32-bit libraries.
|
||||
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
|
||||
5. Other (whereever a library is packaged)
|
||||
5. Other (wherever a library is packaged)
|
||||
|
||||
Some essential libraries will always be emulated and should be bundled. The full list can be found in the [in the core source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/core.c#L413).
|
||||
|
||||
Some essential library files will never be emulated (only natively wrapped instead) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/librarian/library.c#L440). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
|
||||
For finding package names that contian a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
For finding package names that contain a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
- DEB
|
||||
- `apt-file <LIBRARY_FILE>`
|
||||
- EOPKG
|
||||
|
||||
+3
-2
@@ -32,8 +32,9 @@ If you also want binfmt integration on 32bits binaries, you also need to add `-D
|
||||
|
||||
### Note about WowBox64
|
||||
|
||||
A highly experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
|
||||
An experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
|
||||
It will build alongside the regular Box64, and produce a `wowbox64.dll` file in `build/wowbox64-prefix/src/wowbox64-build/` directory.
|
||||
You can also add ̀`-DNOOX64=ON` to not build the main box64 binary to save compilation time if you plan to only use the wowbox64 dll.
|
||||
|
||||
### Note about binfmt_misc on Android
|
||||
|
||||
@@ -294,7 +295,7 @@ Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
|
||||
#### Save memory at run time
|
||||
|
||||
You can use `-DSAVE_MEM=ON` to build Box64 with memory-saving optimizations. This uses a five-level jump table to reduce unused address-space allocations and enables secondary entry points (BOX64_DYNAREC_SEP=1) by default to reduce duplicate DynaRec blocks. These optimizations may reduce memory usage at the cost of additional memory accesses and lower performance on some workloads.
|
||||
You can use `-DSAVE_MEM=ON` to build Box64 with memory-saving optimizations. This uses a five-level jump table to reduce unused address-space allocations, which may reduce memory usage at the cost of additional memory accesses and lower performance on some workloads.
|
||||
|
||||
#### Build outside of a git repo
|
||||
|
||||
|
||||
+8
-29
@@ -80,14 +80,7 @@ Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
* 0: Do not optimize CALL/RET, use jump table.
|
||||
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0: Do not add SEP at CALLRET return [Default]
|
||||
* 1: Add SEP at CALLRET return, on memory that are from known binary files
|
||||
* 2: Add SEP at CALLRET return for all type of memory.
|
||||
* 3: Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
@@ -312,13 +305,6 @@ Specify the CPU type to emulate. Available in WowBox64.
|
||||
* 0: Emulate a Intel CPU Model. [Default]
|
||||
* 1: Emulate a AMD CPU Model.
|
||||
|
||||
### BOX64_CRASHHANDLER
|
||||
|
||||
Use a dummy crash handler or not.
|
||||
|
||||
* 0: Use emulated crashhandler.so library if needed.
|
||||
* 1: Use an internal dummy (empty) crashhandler.so library. [Default]
|
||||
|
||||
### BOX64_DYNAREC_BLEEDING_EDGE
|
||||
|
||||
Detect MonoBleedingEdge and apply conservative settings (Linux only).
|
||||
@@ -419,6 +405,13 @@ Do not load any rc files.
|
||||
* 0: Load rc files. [Default]
|
||||
* 1: Do not load any rc files.
|
||||
|
||||
### BOX64_ONDEMAND_STEAMUI
|
||||
|
||||
Close the Steam UI while a game is running, and reopen it when the game is closed.
|
||||
|
||||
* 0: Disabled. [Default]
|
||||
* 1: Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.
|
||||
|
||||
### BOX64_PATH
|
||||
|
||||
Path to look for x86_64 binaries.
|
||||
@@ -822,20 +815,6 @@ Add an environment variable.
|
||||
|
||||
## Fragile or Legacy
|
||||
|
||||
### BOX64_DYNAREC_PURGE
|
||||
|
||||
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
|
||||
|
||||
* 0: DynaRec will not purge old unused DynaBlocks. [Default]
|
||||
* 1: DynaRec will purge old unused DynaBlocks based on tick age.
|
||||
|
||||
### BOX64_DYNAREC_PURGE_AGE
|
||||
|
||||
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
|
||||
* 4096: Default age threshold. [Default]
|
||||
* XXXX: Custom age threshold (range: 10-65536).
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
|
||||
|
||||
+8
-29
@@ -80,14 +80,7 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 0: 不优化 CALL/RET,使用跳转表。
|
||||
* 1: 尝试优化 CALL/RET,在可能的情况下跳过跳转表。
|
||||
* 2: 尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不在 CALLRET 返回时添加 SEP。 [默认值]
|
||||
* 1: 在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。
|
||||
* 2: 在 CALLRET 返回时添加 SEP,适用于所有类型的内存。
|
||||
* 3: 在 2 的基础上,额外跟踪代码块的使用情况,避免回收仍在使用中的代码块。
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
@@ -245,20 +238,6 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
|
||||
|
||||
## 不稳定或遗留选项
|
||||
|
||||
### BOX64_DYNAREC_PURGE
|
||||
|
||||
根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。
|
||||
|
||||
* 0: DynaRec 不会清除旧的未使用代码块。 [默认值]
|
||||
* 1: DynaRec 将根据年龄阈值清除旧的未使用代码块。
|
||||
|
||||
### BOX64_DYNAREC_PURGE_AGE
|
||||
|
||||
代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。
|
||||
|
||||
* 4096: 默认年龄阈值。 [默认值]
|
||||
* XXXX: 自定义年龄阈值(范围:10-65536)。
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
是否等待代码块构建完成。 在 WowBox64 中可用。
|
||||
@@ -313,13 +292,6 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
|
||||
* 0: 模拟某个 Intel CPU 型号。 [默认值]
|
||||
* 1: 模拟某个 AMD CPU 型号。
|
||||
|
||||
### BOX64_CRASHHANDLER
|
||||
|
||||
是否使用模拟的 crashhandler.so 库。
|
||||
|
||||
* 0: 在需要时使用模拟的 crashhandler.so 库。
|
||||
* 1: 使用内部定义的空 crashhandler.so 库。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_BLEEDING_EDGE
|
||||
|
||||
检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。
|
||||
@@ -420,6 +392,13 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
|
||||
* 0: 加载 rc 文件。 [默认值]
|
||||
* 1: 不加载任何 rc 文件。
|
||||
|
||||
### BOX64_ONDEMAND_STEAMUI
|
||||
|
||||
在游戏运行时关闭 Steam UI,游戏结束后重新打开。
|
||||
|
||||
* 0: 禁用。 [默认值]
|
||||
* 1: 在游戏运行时关闭 Steam UI,游戏结束后重新打开。
|
||||
|
||||
### BOX64_PATH
|
||||
|
||||
查找 x86_64 二进制文件的路径。
|
||||
|
||||
+10
-34
@@ -118,14 +118,6 @@ Specify the CPU type to emulate. Available in WowBox64.
|
||||
* 1 : Emulate a AMD CPU Model.
|
||||
|
||||
|
||||
=item B<BOX64_CRASHHANDLER> =I<0|1>
|
||||
|
||||
Use a dummy crash handler or not.
|
||||
|
||||
* 0 : Use emulated crashhandler.so library if needed.
|
||||
* 1 : Use an internal dummy (empty) crashhandler.so library. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DLSYM_ERROR> =I<0|1>
|
||||
|
||||
Enable or disable the logging of dlsym errors.
|
||||
@@ -176,22 +168,14 @@ Detect MonoBleedingEdge and apply conservative settings (Linux only).
|
||||
* 1 : Detect MonoBleedingEdge and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2>
|
||||
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2|3>
|
||||
|
||||
Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
|
||||
* 0 : Do not optimize CALL/RET, use jump table.
|
||||
* 1 : Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SEP> =I<0|1|2>
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0 : Do not add SEP at CALLRET return [Default]
|
||||
* 1 : Add SEP at CALLRET return, on memory that are from known binary files
|
||||
* 2 : Add SEP at CALLRET return for all type of memory.
|
||||
* 3 : Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DF> =I<0|1>
|
||||
@@ -345,22 +329,6 @@ Generate map file for Linux perf tool.
|
||||
* 1 : DynaRec will generate perf map.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PURGE> =I<0|1>
|
||||
|
||||
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
|
||||
|
||||
* 0 : DynaRec will not purge old unused DynaBlocks. [Default]
|
||||
* 1 : DynaRec will purge old unused DynaBlocks based on tick age.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PURGE_AGE> =I<4096|XXXX>
|
||||
|
||||
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
|
||||
* 4096 : Default age threshold. [Default]
|
||||
* XXXX : Custom age threshold (range: 10-65536).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Available in WowBox64.
|
||||
@@ -771,6 +739,14 @@ Do not load x64 Vulkan overlay.
|
||||
* 1 : Do not load x64 Vulkan overlay.
|
||||
|
||||
|
||||
=item B<BOX64_ONDEMAND_STEAMUI> =I<0|1>
|
||||
|
||||
Close the Steam UI while a game is running, and reopen it when the game is closed.
|
||||
|
||||
* 0 : Disabled. [Default]
|
||||
* 1 : Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.
|
||||
|
||||
|
||||
=item B<BOX64_PATH> =I<XXXX>
|
||||
|
||||
Path to look for x86_64 binaries.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Usage: python gen.py
|
||||
|
||||
import json
|
||||
|
||||
+22
-79
@@ -161,25 +161,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_CRASHHANDLER",
|
||||
"description": "Use a dummy crash handler or not.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"configurator": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Use emulated crashhandler.so library if needed.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Use an internal dummy (empty) crashhandler.so library.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DLSYM_ERROR",
|
||||
"description": "Enable or disable the logging of dlsym errors.",
|
||||
@@ -325,29 +306,10 @@
|
||||
"key": "2",
|
||||
"description": "Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_SEP",
|
||||
"description": "Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"configurator": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not add SEP at CALLRET return",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Add SEP at CALLRET return, on memory that are from known binary files",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "Add SEP at CALLRET return for all type of memory.",
|
||||
"key": "3",
|
||||
"description": "Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
@@ -750,44 +712,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_PURGE",
|
||||
"description": "Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).",
|
||||
"category": "Fragile or Legacy",
|
||||
"wine": false,
|
||||
"configurator": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "DynaRec will not purge old unused DynaBlocks.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "DynaRec will purge old unused DynaBlocks based on tick age.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_PURGE_AGE",
|
||||
"description": "Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).",
|
||||
"category": "Fragile or Legacy",
|
||||
"wine": false,
|
||||
"configurator": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "4096",
|
||||
"description": "Default age threshold.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "XXXX",
|
||||
"description": "Custom age threshold (range: 10-65536).",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_SAFEFLAGS",
|
||||
"description": "Behaviour of flags emulation on CALL/RET opcodes and other edge cases.",
|
||||
@@ -1788,6 +1712,25 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_ONDEMAND_STEAMUI",
|
||||
"description": "Close the Steam UI while a game is running, and reopen it when the game is closed.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"configurator": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Disabled.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_PATH",
|
||||
"description": "Path to look for x86_64 binaries.",
|
||||
@@ -2484,4 +2427,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
+10
-31
@@ -57,13 +57,6 @@
|
||||
"1": "模拟某个 AMD CPU 型号。"
|
||||
}
|
||||
},
|
||||
"BOX64_CRASHHANDLER": {
|
||||
"description": "是否使用模拟的 crashhandler.so 库。",
|
||||
"options": {
|
||||
"0": "在需要时使用模拟的 crashhandler.so 库。",
|
||||
"1": "使用内部定义的空 crashhandler.so 库。"
|
||||
}
|
||||
},
|
||||
"BOX64_DLSYM_ERROR": {
|
||||
"description": "启用或禁用 dlsym 错误的日志记录。",
|
||||
"options": {
|
||||
@@ -113,15 +106,8 @@
|
||||
"options": {
|
||||
"0": "不优化 CALL/RET,使用跳转表。",
|
||||
"1": "尝试优化 CALL/RET,在可能的情况下跳过跳转表。",
|
||||
"2": "尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_SEP": {
|
||||
"description": "使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。",
|
||||
"options": {
|
||||
"0": "不在 CALLRET 返回时添加 SEP。",
|
||||
"1": "在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。",
|
||||
"2": "在 CALLRET 返回时添加 SEP,适用于所有类型的内存。"
|
||||
"2": "尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。",
|
||||
"3": "在 2 的基础上,额外跟踪代码块的使用情况,避免回收仍在使用中的代码块。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_DF": {
|
||||
@@ -258,20 +244,6 @@
|
||||
"1": "DynaRec 将生成 perf 映射。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_PURGE": {
|
||||
"description": "根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。",
|
||||
"options": {
|
||||
"0": "DynaRec 不会清除旧的未使用代码块。",
|
||||
"1": "DynaRec 将根据年龄阈值清除旧的未使用代码块。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_PURGE_AGE": {
|
||||
"description": "代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。",
|
||||
"options": {
|
||||
"4096": "默认年龄阈值。",
|
||||
"XXXX": "自定义年龄阈值(范围:10-65536)。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_SAFEFLAGS": {
|
||||
"description": "在 CALL/RET 指令和其他边缘情况下 FLAGS 模拟的行为。",
|
||||
"options": {
|
||||
@@ -625,6 +597,13 @@
|
||||
"1": "不加载 x64 Vulkan 覆盖层。"
|
||||
}
|
||||
},
|
||||
"BOX64_ONDEMAND_STEAMUI": {
|
||||
"description": "在游戏运行时关闭 Steam UI,游戏结束后重新打开。",
|
||||
"options": {
|
||||
"0": "禁用。",
|
||||
"1": "在游戏运行时关闭 Steam UI,游戏结束后重新打开。"
|
||||
}
|
||||
},
|
||||
"BOX64_PATH": {
|
||||
"description": "查找 x86_64 二进制文件的路径。",
|
||||
"options": {
|
||||
@@ -873,4 +852,4 @@
|
||||
"1": "不为 32 位二进制文件切换 personality。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "gdbjit.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static char block_name_buffer[16];
|
||||
static char block_name_buffer[2 * sizeof(uintptr_t) + 1];
|
||||
|
||||
static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz)
|
||||
{
|
||||
@@ -9,7 +11,7 @@ static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb
|
||||
|
||||
struct gdb_object* object = cbs->object_open(cbs);
|
||||
struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, block->filename);
|
||||
sprintf(block_name_buffer, "%x", block->x64start);
|
||||
sprintf(block_name_buffer, "%" PRIxPTR, block->x64start);
|
||||
cbs->block_open(cbs, symtab, NULL, block->start, block->end, block_name_buffer);
|
||||
|
||||
cbs->line_mapping_add(cbs, symtab, block->nlines, block->lines);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# create necessary directories
|
||||
mkdir -p ~/steam/tmp # makes both ~/steam and ~/steam/tmp in one cmd
|
||||
|
||||
+7
-1
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -416,8 +417,12 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("libc", "androidshmem") \
|
||||
or match("libc", "mimalloc") \
|
||||
or match("crypto", "libssl3") \
|
||||
or match("tcmallocminimal", "tbbmallocproxy") \
|
||||
or match("tcmallocminimal", "mimalloc") \
|
||||
or match("tbbmallocproxy", "mimalloc") \
|
||||
or match("libbsd", "mimalloc") \
|
||||
or match("iconv", "libunistring2") \
|
||||
or match("gomp", "libomp"):
|
||||
continue
|
||||
@@ -1094,7 +1099,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"""
|
||||
}
|
||||
|
||||
banner = "/********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
banner = "// SPDX-License-Identifier: MIT\n" \
|
||||
"/********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
" * File automatically generated by rebuild_wrappers.py (v" + ver + ") *\n" \
|
||||
" ********************************************************" + ('*'*len(ver)) + "***/\n"
|
||||
trim = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -1405,7 +1406,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
#endif // __{filename}UNDEFS32_H_
|
||||
"""
|
||||
}
|
||||
banner = "/***********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
banner = "// SPDX-License-Identifier: MIT\n" \
|
||||
"/***********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
" * File automatically generated by rebuild_wrappers_32.py (v" + ver + ") *\n" \
|
||||
" ***********************************************************" + ('*'*len(ver)) + "***/\n"
|
||||
trim: Callable[[str], str] = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
+12
-1
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -349,6 +350,8 @@ void FreeBox64Context(box64context_t** context)
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
|
||||
box_free(ctx->quick_cleanups);
|
||||
|
||||
for(int i=0; i<MAX_SIGNAL; ++i)
|
||||
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
|
||||
signal(i, SIG_DFL);
|
||||
@@ -437,6 +440,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
int idx = 0;
|
||||
mutex_lock(&ctx->mutex_tls);
|
||||
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
|
||||
if(idx == ctx->elfsize) {
|
||||
if(idx==ctx->elfcap) {
|
||||
@@ -449,11 +453,13 @@ int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
} else {
|
||||
ctx->elfs[idx] = head;
|
||||
}
|
||||
mutex_unlock(&ctx->mutex_tls);
|
||||
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
mutex_lock(&ctx->mutex_tls);
|
||||
if(GetTLSBase(head)) {
|
||||
// should remove the tls info
|
||||
int tlsbase = GetTLSBase(head);
|
||||
@@ -465,19 +471,24 @@ void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
for(int i=0; i<ctx->elfsize; ++i)
|
||||
if(ctx->elfs[i] == head) {
|
||||
ctx->elfs[i] = NULL;
|
||||
mutex_unlock(&ctx->mutex_tls);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&ctx->mutex_tls);
|
||||
}
|
||||
|
||||
int AddTLSPartition(box64context_t* context, int tlssize) {
|
||||
mutex_lock(&context->mutex_tls);
|
||||
int oldsize = context->tlssize;
|
||||
// should in fact first try to map a hole, but rewinding all elfs and checking filled space, like with the mapmem utilities
|
||||
context->tlssize += tlssize;
|
||||
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
|
||||
int ret = -context->tlssize; // negative offset
|
||||
mutex_unlock(&context->mutex_tls);
|
||||
// clean GS segment for current emu?
|
||||
|
||||
return -context->tlssize; // negative offset
|
||||
return ret;
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __BOX64_VERSION_H_
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 4
|
||||
#define BOX64_REVISION 4
|
||||
#define BOX64_REVISION 5
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
#include "box64version.h"
|
||||
|
||||
+4
-1
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "box64version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
@@ -28,7 +29,9 @@ void PrintBox64Version(int prefix);
|
||||
#define BOX64_BUILD_INFO_STR_HELPER(x) #x
|
||||
#define BOX64_BUILD_INFO_STR(x) BOX64_BUILD_INFO_STR_HELPER(x)
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef BOX64EC
|
||||
#define BOX64_STR "Box64EC"
|
||||
#elif defined(_WIN32)
|
||||
#define BOX64_STR "WowBox64"
|
||||
#else
|
||||
#define BOX64_STR "Box64"
|
||||
|
||||
+22
-4
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
@@ -29,6 +31,7 @@
|
||||
#include "debug.h"
|
||||
#include "fileutils.h"
|
||||
#include "box64context.h"
|
||||
#include "steamwebhelper.h"
|
||||
#include "box64cpu.h"
|
||||
#include "box64cpu_util.h"
|
||||
#include "wine_tools.h"
|
||||
@@ -57,6 +60,7 @@ extern box64env_t box64env;
|
||||
|
||||
int box64_quit = 0;
|
||||
int box64_exit_code = 0;
|
||||
int box64_in_fatal_handler = 0;
|
||||
int box64_stdout_no_w = 0;
|
||||
uintptr_t box64_pagesize;
|
||||
path_collection_t box64_addlibs = {0};
|
||||
@@ -68,6 +72,7 @@ int box64_mapclean = 0;
|
||||
int box64_zoom = 0;
|
||||
int box64_steam = 0;
|
||||
int box64_steamcmd = 0;
|
||||
int box64_srt_logger = 0;
|
||||
int box64_musl = 0;
|
||||
int box64_nolibs = 0;
|
||||
int box64_hasinterp = 0;
|
||||
@@ -355,10 +360,10 @@ void KillAllInstances()
|
||||
struct dirent* entry;
|
||||
ssize_t len;
|
||||
char proc_path[PATH_MAX];
|
||||
char exe_path[PATH_MAX];
|
||||
char exe_path[PATH_MAX+8];
|
||||
char exe_target[PATH_MAX];
|
||||
char self_name[PATH_MAX];
|
||||
char self_name_with_deleted[PATH_MAX];
|
||||
char self_name_with_deleted[PATH_MAX+16];
|
||||
|
||||
DIR* proc_dir = opendir("/proc");
|
||||
if (proc_dir == NULL) {
|
||||
@@ -726,6 +731,8 @@ void endBox64()
|
||||
x64emu_t* emu = thread_get_emu();
|
||||
void startTimedExit();
|
||||
startTimedExit();
|
||||
printf_log(LOG_DEBUG, "Calling thread_local destructors (exiting box64)\n");
|
||||
CallThreadCleanup(emu);
|
||||
// atexit first
|
||||
printf_log(LOG_DEBUG, "Calling atexit registered functions (exiting box64)\n");
|
||||
CallAllCleanup(emu);
|
||||
@@ -738,14 +745,14 @@ void endBox64()
|
||||
// unload needed libs
|
||||
needed_libs_t* needed = my_context->elfs[0]->needed;
|
||||
printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0);
|
||||
int workers = get_active_emu_workers();
|
||||
int workers = atomic_load_explicit(&g_active_emu_workers, memory_order_relaxed);
|
||||
if (workers > 0) {
|
||||
const int sleep_us = 10000; // 10ms
|
||||
const int max_wait_ms = 2000; // 2s
|
||||
int waited_ms = 0;
|
||||
|
||||
printf_log(LOG_DEBUG, "endBox64: waiting emu workers to exit (n=%d)\n", workers);
|
||||
while ((workers = get_active_emu_workers()) > 0 && waited_ms < max_wait_ms) {
|
||||
while ((workers = atomic_load_explicit(&g_active_emu_workers, memory_order_relaxed)) > 0 && waited_ms < max_wait_ms) {
|
||||
usleep(sleep_us);
|
||||
waited_ms += sleep_us / 1000;
|
||||
}
|
||||
@@ -1008,11 +1015,16 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
} else if(!strcmp(prog_, "steamcmd")) {
|
||||
printf_log(LOG_INFO, "steamcmd detected\n");
|
||||
box64_steamcmd = 1;
|
||||
} else if(!strcmp(prog_, "srt-logger")) {
|
||||
box64_srt_logger = 1;
|
||||
} else if(!strcmp(prog_, "wineserver")) {
|
||||
// check if this is wineserver
|
||||
box64_wine = 1;
|
||||
}
|
||||
// Create a new context
|
||||
#ifdef BOX32
|
||||
box64_is32bits = FileIsX86ELF(prog);
|
||||
#endif
|
||||
my_context = NewBox64Context(argc - nextarg);
|
||||
|
||||
addLibPaths(my_context);
|
||||
@@ -1178,6 +1190,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
printf_log(LOG_INFO, "Applied settings from rcfile\n");
|
||||
displayMiscInfo();
|
||||
}
|
||||
if (BOX64ENV(ondemand_steamui) && (!strcmp(box64_guest_name, "steam") || !strcmp(box64_guest_name, "steamwebhelper")))
|
||||
StartOnDemandSteamUI();
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
setupZydis(my_context);
|
||||
|
||||
@@ -1326,6 +1340,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
int script = my_context->bashpath?FileIsShell(my_context->fullpath):0;
|
||||
int python3 = my_context->pythonpath?FileIsPython(my_context->fullpath):0;
|
||||
printf_log(LOG_NONE, "Error: Reading elf header of %s, Try to launch %s instead\n", my_context->fullpath, x86?"using box86":(script?"using bash":"natively"));
|
||||
#ifndef BOX32
|
||||
if(!x86 && !my_context->box86path && FileIsX86ELF(my_context->fullpath))
|
||||
printf_log(LOG_NONE, "Maybe you should enable BOX32 when building Box64 to enable 32bits program to be run\n");
|
||||
#endif
|
||||
fclose(f);
|
||||
FreeCollection(&ld_preload);
|
||||
int ret;
|
||||
|
||||
+438
-266
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_EMITTER_H__
|
||||
#define __ARM64_EMITTER_H__
|
||||
/*
|
||||
@@ -229,25 +230,25 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define LDURSBx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, 0b10, imm9, Rn, Rt))
|
||||
#define LDURSBxw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, (rex.w)?0b10:0b11, imm9, Rn, Rt))
|
||||
|
||||
#define LDxw(A, B, C) if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}
|
||||
#define LDz(A, B, C) if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}
|
||||
#define LDx(A, B, C) if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}
|
||||
#define LDW(A, B, C) if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}
|
||||
#define LDH(A, B, C) if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}
|
||||
#define LDB(A, B, C) if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}
|
||||
#define LDSW(A, B, C) if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}
|
||||
#define LDSHxw(A, B, C) if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}
|
||||
#define LDSHx(A, B, C) if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}
|
||||
#define LDSHw(A, B, C) if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}
|
||||
#define LDSBxw(A, B, C) if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}
|
||||
#define LDSBx(A, B, C) if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}
|
||||
#define LDSBw(A, B, C) if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}
|
||||
#define STxw(A, B, C) if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}
|
||||
#define STz(A, B, C) if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}
|
||||
#define STx(A, B, C) if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}
|
||||
#define STW(A, B, C) if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}
|
||||
#define STH(A, B, C) if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}
|
||||
#define STB(A, B, C) if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}
|
||||
#define LDxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURxw(A, B, C);} else if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}} while(0)
|
||||
#define LDz(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURz(A, B, C);} else if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}} while(0)
|
||||
#define LDx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURx(A, B, C);} else if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}} while(0)
|
||||
#define LDW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURw(A, B, C);} else if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}} while(0)
|
||||
#define LDH(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURH(A, B, C);} else if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}} while(0)
|
||||
#define LDB(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURB(A, B, C);} else if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}} while(0)
|
||||
#define LDSW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSW(A, B, C);} else if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}} while (0)
|
||||
#define LDSHxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHxw(A, B, C);} else if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}} while (0)
|
||||
#define LDSHx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHx(A, B, C);} else if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}} while (0)
|
||||
#define LDSHw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHw(A, B, C);} else if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}} while (0)
|
||||
#define LDSBxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBxw(A, B, C);} else if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}} while (0)
|
||||
#define LDSBx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBx(A, B, C);} else if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}} while (0)
|
||||
#define LDSBw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBw(A, B, C);} else if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}} while (0)
|
||||
#define STxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURxw(A, B, C);} else if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}} while(0)
|
||||
#define STz(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURz(A, B, C);} else if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}} while(0)
|
||||
#define STx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURx(A, B, C);} else if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}} while(0)
|
||||
#define STW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURw(A, B, C);} else if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}} while(0)
|
||||
#define STH(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURH(A, B, C);} else if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}} while(0)
|
||||
#define STB(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURB(A, B, C);} else if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}} while(0)
|
||||
|
||||
// STR
|
||||
#define STR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b00<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -463,9 +464,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define CSINVx(Rd, Rn, Rm, cond) EMIT(CSINV_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSINVw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invCond(cond))
|
||||
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invCond(cond))
|
||||
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invCond(cond))
|
||||
#define CSETMx(Rd, cond) CSINVx(Rd, xZR, xZR, invCond(cond))
|
||||
#define CSETMw(Rd, cond) CSINVw(Rd, xZR, xZR, invCond(cond))
|
||||
#define CSETMxw(Rd, cond) CSINVxw(Rd, xZR, xZR, invCond(cond))
|
||||
@@ -479,9 +480,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define CSNEGx(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSNEGw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSNEGxw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CNEGx(Rd, Rn, cond) CSNEGx(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGw(Rd, Rn, cond) CSNEGw(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGx(Rd, Rn, cond) CSNEGx(Rd, Rn, Rn, invCond(cond))
|
||||
#define CNEGw(Rd, Rn, cond) CSNEGw(Rd, Rn, Rn, invCond(cond))
|
||||
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rd, Rn, Rn, invCond(cond))
|
||||
|
||||
// AND / ORR
|
||||
#define LOGIC_gen(sf, opc, N, immr, imms, Rn, Rd) ((sf)<<31 | (opc)<<29 | 0b100100<<23 | (N)<<22 | (immr)<<16 | (imms)<<10 | (Rn)<<5 | Rd)
|
||||
@@ -648,9 +649,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define ASRx(Rd, Rn, shift) SBFMx(Rd, Rn, shift, 63)
|
||||
#define ASRw(Rd, Rn, shift) SBFMw(Rd, Rn, shift, 31)
|
||||
#define ASRxw(Rd, Rn, shift) SBFMxw(Rd, Rn, shift, rex.w?63:31)
|
||||
#define SBFIZx(Rd, Rn, lsb, width) SFBFMx(Rd, Rn, ((-(lsb))%64), (width)-1)
|
||||
#define SBFIZw(Rd, Rn, lsb, width) SFBFMw(Rd, Rn, ((-(lsb))%32), (width)-1)
|
||||
#define SBFIZxw(Rd, Rn, lsb, width) SFBFMxw(Rd, Rn, ((-(lsb))%(rex.w?64:32)), (width)-1)
|
||||
#define SBFIZx(Rd, Rn, lsb, width) SBFMx(Rd, Rn, ((-(lsb))%64), (width)-1)
|
||||
#define SBFIZw(Rd, Rn, lsb, width) SBFMw(Rd, Rn, ((-(lsb))%32), (width)-1)
|
||||
#define SBFIZxw(Rd, Rn, lsb, width) SBFMxw(Rd, Rn, ((-(lsb))%(rex.w?64:32)), (width)-1)
|
||||
|
||||
// EXTR
|
||||
#define EXTR_gen(sf, N, Rm, imms, Rn, Rd) ((sf)<<31 | 0b00<<29 | 0b100111<<23 | (N)<<22 | (Rm)<<16 | (imms)<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -827,26 +828,26 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
|
||||
|
||||
#define VLD128(A, B, C) if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}
|
||||
#define VLD64(A, B, C) if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}
|
||||
#define VLD32(A, B, C) if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}
|
||||
#define VLD16(A, B, C) if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}
|
||||
#define VLD8(A, B, C) if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}
|
||||
#define VST128(A, B, C) if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}
|
||||
#define VST64(A, B, C) if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}
|
||||
#define VST32(A, B, C) if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}
|
||||
#define VST16(A, B, C) if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}
|
||||
#define VST8(A, B, C) if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}
|
||||
#define VLD128(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR128(A, B, C);} else if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}} while(0)
|
||||
#define VLD64(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR64(A, B, C);} else if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}} while(0)
|
||||
#define VLD32(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR32(A, B, C);} else if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}} while(0)
|
||||
#define VLD16(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR16(A, B, C);} else if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}} while(0)
|
||||
#define VLD8(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR8(A, B, C);} else if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}} while(0)
|
||||
#define VST128(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR128(A, B, C);} else if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}} while (0)
|
||||
#define VST64(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR64(A, B, C);} else if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}} while (0)
|
||||
#define VST32(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR32(A, B, C);} else if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}} while (0)
|
||||
#define VST16(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR16(A, B, C);} else if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}} while (0)
|
||||
#define VST8(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR8(A, B, C);} else if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}} while (0)
|
||||
|
||||
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VLDR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VLDR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b11, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VLDR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b11, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VLDR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b11, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VLDR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b11, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VSTR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VSTR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b00, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VSTR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b10, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VSTR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b10, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VSTR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b10, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VSTR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b10, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
|
||||
#define VMEM_REG_gen(size, opc, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
|
||||
|
||||
@@ -902,7 +903,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VEORQ(Vd, Vn, Vm) EMIT(VLOGIC_gen(1, 0b00, Vm, Vn, Vd))
|
||||
#define VEOR(Vd, Vn, Vm) EMIT(VLOGIC_gen(0, 0b00, Vm, Vn, Vd))
|
||||
|
||||
#define VLOGIC_immediate(Q, op, abc, cmade, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
#define VLOGIC_immediate(Q, op, abc, cmode, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
//#define V
|
||||
|
||||
#define SHL_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -962,7 +963,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VEXTQ_8(Rd, Rn, Rm, index) EMIT(EXT_vector(1, Rm, index, Rn, Rd))
|
||||
|
||||
// Shift Left and Insert (not touching lower part of dest)
|
||||
#define SLI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<1 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSLI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSLIQ_8(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0001, (shift)&7, Vn, Vd))
|
||||
#define VSLIQ_16(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSLIQ_32(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
@@ -972,14 +973,14 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VSLI_32(Vd, Vn, shift) EMIT(VSLI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
|
||||
// Shift Right and Insert (not touching higher part of dest)
|
||||
#define SRI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01000<<1 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSRIQ_8(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0001, (shift)&7, Vn, Vd))
|
||||
#define VSRIQ_16(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSRIQ_32(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
#define VSRIQ_64(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b1000 | (((shift)>>3)&7), (shift)&7, Vn, Vd))
|
||||
#define VSRI_8(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0001, (shift)&7, Vn, Vd))
|
||||
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
#define VSRI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01000<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSRIQ_8(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0001, (8-(shift))&7, Vn, Vd))
|
||||
#define VSRIQ_16(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0010 | ((16-(shift))>>3)&1, (16-(shift))&7, Vn, Vd))
|
||||
#define VSRIQ_32(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0100 | ((32-(shift))>>3)&3, (32-(shift))&7, Vn, Vd))
|
||||
#define VSRIQ_64(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b1000 | ((64-(shift))>>3)&7, (64-(shift))&7, Vn, Vd))
|
||||
#define VSRI_8(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0001, (8-(shift))&7, Vn, Vd))
|
||||
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((16-(shift))>>3)&1, (16-(shift))&7, Vn, Vd))
|
||||
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | ((32-(shift))>>3)&3, (32-(shift))&7, Vn, Vd))
|
||||
|
||||
// Reverse elements in 64-bit doublewords (vector). This instruction reverses the order of 8-bit, 16-bit, or 32-bit elements in each doubleword
|
||||
#define VREVx_vector(Q, U, size, o0, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | (o0)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1044,7 +1045,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// Double-precision to 64-bit
|
||||
#define FMOVxD(Xd, Dn) EMIT(FMOV_general(1, 0b01, 0b00, 0b110, Dn, Xd))
|
||||
// Top half of 128-bit to 64-bit
|
||||
#define FMOVxD1(Xd, Vn) EMIT(FMOV_general(1, 0b10, 0b01, ob110, Vn, Xd))
|
||||
#define FMOVxD1(Xd, Vn) EMIT(FMOV_general(1, 0b10, 0b01, 0b110, Vn, Xd))
|
||||
|
||||
#define FMOV_register(type, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FMOVS(Sd, Sn) EMIT(FMOV_register(0b00, Sn, Sd))
|
||||
@@ -1251,7 +1252,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FCVTMUxwS(Xd, Sn) EMIT(FCVT_scalar(rex.w, 0b00, 0b10, 0b101, Sn, Xd))
|
||||
#define FCVTMUwD(Wd, Dn) EMIT(FCVT_scalar(0, 0b01, 0b10, 0b101, Dn, Wd))
|
||||
#define FCVTMUxD(Xd, Dn) EMIT(FCVT_scalar(1, 0b01, 0b10, 0b101, Dn, Xd))
|
||||
#define FCVTMUxwD(Xd, Dn) EMIT(FCVT_scalar(rfex.w, 0b01, 0b10, 0b101, Dn, Xd))
|
||||
#define FCVTMUxwD(Xd, Dn) EMIT(FCVT_scalar(rex.w, 0b01, 0b10, 0b101, Dn, Xd))
|
||||
// Floating-point Convert to Signed integer, rounding to nearest with ties to even
|
||||
#define FCVTNSwS(Wd, Sn) EMIT(FCVT_scalar(0, 0b00, 0b00, 0b000, Sn, Wd))
|
||||
#define FCVTNSxS(Xd, Sn) EMIT(FCVT_scalar(1, 0b00, 0b00, 0b000, Sn, Xd))
|
||||
@@ -2372,11 +2373,51 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// LRCPC extension
|
||||
|
||||
#define LDAPR_gen(sz, Rn, Rt) ((sz)<<30 | 0b111<<27 | 1<<23 | 1<<21 | 0b11111<<16 | 1<<15 | 0b100<<12 | (Rn)<<5 | (Rt))
|
||||
#define LDAPRx(Rt, Rn) EMIT(LDAPR_gen(0b11, Rn, Rt))
|
||||
#define LDAPRw(Rt, Rn) EMIT(LDAPR_gen(0b10, Rn, Rt))
|
||||
#define LDAPRxw(Rt, Rn) EMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
|
||||
#define LDAPRz(Rt, Rn) EMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
|
||||
#define LDAPRH(Rt, Rn) EMIT(LDAPR_gen(0b01, Rn, Rt))
|
||||
#define LDAPRB(Rt, Rn) EMIT(LDAPR_gen(0b00, Rn, Rt))
|
||||
#define LDAPRx(Rt, Rn) LEMIT(LDAPR_gen(0b11, Rn, Rt))
|
||||
#define LDAPRw(Rt, Rn) LEMIT(LDAPR_gen(0b10, Rn, Rt))
|
||||
#define LDAPRxw(Rt, Rn) LEMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
|
||||
#define LDAPRz(Rt, Rn) LEMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
|
||||
#define LDAPRH(Rt, Rn) LEMIT(LDAPR_gen(0b01, Rn, Rt))
|
||||
#define LDAPRB(Rt, Rn) LEMIT(LDAPR_gen(0b00, Rn, Rt))
|
||||
|
||||
// LRCPC2 extension
|
||||
|
||||
#define LRCPC2_gen(sz, opc, imm9, Rn, Rt) ((sz)<<30 | 0b011001<<24 | (opc)<<22 | ((imm9)&0b111111111)<<12 | (Rn)<<5 | (Rt))
|
||||
#define STLURx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STLURw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b00, imm9, Rn, Rt))
|
||||
#define STLURxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10+rex.w, 0b00, imm9, Rn, Rt))
|
||||
#define STLURz(Rt, Rn, imm9) LEMIT(LRCPC2_gen(rex.is32bits?0b10:0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STLURH(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b00, imm9, Rn, Rt))
|
||||
#define STLURB(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b00, imm9, Rn, Rt))
|
||||
|
||||
#define LDAPURx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b11, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10+rex.w, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURz(Rt, Rn, imm9) LEMIT(LRCPC2_gen(rex.is32bits?0b10:0b11, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURH(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURB(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURSW(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b10, imm9, Rn, Rt))
|
||||
#define LDAPURSHw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b11, imm9, Rn, Rt))
|
||||
#define LDAPURSHx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b10, imm9, Rn, Rt))
|
||||
#define LDAPURSHxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, rex.w?0b10:0b11, imm9, Rn, Rt))
|
||||
#define LDAPURSBw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b11, imm9, Rn, Rt))
|
||||
#define LDAPURSBx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b10, imm9, Rn, Rt))
|
||||
#define LDAPURSBxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, rex.w?0b10:0b11, imm9, Rn, Rt))
|
||||
|
||||
#define NOLRCPC() dyn->insts[ninst].use_lrcpc=0
|
||||
|
||||
// LRCPC3 extension
|
||||
#define LRCPC3_gen(sz, opc, imm9, Rn, Rt) ((sz)<<30 | 0b011101<<24 | (opc)<<22 | ((imm9)&0b111111111)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDAPUR128(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b11, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR64(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b11, 0b01, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR32(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b10, 0b01, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR16(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b01, 0b01, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR8(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b01, imm9, Vn, Vt));} while(0)
|
||||
|
||||
#define VSTLUR128(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b10, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR64(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b11, 0b00, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR32(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b10, 0b00, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR16(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b01, 0b00, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR8(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b00, imm9, Vn, Vt));} while(0)
|
||||
|
||||
#endif //__ARM64_EMITTER_H__
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include "arm64_immenc.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_IMMENC_H__
|
||||
#define __ARM64_IMMENC_H__
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm lock helper
|
||||
//there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
@@ -29,6 +30,7 @@
|
||||
.global arm64_lock_decifnot0b
|
||||
.global arm64_lock_storeb
|
||||
.global arm64_lock_incif0
|
||||
.global arm64_lock_inc
|
||||
.global arm64_lock_decifnot0
|
||||
.global arm64_lock_store
|
||||
.global arm64_lock_store_dd
|
||||
@@ -403,6 +405,28 @@ arm64_atomic_incif0:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_inc:
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
tbnz w3, #0, arm64_atomic_inc
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
add w3, w1, #1
|
||||
stlxr w2, w3, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_atomic_inc:
|
||||
mov w1, #1
|
||||
dmb ish
|
||||
ldadd w1, w2, [x0]
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_store:
|
||||
str w1, [x0]
|
||||
dmb ish
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_LOCK__H__
|
||||
#define __ARM64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
@@ -76,8 +77,11 @@ extern void arm64_lock_storeb(void*p, uint8_t b);
|
||||
// increment atomically the int at [p] only if it was 0. Return the old value of [p]
|
||||
extern int arm64_lock_incif0(void*p);
|
||||
|
||||
// increment atomically the int at [p]. Return the old value of [p]
|
||||
extern int arm64_lock_inc(volatile void*p);
|
||||
|
||||
// decrement atomically the int at [p] (but only if p not 0)
|
||||
extern int arm64_lock_decifnot0(void*p);
|
||||
extern int arm64_lock_decifnot0(volatile void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_store(void*p, uint32_t v);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_MAPPING_H__
|
||||
#define __ARM64_MAPPING_H__
|
||||
|
||||
@@ -38,6 +39,32 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#ifdef BOX64EC
|
||||
// x18 is the TEB and x6 is guest R9, the other scratch registers are x1 to x5
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
#define xRBX 8
|
||||
#define xRSP 20
|
||||
#define xRBP 21
|
||||
#define xRSI 16
|
||||
#define xRDI 17
|
||||
#define xR8 15
|
||||
#define xR9 6
|
||||
#define xR10 23
|
||||
#define xR11 9
|
||||
#define xR12 22
|
||||
#define xR13 25
|
||||
#define xR14 26
|
||||
#define xR15 19
|
||||
#define xFlags 7
|
||||
#define xRIP 27
|
||||
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (((uint8_t[]){10, 11, 12, 8, 20, 21, 16, 17, 15, 6, 23, 9, 22, 25, 26, 19})[(A)])
|
||||
#define IS_GPR(A) (((uint8_t[]){0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, \
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0})[(A)])
|
||||
#else
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
@@ -61,6 +88,9 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (xRAX + (A))
|
||||
#define IS_GPR(A) ((A)>=xRAX && (A)<=xRIP)
|
||||
#endif
|
||||
// the Windows platform register, reloaded with the TEB after C calls
|
||||
#define xTEB 18
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
@@ -86,8 +116,14 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define x3 3
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#ifdef BOX64EC
|
||||
#define x6 BOX64EC_x6_IS_GUEST_R9_USE_xR9
|
||||
// x87pc is x5, a normal scratch: BOX64_DYNAREC_X87DOUBLE=2 precision tracking is not supported on Box64EC
|
||||
#define x87pc 5
|
||||
#else
|
||||
#define x6 6
|
||||
#define x87pc 7
|
||||
#endif
|
||||
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
@@ -95,7 +131,11 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define w3 x3
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#ifdef BOX64EC
|
||||
#define w6 BOX64EC_w6_IS_GUEST_R9_USE_wR9
|
||||
#else
|
||||
#define w6 x6
|
||||
#endif
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
|
||||
@@ -14,6 +15,8 @@
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
str x14, [x0, #(8 * 4)] // RSP
|
||||
str x27, [x0, #(8 * 17)] // RIP
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
@@ -47,6 +50,8 @@ arm64_next:
|
||||
arm64_next_invalid:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
str x14, [x0, #(8 * 4)] // RSP
|
||||
str x27, [x0, #(8 * 17)] // RIP
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -208,12 +209,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "001110001x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "011110001x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10111000100iiiiiiiii00nnnnnttttt", &a)) {
|
||||
@@ -221,6 +222,37 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "LDURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x011001010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00011001010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011001010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "000110011x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURSB %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "010110011x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURSH %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10011001100iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x111000000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
@@ -237,6 +269,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "STURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x011001000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STLUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00011001000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STLURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011001000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STLURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x11100101iiiiiiiiiiiinnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = (imm)<<size;
|
||||
@@ -557,22 +605,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "f1001011001mmmmmoooiiinnnnnddddd", &a)) {
|
||||
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
|
||||
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
|
||||
if(((sf==0 && option==2) || (sf==1 && option==3)) && imm==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
|
||||
else if(shift==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
|
||||
else if(imm==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option], imm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0001011001mmmmmoooiiinnnnnddddd", &a)) {
|
||||
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
|
||||
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
|
||||
if(((sf==0 && option==2) || (sf==1 && option==3)) && imm==0)
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
|
||||
else if(shift==0)
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
|
||||
else if(imm==0)
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option], imm);
|
||||
return buff;
|
||||
}
|
||||
// ---- LOGIC
|
||||
@@ -1664,6 +1712,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
// LDAPUR/STLUR
|
||||
if(isMask(opcode, "ff011101cL0iiiiiiiii10nnnnnttttt", &a)) {
|
||||
const char* Y[] = {"B", "H", "S", "D", "Q"};
|
||||
int sz = sf;
|
||||
if(sz==0 && a.c)
|
||||
sz = 4;
|
||||
int offset = signExtend(imm, 9);
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s]", a.L?"LDAP":"STL", Y[sz], Rt, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LDAP":"STL", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
// LDR/STR vector immediate
|
||||
if(isMask(opcode, "ff111101cLiiiiiiiiiiiinnnnnttttt", &a)) {
|
||||
const char* Y[] = {"B", "H", "S", "D", "Q"};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef _ARM_PRINTER_H_
|
||||
#define _ARM_PRINTER_H_
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -36,6 +37,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int32_t i32, tmp;
|
||||
int64_t i64, j64;
|
||||
uint8_t u8;
|
||||
uint8_t f_save;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
@@ -983,8 +985,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
f_save = dyn->f;
|
||||
CALL_S(const_native_br, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
dyn->f = f_save;
|
||||
} else {
|
||||
INST_NAME("Illegal 62");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
@@ -1010,10 +1014,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
// Extract RPL (low 2 bits)
|
||||
UBFXw(x6, ed, 0, 2);
|
||||
UBFXw(x5, ed, 0, 2);
|
||||
UBFXw(x4, gd, 0, 2);
|
||||
// need_update = (dst_rpl < src_rpl)
|
||||
CMPSw_REG(x6, x4);
|
||||
CMPSw_REG(x5, x4);
|
||||
CSETw(x5, cLT);
|
||||
// ZF = need_update
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
@@ -1054,6 +1058,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
TABLE64(x3, addr-4);
|
||||
LDRSW_U12(x1, x3, 0);
|
||||
PUSH1z(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
if (!i64) {
|
||||
PUSH1z(xZR);
|
||||
@@ -1213,7 +1218,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x6E:
|
||||
case 0x6F:
|
||||
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSD");
|
||||
INST_NAME(opcode == 0x6E ? "OUTSB" : "OUTSD");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
@@ -1467,7 +1472,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4);
|
||||
break;
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ed, Gd");
|
||||
@@ -1475,7 +1480,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5, x6);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5);
|
||||
break;
|
||||
case 0x86:
|
||||
INST_NAME("(LOCK)XCHG Eb, Gb");
|
||||
@@ -1602,6 +1607,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else { // mem <= reg
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 0);
|
||||
if(gd==wback) {
|
||||
MOVx_REG(x2, wback);
|
||||
@@ -1614,9 +1620,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// gd restored after that
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << (2 + rex.w), (1 << (2 + rex.w)) - 1, rex, &lock, 0, 0);
|
||||
if(!lock && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
DMB_ISH();
|
||||
lock = 1;
|
||||
if(!lock && !dyn->insts[ninst].use_lrcpc && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
if(!dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat)
|
||||
dyn->insts[ninst].use_lrcpc = 1;
|
||||
else {
|
||||
DMB_ISH();
|
||||
lock = 1;
|
||||
}
|
||||
}
|
||||
STxw(gd, ed, fixedaddress);
|
||||
}
|
||||
@@ -1665,8 +1675,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
if(!lock && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
lock = 1;
|
||||
if(!lock && !dyn->insts[ninst].use_lrcpc && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
if(!dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat)
|
||||
dyn->insts[ninst].use_lrcpc = 1;
|
||||
else
|
||||
lock = 1;
|
||||
}
|
||||
SMREADLOCK(lock);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
@@ -1834,6 +1847,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x9B:
|
||||
INST_NAME("FWAIT");
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, cw));
|
||||
MVNw_REG(x2, x2); // ~CW
|
||||
ANDw_REG(x1, x1, x2); // SW & ~CW
|
||||
MOV32w(x3, 0x3F); // 6 exception flag bits
|
||||
ANDw_REG(x1, x1, x3); // & 0x3F
|
||||
CBZw_MARK3(x1); // no pending unmasked exception
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
break;
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
@@ -2006,6 +2035,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
@@ -2067,8 +2097,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
STRB_U12(x1, xRDI, 0);
|
||||
unscaled = 0;
|
||||
LDB(x1, xRSI, 0);
|
||||
STB(x1, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
@@ -2079,6 +2110,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSD");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
@@ -2103,8 +2135,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
LDRxw_U12(x1, xRSI, 0);
|
||||
STRxw_U12(x1, xRDI, 0);
|
||||
unscaled = 0;
|
||||
LDxw(x1, xRSI, 0);
|
||||
STxw(x1, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
@@ -2122,6 +2155,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
@@ -2144,6 +2178,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSB");
|
||||
@@ -2154,8 +2189,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
SMREAD();
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
LDRB_U12(x2, xRDI, 0);
|
||||
unscaled = 0;
|
||||
LDB(x1, xRSI, 0);
|
||||
LDB(x2, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
@@ -2174,6 +2210,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
@@ -2196,6 +2233,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSD");
|
||||
@@ -2206,8 +2244,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
SMREAD();
|
||||
LDRxw_U12(x1, xRSI, 0);
|
||||
LDRxw_U12(x2, xRDI, 0);
|
||||
unscaled = 0;
|
||||
LDxw(x1, xRSI, 0);
|
||||
LDxw(x2, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
@@ -2219,19 +2258,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTBx(x1, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8c(dyn, ninst, x1, u8, x3, x4);
|
||||
break;
|
||||
case 0xA9:
|
||||
INST_NAME("TEST EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
|
||||
emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
case 0xAA:
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
@@ -2283,7 +2322,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
STRB_U12(xRAX, xRDI, 0);
|
||||
unscaled = 0;
|
||||
STB(xRAX, xRDI, 0);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
@@ -2292,6 +2332,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSD");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
@@ -2313,7 +2354,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
STRxw_U12(xRAX, xRDI, 0);
|
||||
unscaled = 0;
|
||||
STxw(xRAX, xRDI, 0);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
@@ -2324,6 +2366,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("LODSB");
|
||||
}
|
||||
NOLRCPC();
|
||||
GETDIR(x1, 1);
|
||||
SMREAD();
|
||||
if(rex.rep) {
|
||||
@@ -2347,6 +2390,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("LODSD");
|
||||
}
|
||||
NOLRCPC();
|
||||
GETDIR(x1, rex.w?8:4);
|
||||
if(rex.rep) {
|
||||
CBZx_NEXT(xRCX);
|
||||
@@ -2363,6 +2407,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
NOLRCPC();
|
||||
switch(rex.rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
@@ -2394,6 +2439,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASB");
|
||||
@@ -2410,6 +2456,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
NOLRCPC();
|
||||
switch(rex.rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
@@ -2440,6 +2487,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASD");
|
||||
@@ -2874,6 +2922,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else { // mem <= i32
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
if(i64) {
|
||||
@@ -2937,6 +2986,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
|
||||
TBZ_MARK(x3, 0);
|
||||
TBZ_MARK(x3, 1); //GP if CS is incorect
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if(u16<0x1000)
|
||||
ADDz_U12(xRSP, xRSP, u16);
|
||||
@@ -2945,6 +2996,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADDz_REG(xRSP, xRSP, x1);
|
||||
}
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
MARK;
|
||||
ADDx_U12(xRSP, xRSP, (rex.w?8:4)*2);
|
||||
MOV64x(xRIP, ip); // move back RIP to the opcode
|
||||
CALL_S(const_native_priv, -1);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2953,8 +3009,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
|
||||
TBZ_MARK(x3, 0);
|
||||
TBZ_MARK(x3, 1); //GP if CS is incorect
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
MARK;
|
||||
ADDx_U12(xRSP, xRSP, (rex.w?8:4)*2);
|
||||
MOV64x(xRIP, ip); // move back RIP to the opcode
|
||||
CALL_S(const_native_priv, -1);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -3011,20 +3074,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("INT 3");
|
||||
if(!BOX64ENV(ignoreint3)) {
|
||||
// check if TRAP signal is handled
|
||||
TABLE64C(x1, const_context);
|
||||
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
LDRx_REG(x3, x1, x2);
|
||||
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
CMPSx_U12(x3, 0);
|
||||
// commit df before branch, CALL_S in int3 path has FORCE_DFNONE
|
||||
CHECK_DFNONE(0);
|
||||
B_MARK(cEQ);
|
||||
GETIP(addr); // update RIP
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_int3, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
MARK;
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -3529,7 +3583,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -3548,7 +3602,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -3930,6 +3984,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64x(x4, j64);
|
||||
}
|
||||
LDRx_U12(x4, x4, 0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x1, x2, x3);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
@@ -4068,8 +4124,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8c(dyn, ninst, x1, u8, x3, x4);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Eb");
|
||||
@@ -4234,7 +4289,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDH(x1, 4);
|
||||
i64 = F32S;
|
||||
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
@@ -4517,8 +4572,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SET_DFNONE();
|
||||
ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
|
||||
break;
|
||||
case 0xFA: /* STI */
|
||||
case 0xFB: /* CLI */
|
||||
case 0xFA: /* CLI */
|
||||
case 0xFB: /* STI */
|
||||
INST_NAME(opcode==0xFA?"CLI":"STI");
|
||||
if(rex.is32bits && BOX64ENV(ignoreint3))
|
||||
{} else {
|
||||
@@ -4628,6 +4683,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x1, x2, x3);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
@@ -4644,6 +4701,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDxw(x1, wback, 0);
|
||||
ed = x1;
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
TBZ(x3, 0, 4+4);
|
||||
TBNZ_MARK2(x3, 1);
|
||||
// Bad CS => GP
|
||||
CALL_S(const_native_priv, -1);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK2;
|
||||
LDH(x5, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if (BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock) > 1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
@@ -4673,7 +4736,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
if (rex.w) PUSH2(x5, xRIP); else PUSH2_32(x5, xRIP);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
CALLRET_RET(can_continue);
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
@@ -4683,6 +4746,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x1, x2, x3);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
@@ -4709,7 +4774,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDxw(x1, wback, 0);
|
||||
ed = x1;
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.w?0:1);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -160,6 +161,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("SYSCALL");
|
||||
if (rex.is32bits) {
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(const_native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
}
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
@@ -281,6 +298,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(wback!=x1) {
|
||||
MOVx_REG(x1, wback);
|
||||
@@ -359,8 +377,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVHPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
INST_NAME("Illegal 0F 17");
|
||||
UDF(0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
@@ -485,6 +503,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("MOVNTPS Ex,Gx");
|
||||
NOLRCPC();
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
@@ -1596,7 +1615,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
@@ -2534,8 +2552,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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)
|
||||
EBBACK; // Eb writeback must be done first, as Gb writeback can clobber the address register
|
||||
if (!(MODREG && wback == gb1 && wb2 == gb2))
|
||||
GBBACK;
|
||||
break;
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Ed, Gd");
|
||||
@@ -2577,6 +2596,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xC3:
|
||||
INST_NAME("MOVNTI Ed, Gd");
|
||||
NOLRCPC();
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
@@ -2666,32 +2686,43 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
if(MODREG) switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
if(rex.rep==2 || !rex.rep) {
|
||||
if(rex.rep==2)
|
||||
INST_NAME("RDSEED Ed");
|
||||
else
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
MOVxw_REG(ed, x1);
|
||||
} else {
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
DEFAULT;
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
MOVxw_REG(ed, x1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("RDPID Ed");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
GETED(0);
|
||||
CALL_(const_helper_getcpu, ed, x2);
|
||||
IFX(X_CF) {
|
||||
MOV32w(x2, 1);
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2961,6 +2992,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTQ Em, Gm");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if(MODREG) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -604,7 +605,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x87:
|
||||
@@ -883,6 +884,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
@@ -907,8 +909,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
STRH_U12(x1, xRDI, 0);
|
||||
unscaled = 0;
|
||||
LDH(x1, xRSI, 0);
|
||||
STH(x1, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
@@ -927,6 +930,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
@@ -949,6 +953,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSW");
|
||||
@@ -972,13 +977,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
UBFXx(x1, xRAX, 0, 16);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
@@ -1000,7 +1006,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
STRH_U12(xRAX, xRDI, 0);
|
||||
unscaled = 0;
|
||||
STH(xRAX, xRDI, 0);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
@@ -1049,6 +1056,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
@@ -1069,6 +1077,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASW");
|
||||
@@ -1122,7 +1131,8 @@ 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) & 0x1f) {
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
@@ -1555,7 +1565,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -950,9 +951,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
@@ -1276,12 +1281,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
PMULL2_128(q0, q0, q1);
|
||||
break;
|
||||
case 0b00000001:
|
||||
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(q0, q0, q1);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(d0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(q0, d0, q1);
|
||||
break;
|
||||
case 0b00010000:
|
||||
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(q0, q0, q1);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(d0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(q0, d0, q1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -1317,6 +1324,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(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);
|
||||
@@ -1327,7 +1336,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
@@ -1405,6 +1414,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVBto(x2, d0, 0);
|
||||
BFIw(x1, x2, 8, 8); // insert
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
int lreg = x2; // no x6 (guest R9): lreg is lost in min(lmem, lreg) and recomputed for SF
|
||||
#else
|
||||
int lreg = x6;
|
||||
#endif
|
||||
// get abs of eax / edx and find min
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
@@ -1413,17 +1427,24 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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(x6, x2, x4, cLT); // x6 is lreg
|
||||
CMPSw_REG(x6, x3);
|
||||
CSELw(x5, x3, x6, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, x6, x3, cLT); // x2 is min(lmem, lreg)
|
||||
if(rex.w) {
|
||||
CMPSx_REG(x3, x4);
|
||||
CSELx(x3, x3, x4, cLO); // x3 is lmem
|
||||
CMPSx_REG(x2, x4);
|
||||
CSELx(lreg, x2, x4, cLO);
|
||||
} else {
|
||||
CMPSw_REG(x3, x4);
|
||||
CSELw(x3, x3, x4, cLO); // x3 is lmem
|
||||
CMPSw_REG(x2, x4);
|
||||
CSELw(lreg, x2, x4, cLO);
|
||||
}
|
||||
CMPSw_REG(lreg, x3);
|
||||
CSELw(x5, x3, lreg, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, lreg, x3, cLT); // x2 is min(lmem, lreg)
|
||||
// x2 is min length 0-n_packed
|
||||
MVNw_REG(x4, xZR);
|
||||
LSLw_REG(x87pc, x4, x2);
|
||||
BICw_REG(x1, x1, x87pc);
|
||||
LSLw_REG(x2, x4, x2);
|
||||
BICw_REG(x1, x1, x2);
|
||||
LSLw_REG(x4, x4, x5);
|
||||
ORRw_REG(x1, x1, x4);
|
||||
ANDw_mask(x1, x1, 0, (u8&1)?7:15);
|
||||
@@ -1455,8 +1476,17 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
#ifdef BOX64EC
|
||||
// lreg was overwritten by min(lmem, lreg), recompute it from abs(RAX)
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
NEGxw_REG(x2, x2);
|
||||
CMPSxw_REG(x2, x4);
|
||||
CSETw(x5, cLO);
|
||||
#else
|
||||
CMPSw_REG(x6, x4);
|
||||
CSETw(x5, cLT);
|
||||
#endif
|
||||
BFIw(xFlags, x5, F_SF, 1);
|
||||
}
|
||||
}
|
||||
@@ -1481,11 +1511,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
else
|
||||
sse_mark_used(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);
|
||||
else
|
||||
sse_mark_used(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);
|
||||
@@ -1493,10 +1527,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
}
|
||||
MOVw_REG(x2, xRDX);
|
||||
MOVw_REG(x4, xRAX);
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
}
|
||||
if(u8&0b1000000) {
|
||||
@@ -1524,6 +1558,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(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);
|
||||
@@ -1573,11 +1609,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETG;
|
||||
if(gd>7)
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, gd);
|
||||
ADDx_U12(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(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);
|
||||
@@ -1597,7 +1637,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOV32w(x2, 31);
|
||||
SUBw_REG(xRCX, x2, xRCX);
|
||||
} else {
|
||||
RBITxw(xRCX, x1);
|
||||
RBITw(xRCX, x1);
|
||||
CLZw(xRCX, xRCX);
|
||||
}
|
||||
break;
|
||||
@@ -2450,7 +2490,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x1, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x1, 1); //(&ed)+=r1*2;
|
||||
LDH(x1, x3, fixedaddress);
|
||||
@@ -2494,7 +2534,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
UFLAG_IF {
|
||||
CBZw_NEXT(x4);
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// x1 to x5 are all in use and x6 is guest R9, so the address in x3 goes through the emu
|
||||
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x3);
|
||||
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
#endif
|
||||
EWBACK;
|
||||
break;
|
||||
|
||||
@@ -2511,7 +2558,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDH(x4, x3, fixedaddress);
|
||||
@@ -2564,7 +2611,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CBZw_NEXT(x4);
|
||||
} else {
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// as SHLD, the address in x3 goes through the emu
|
||||
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x3);
|
||||
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
#endif
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAE:
|
||||
@@ -2637,7 +2691,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDH(x4, x3, fixedaddress);
|
||||
@@ -2706,10 +2760,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
gd = x2;
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x0f;
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2723,7 +2776,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2740,7 +2793,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2756,7 +2809,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2783,7 +2836,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDH(x4, x3, fixedaddress);
|
||||
@@ -2924,10 +2977,12 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
if (!(MODREG && wback == u8)) MOVx_REG(x6, ed);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
if (!(MODREG && wback == u8)) BFIx(u8, x6, 0, 16);
|
||||
if (!(MODREG && wback == u8)) {
|
||||
SUBw_REG(gd, ed, gd); // the old Ew is the sum minus Gw
|
||||
BFIx(u8, gd, 0, 16);
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
@@ -3008,6 +3063,40 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
nextop = F8;
|
||||
if (MODREG) switch ((nextop >> 3) & 7) {
|
||||
case 6:
|
||||
case 7:
|
||||
if (((nextop >> 3) & 7) == 7) {
|
||||
INST_NAME("RDSEED Ew");
|
||||
} else {
|
||||
INST_NAME("RDRAND Ew");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
GETEW(x2, 0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if (cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
EWBACKW(x1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -114,7 +115,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("LOCK CMPXCHG Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
UXTHw(x6, xRAX);
|
||||
UXTHw(x5, xRAX);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
if(cpuext.uscat) {
|
||||
@@ -128,12 +129,12 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
// Aligned version
|
||||
if(cpuext.atomics) {
|
||||
MOVw_REG(x1, x6);
|
||||
MOVw_REG(x1, x5);
|
||||
CASALH(x1, gd, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
CMPSw_REG(x6, x1);
|
||||
CMPSw_REG(x5, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRH(x4, gd, wback);
|
||||
@@ -148,7 +149,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
SUBw_UXTB(x3, x3, x1);
|
||||
CBNZw_MARK3(x3);
|
||||
CMPSw_REG(x6, x1);
|
||||
CMPSw_REG(x5, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
@@ -157,7 +158,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x5, x1, x3, x4, x2);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
@@ -210,11 +211,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x5);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
@@ -361,11 +358,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
@@ -386,11 +379,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -12,6 +13,11 @@
|
||||
#include "dynarec_arm64_arch.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_SET_INIT_INT64(lrcpc)
|
||||
static kh_lrcpc_t *lrcpc = NULL;
|
||||
|
||||
//order might be important, so define SUPER for the right one
|
||||
#define SUPER() \
|
||||
@@ -67,6 +73,7 @@ typedef struct arch_arch_s
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint16_t unaligned:1;
|
||||
uint16_t lrcpc:1;
|
||||
uint16_t seq:10; // how many instruction on the same values
|
||||
} arch_arch_t;
|
||||
|
||||
@@ -76,6 +83,7 @@ typedef struct arch_build_s
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint8_t unaligned;
|
||||
uint8_t lrcpc;
|
||||
#define GO(A) arch_##A##_t A##_;
|
||||
SUPER()
|
||||
#undef GO
|
||||
@@ -91,16 +99,18 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->flags = 1;
|
||||
arch->flags_.defered = (dyn->insts[ninst].f_entry!=status_none && dyn->insts[ninst].f_entry!=status_none_pending);
|
||||
uint8_t flags = dyn->insts[ninst].need_nat_flags | dyn->insts[ninst].before_nat_flags;
|
||||
arch->flags_.vf = flags&NF_VF;
|
||||
arch->flags_.nf = flags&NF_SF;
|
||||
arch->flags_.eq = flags&NF_EQ;
|
||||
arch->flags_.cf = flags&NF_CF;
|
||||
arch->flags_.vf = !!(flags&NF_VF);
|
||||
arch->flags_.nf = !!(flags&NF_SF);
|
||||
arch->flags_.eq = !!(flags&NF_EQ);
|
||||
arch->flags_.cf = !!(flags&NF_CF);
|
||||
if(arch->flags_.cf)
|
||||
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
|
||||
arch->flags_.pf_v = flags&NF_PF_V;
|
||||
arch->flags_.pf_v = !!(flags&NF_PF_V);
|
||||
}
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
// opcode has lrcpc opcode in it
|
||||
arch->lrcpc = dyn->insts[ninst].has_lrcpc;
|
||||
if(!noarch) {
|
||||
// got through all naoncache to gather regs assignments
|
||||
if(dyn->use_x87 || dyn->use_mmx || dyn->use_xmm || dyn->use_ymm) {
|
||||
@@ -120,29 +130,29 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->ymm = 1;
|
||||
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
idx = i;
|
||||
if(idx>=EMM0 && idx<=EMM0+8)
|
||||
if(idx>=EMM0 && idx<EMM0+8)
|
||||
idx-=EMM0;
|
||||
else
|
||||
idx-=SCRATCH0-8;
|
||||
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->ymm_.ymm_pos |= (uint64_t)idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
arch->x87_.x87_pos |= (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type |= (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
arch->x87_.x87_pos |= (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type |= (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
arch->x87_.x87_pos |= (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type |= (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_YMMR:
|
||||
@@ -162,7 +172,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
|
||||
}
|
||||
}
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned + arch->lrcpc;
|
||||
}
|
||||
|
||||
static int sizeof_arch(arch_arch_t* arch)
|
||||
@@ -217,6 +227,7 @@ static void build_next(arch_arch_t* arch, arch_build_t* build)
|
||||
SUPER()
|
||||
#undef GO
|
||||
arch->unaligned = build->unaligned;
|
||||
arch->lrcpc = build->lrcpc;
|
||||
arch->seq = 0;
|
||||
void* p = ((void*)arch)+sizeof(arch_arch_t);
|
||||
#define GO(A) \
|
||||
@@ -309,6 +320,8 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
if(flags->defered) {
|
||||
CHECK_FLAGS(emu);
|
||||
//return;
|
||||
} else {
|
||||
emu->df = d_none;
|
||||
}
|
||||
if(flags->nf) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
|
||||
@@ -358,12 +371,8 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (fpsimd=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, fpsimd);
|
||||
for(int i=0; i<16; ++i) {
|
||||
if(fpsimd && (ymm->ymm>>i)&1) {
|
||||
int idx = (ymm->ymm_pos>>(i*4))&0xf;
|
||||
if(i>7) {
|
||||
idx = SCRATCH0 + i - 8;
|
||||
} else {
|
||||
idx = EMM0 + i;
|
||||
}
|
||||
int pos = (ymm->ymm_pos>>(i*4))&0xf;
|
||||
int idx = (pos>7) ? (SCRATCH0 + pos - 8) : (EMM0 + pos);
|
||||
emu->ymm[i].u128 = fpsimd->vregs[idx];
|
||||
}
|
||||
if(ymm->ymm0&(1<<i))
|
||||
@@ -380,10 +389,10 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
}
|
||||
if(x87) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x (fpsimd=%p)] ", x87->x87, x87->x87_pos, x87->x87_type, fpsimd);
|
||||
emu->top -= x87->delta;
|
||||
if (x87->delta) emu->top = (emu->top - x87->delta) & 7;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(x87->x87&(1<<i)) {
|
||||
int idx = EMM0 + (x87->x87_pos>>(i*4))&0x0f;
|
||||
int idx = EMM0 + ((x87->x87_pos>>(i*4))&0x0f);
|
||||
int t = (x87->x87_type>>(i*2))&0x3;
|
||||
switch (t) {
|
||||
case X87_ST_F:
|
||||
@@ -424,3 +433,53 @@ int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
|
||||
}
|
||||
return arch->unaligned;
|
||||
}
|
||||
|
||||
int arch_lrcpc(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
if(!db)
|
||||
return 0;
|
||||
if(!db->arch_size || !db->arch)
|
||||
return 0;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
if(ninst<0) {
|
||||
return 0;
|
||||
}
|
||||
// look for state at ninst
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
int i = -1;
|
||||
while(i<ninst) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
return arch->lrcpc;
|
||||
}
|
||||
|
||||
void add_lrcpc_address(uintptr_t addr)
|
||||
{
|
||||
if(!lrcpc)
|
||||
lrcpc = kh_init(lrcpc);
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(lrcpc, lrcpc, addr, &ret); // just add
|
||||
}
|
||||
|
||||
int is_addr_lrcpc(uintptr_t addr)
|
||||
{
|
||||
if(!lrcpc)
|
||||
return 0;
|
||||
khint_t k = kh_get(lrcpc, lrcpc, addr);
|
||||
return (k==kh_end(lrcpc))?0:1;
|
||||
}
|
||||
|
||||
int mark_db_lrcpc(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
add_lrcpc_address(x64pc);
|
||||
if(db->to_delete)
|
||||
return 2; // already marked
|
||||
db->to_delete = 1; // mark block for deletion
|
||||
MarkDynablock(db); // and mark it as dirty
|
||||
if(BOX64ENV(showsegv)) printf_log(LOG_INFO, "Marked db %p as dirty, and address %p as avoid lrcpc\n", db, (void*)x64pc);
|
||||
return 2; // marked, exit handling...
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM_ARCH_H__
|
||||
#define __DYNAREC_ARM_ARCH_H__
|
||||
|
||||
@@ -21,4 +22,9 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
#endif
|
||||
// get if instruction can be regenerated for unaligned access
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
|
||||
// get if instruction has lrcpc so it can be regenerated without
|
||||
int arch_lrcpc(dynablock_t* db, uintptr_t x64pc);
|
||||
void add_lrcpc_address(uintptr_t addr);
|
||||
int is_addr_lrcpc(uintptr_t addr);
|
||||
int mark_db_lrcpc(dynablock_t* db, uintptr_t x64pc);
|
||||
#endif // __DYNAREC_ARM_ARCH_H__
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -268,6 +269,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("VMOVNTPS Ex, Gx");
|
||||
NOLRCPC();
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(vex.l) {
|
||||
@@ -417,7 +419,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VANDQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPS Gx, Vx, Ex");
|
||||
@@ -427,7 +429,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VBICQ(v0, v1, v2);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPS Gx, Vx, Ex");
|
||||
@@ -437,7 +439,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VORRQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPS Gx, Vx, Ex");
|
||||
@@ -447,7 +449,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VEORQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPS Gx, Vx, Ex");
|
||||
@@ -477,7 +479,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPS Gx, Vx, Ex");
|
||||
@@ -507,7 +509,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
@@ -521,7 +523,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty(q0, -1, -1, -1);
|
||||
FCVTL2(q0, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
FCVTL(v0, v1);
|
||||
break;
|
||||
case 0x5B:
|
||||
@@ -532,7 +534,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
SCVTQFS(v0, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPS Gx, Vx, Ex");
|
||||
@@ -562,7 +564,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
@@ -606,7 +608,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -253,15 +254,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
UXTBw(x6, vd);
|
||||
CMPSw_U12(x6, rex.w ? 64 : 32);
|
||||
UXTBw(x5, vd);
|
||||
CMPSw_U12(x5, rex.w ? 64 : 32);
|
||||
CSETMxw(x2, cPL);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
MVNxw_REG(x2, x2); //prepare mask
|
||||
B_MARK(cPL);
|
||||
LSLxw_REG(x2, x2, x6);
|
||||
LSLxw_REG(x2, x2, x5);
|
||||
MARK;
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
@@ -326,12 +327,8 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_CF) BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else { BFCw(xFlags, F_SF, 1); }
|
||||
}
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -243,6 +244,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("VMOVNTPD Ex,Gx");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
@@ -321,7 +323,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VANDQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPD Gx, Vx, Ex");
|
||||
@@ -331,7 +333,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VBICQ(v0, v1, v2);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPD Gx, Vx, Ex");
|
||||
@@ -341,7 +343,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VORRQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPD Gx, Vx, Ex");
|
||||
@@ -351,7 +353,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VEORQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPD Gx, Vx, Ex");
|
||||
@@ -413,7 +415,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPD2PS Gx, Ex");
|
||||
@@ -441,7 +443,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
u8 = sse_setround(dyn, ninst, x3, x2, x4); // the address below can use x2 and x3, x4 keeps the old FPCR
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -1783,6 +1785,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
case 0xE7:
|
||||
INST_NAME("VMOVNTDQ Ex,Gx");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -358,7 +359,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x13:
|
||||
INST_NAME("VCVTPH2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(v1, 0, 0);
|
||||
if(vex.l) {GETEX_Y(v1, 0, 0);} else {GETEX64(v1, 0, 0);}
|
||||
GETGX_empty(v0);
|
||||
if(vex.l && v0==v1) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -642,6 +643,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("VMOVNTDQA Gx, Ex");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -162,7 +163,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else {
|
||||
s0 = -1;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 1);
|
||||
}
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
@@ -509,17 +510,17 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
u8 = F8;
|
||||
if(u8&4) {
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x5);
|
||||
} else {
|
||||
u8&=3;
|
||||
if(u8==1) u8=2;
|
||||
else if(u8==2) u8=1;
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
MOV32w(x2, u8);
|
||||
MOVx_REG(x6, x1);
|
||||
MOVx_REG(x5, x1);
|
||||
BFIx(x1, x2, 22, 2); // inject new round
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
s0 = x6;
|
||||
s0 = x5;
|
||||
}
|
||||
FCVTN16(v1, v0);
|
||||
if(vex.l) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -227,7 +228,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -259,7 +260,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSD Gx, Vx, Ex");
|
||||
@@ -309,7 +310,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
@@ -341,7 +342,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSD Gx, Vx, Ex");
|
||||
@@ -356,7 +357,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSD Gx, Vx, Ex");
|
||||
@@ -387,7 +388,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSD Gx, Vx, Ex");
|
||||
@@ -401,7 +402,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
@@ -585,11 +586,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// after the address, so x2 can keep the old FPCR
|
||||
u8 = sse_setround(dyn, ninst, x4, x5, x2);
|
||||
if(!BOX64ENV(dynarec_fastround) || vex.l)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -294,7 +295,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSS Gx, Vx, Ex");
|
||||
@@ -325,7 +326,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
|
||||
@@ -404,7 +405,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSS Gx, Vx, Ex");
|
||||
@@ -418,7 +419,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSS Gx, Vx, Ex");
|
||||
@@ -449,7 +450,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSS Gx, Vx, Ex");
|
||||
@@ -463,7 +464,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
@@ -550,6 +551,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -124,7 +125,7 @@ uintptr_t getConst(arm64_consts_t which)
|
||||
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
|
||||
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
|
||||
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len_imm8w;
|
||||
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
|
||||
case const_x64test_step: return (uintptr_t)x64test_step;
|
||||
case const_printtrace: return (uintptr_t)PrintTrace;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM64_CONSTS__
|
||||
#define __DYNAREC_ARM64_CONSTS__
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -30,12 +31,14 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
int s0;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s5);
|
||||
MAYUSE(s6);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
@@ -53,9 +56,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FADDS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -75,9 +94,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FMULS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -134,9 +169,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FSUBS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -156,9 +207,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FSUBS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -178,9 +245,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FDIVS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -200,9 +283,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FDIVS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -222,10 +321,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FADDS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FADDD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -240,10 +355,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FMULS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FMULD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -287,10 +418,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FSUBS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FSUBD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -305,10 +452,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(s0, v1, s5);
|
||||
}
|
||||
FSUBS(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(s0, v1, s5);
|
||||
}
|
||||
FSUBD(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -323,10 +486,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FDIVS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FDIVD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -341,10 +520,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(s0, v1, s5);
|
||||
}
|
||||
FDIVS(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(s0, v1, s5);
|
||||
}
|
||||
FDIVD(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -236,11 +237,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
&& 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);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
FTABLE64(v1, PI/4.0);
|
||||
addr+=4;
|
||||
} else {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
@@ -275,7 +276,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
VEOR(v1, v1, v1);
|
||||
break;
|
||||
|
||||
@@ -302,7 +303,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = F8;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
} else {
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v2, 0b01110000);
|
||||
} else {
|
||||
@@ -449,9 +450,19 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS_0(v1);
|
||||
FSQRTS(v1, v1);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
MOV32w(x3, X87_REAL_INDEFINITE_FLOAT);
|
||||
FMOVSw(v2, x3);
|
||||
FCSELS(v1, v2, v1, cMI); // MI: less than, not unordered
|
||||
} else {
|
||||
FCMPD_0(v1);
|
||||
FSQRTD(v1, v1);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
MOV64x(x3, X87_REAL_INDEFINITE_DOUBLE);
|
||||
FMOVDx(v2, x3);
|
||||
FCSELD(v1, v2, v1, cMI); // MI: less than, not unordered
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -28,7 +29,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
int d0;
|
||||
int s0;
|
||||
int64_t fixedaddress;
|
||||
@@ -149,7 +150,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -164,7 +173,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -202,7 +219,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -217,7 +242,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -230,9 +263,35 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
FCMPD_0(v2);
|
||||
B_MARK3(cNE);
|
||||
LDRH_U12(x5, xEmu, offsetof(x64emu_t, cw));
|
||||
TBNZ_MARK2(x5, 2); // set SW.ZE flag if bit 2 is set
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK2;
|
||||
LDRH_U12(x5, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x4, 0x4); // ZE flag
|
||||
ORRw_REG(x5, x5, x4);
|
||||
STRH_U12(x5, xEmu, offsetof(x64emu_t, sw));
|
||||
MARK3;
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -247,7 +306,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -275,7 +276,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
NOTEST(x5);
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, ed, 8);
|
||||
LDRH_U12(x4, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; // 0xDB or rex
|
||||
@@ -287,7 +288,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
STRH_U12(x4, ed, 8);
|
||||
} else {
|
||||
if(BOX64ENV(x87_no80bits)) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
@@ -356,11 +357,21 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
#ifdef BOX64EC
|
||||
// no x6 (guest R9) and x2 can be the address: x3 is free here (exp11 == 0), at the cost of the MOV
|
||||
CLZx(x3, x1);
|
||||
ADDw_U12(x3, x3, 1); // "one"
|
||||
SUBw_REG(x4, x4, x3); // x4 = exp16
|
||||
ORRw_REG(x4, x4, x5); // x4 = sign | exp16
|
||||
LSLx_REG(x5, x1, x3); // x5 = mantisse
|
||||
MOVw_REG(x3, x4);
|
||||
#else
|
||||
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
|
||||
#endif
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -30,7 +31,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -51,9 +52,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FADDS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -73,9 +90,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FMULS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -132,9 +165,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FSUBS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -154,9 +203,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FSUBS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -176,9 +241,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FDIVS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -198,9 +279,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FDIVS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -219,7 +316,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -232,7 +337,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -264,7 +377,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -277,7 +398,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -290,7 +419,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -303,7 +440,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -30,7 +31,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -51,9 +52,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FADDS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -74,9 +91,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FMULS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -129,9 +162,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FSUBS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -152,9 +201,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FSUBS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -175,9 +240,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FDIVS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -198,9 +279,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FDIVS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -221,8 +318,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
@@ -233,8 +342,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
@@ -270,8 +391,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
@@ -282,8 +415,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
@@ -294,8 +439,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
@@ -306,8 +463,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -127,7 +128,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D: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)) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -1000,9 +1001,13 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -1143,9 +1148,13 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -1207,9 +1216,13 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -1331,9 +1344,13 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
} else {
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(s4, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -1480,9 +1497,13 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
} else {
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(s4, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -1545,9 +1566,13 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
} else {
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C, bit 29
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(s4, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C, bit 29
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -1727,10 +1752,8 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s3, s1); // bc = op1 | res
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -1783,10 +1806,8 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s3, s1); // bc = op1 | res
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -1274,9 +1275,14 @@ void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
}
|
||||
|
||||
// emit RCL32/RCL64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
#ifdef BOX64EC
|
||||
int s5 = s3; // no x6 (guest R9), so s3 is reused and the new CF waits in F_res2
|
||||
#else
|
||||
int s5 = x6;
|
||||
#endif
|
||||
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_OF|X_CF) {
|
||||
@@ -1291,6 +1297,11 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
LSRxw_REG(s3, s1, s4);
|
||||
}
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
|
||||
BFIw(xFlags, s3, F_res2, 1);
|
||||
}
|
||||
#endif
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX(X_OF) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
@@ -1318,15 +1329,27 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
ORRxw_REG(s1, s1, s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
#ifdef BOX64EC
|
||||
BFXILw(xFlags, xFlags, F_res2, 1);
|
||||
#else
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
#endif
|
||||
}
|
||||
IFX2(X_OF, && BOX64ENV(cputype)) {
|
||||
#ifdef BOX64EC
|
||||
UBFXw(s3, xFlags, F_res2, 1);
|
||||
#endif
|
||||
EORxw_REG_LSR(s3, s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
|
||||
BFCw(xFlags, F_res2, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// emit RCR32/RCR64 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit RCR32/RCR64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
@@ -1348,15 +1371,15 @@ void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
/*else*/
|
||||
{
|
||||
LSRxw_REG(s5, s1, s2);
|
||||
UBFXw(s4, xFlags, 0, 1);
|
||||
LSRxw_REG(s4, s1, s2);
|
||||
MOVZw(s3, (rex.w?64:32));
|
||||
SUBx_REG(s3, s3, s2);
|
||||
LSLxw_REG(s4, s4, s3);
|
||||
ORRxw_REG(s5, s5, s4);
|
||||
UBFXw(s2, xFlags, 0, 1); // s2 is not needed anymore
|
||||
LSLxw_REG(s2, s2, s3);
|
||||
ORRxw_REG(s4, s4, s2);
|
||||
ADDx_U12(s3, s3, 1);
|
||||
LSLxw_REG(s1, s1, s3);
|
||||
ORRxw_REG(s1, s1, s5);
|
||||
ORRxw_REG(s1, s1, s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, xFlags, F_res2, 1);
|
||||
@@ -1622,8 +1645,9 @@ void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
ORRw_REG_LSL(s3, s3, s2, 16); // store fill in the upper half, the deferred handler needs it for OF
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shrd16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
@@ -1665,7 +1689,8 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
ORRw_REG_LSL(s3, s5, s2, 16); // store fill in the upper half, needed for count > 16
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// same flags computation as with shl64/shl32
|
||||
SET_DF(s4, d_shrd16);
|
||||
} else {
|
||||
@@ -1714,8 +1739,9 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
ORRw_REG_LSL(s3, s3, s2, 16); // store fill in the upper half, the deferred handler needs it for OF
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shld16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
@@ -1769,12 +1795,12 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
ORRw_REG_LSL(s3, s5, s2, 16); // store fill in the upper half, needed for count > 16
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shld16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
uint8_t mask = X_CF;
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_CF|X_OF) {
|
||||
MOV32w(s3, 16);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -309,8 +310,8 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX_PENDOR0 {
|
||||
@@ -348,12 +349,12 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
int mask = convert_bitmask_xw(c);
|
||||
@@ -397,12 +398,12 @@ void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
@@ -411,8 +412,8 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
ANDSw_REG_LSL(s5, s5, s2, 16);
|
||||
LSLw(s3, s1, 16);
|
||||
ANDSw_REG_LSL(s3, s3, s2, 16);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
@@ -432,24 +433,24 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
LSRw(s3, s3, 16);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s5, s1, s2); // res = s1 & s2
|
||||
ANDw_REG(s3, s1, s2); // res = s1 & s2
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1);
|
||||
int mask = 0;
|
||||
@@ -459,13 +460,13 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
LSLw(s3, s1, 16);
|
||||
mask = convert_bitmask_w(c<<16);
|
||||
if(mask) {
|
||||
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDSw_mask(s3, s3, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c);
|
||||
ANDSw_REG_LSL(s5, s5, s3, 16);
|
||||
MOV32w(s4, c);
|
||||
ANDSw_REG_LSL(s3, s3, s4, 16);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -486,30 +487,30 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
LSRw(s3, s3, 16);
|
||||
}
|
||||
} else {
|
||||
mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDw_mask(s3, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s5, c);
|
||||
ANDw_REG(s5, s1, s5); // res = s1 & s2
|
||||
MOV32w(s3, c);
|
||||
ANDw_REG(s3, s1, s3); // res = s1 & s2
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit TEST8 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
@@ -518,8 +519,8 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
ANDSw_REG_LSL(s5, s5, s2, 24);
|
||||
LSLw(s3, s1, 24);
|
||||
ANDSw_REG_LSL(s3, s3, s2, 24);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
@@ -539,24 +540,24 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
LSRw(s3, s3, 24);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s5, s1, s2); // res = s1 & s2
|
||||
ANDw_REG(s3, s1, s2); // res = s1 & s2
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1);
|
||||
int mask = 0;
|
||||
@@ -566,13 +567,13 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
LSLw(s3, s1, 24);
|
||||
mask = convert_bitmask_w(c<<24);
|
||||
if(mask) {
|
||||
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDSw_mask(s3, s3, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c);
|
||||
ANDSw_REG_LSL(s5, s5, s3, 24);
|
||||
MOV32w(s4, c);
|
||||
ANDSw_REG_LSL(s3, s3, s4, 24);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -593,24 +594,24 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
LSRw(s3, s3, 24);
|
||||
}
|
||||
} else {
|
||||
mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDw_mask(s3, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s5, c);
|
||||
ANDw_REG(s5, s1, s5); // res = s1 & s2
|
||||
MOV32w(s3, c);
|
||||
ANDw_REG(s3, s1, s3); // res = s1 & s2
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -238,28 +239,28 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("LOCK CMPXCHG Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x1);
|
||||
UBFXx(x6, xRAX, 0, 8);
|
||||
UBFXx(x5, xRAX, 0, 8);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
MOVw_REG(x2, x6);
|
||||
CASALB(x6, gd, wback);
|
||||
emit_cmp8(dyn, ninst, x2, x6, x3, x4, x5);
|
||||
MOVw_REG(x2, x5);
|
||||
CASALB(x5, gd, wback);
|
||||
emit_cmp8(dyn, ninst, x2, x5, x3, x4, x1);
|
||||
} else {
|
||||
CASALB(x6, gd, wback);
|
||||
CASALB(x5, gd, wback);
|
||||
}
|
||||
BFIx(xRAX, x6, 0, 8);
|
||||
BFIx(xRAX, x5, 0, 8);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRB(x2, wback);
|
||||
CMPSxw_REG(x6, x2);
|
||||
CMPSxw_REG(x5, x2);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
MARK;
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x6, x2, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x5, x2, x3, x4, x1);}
|
||||
BFIx(xRAX, x2, 0, 8);
|
||||
}
|
||||
}
|
||||
@@ -282,7 +283,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
UFLAG_IF { MOVxw_REG(x6, xRAX); }
|
||||
UFLAG_IF { MOVxw_REG(x5, xRAX); }
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -344,7 +345,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
MARK;
|
||||
UFLAG_IF {
|
||||
emit_cmp32(dyn, ninst, rex, x6, x1, x3, x4, x5);
|
||||
emit_cmp32(dyn, ninst, rex, x5, x1, x3, x4, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -371,7 +372,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// Will fetch only 1 byte, to avoid alignment issue
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDy_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
ed = x1;
|
||||
@@ -547,7 +548,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// Will fetch only 1 byte, to avoid alignment issue
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDy_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
ed = x1;
|
||||
@@ -785,7 +786,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARKSEG;
|
||||
STLXRB(x4, x5, wback); //write back
|
||||
STLXRB(x4, x2, wback); //write back
|
||||
CBNZx_MARK2(x4);
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
@@ -822,11 +823,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
STLXRB(x4, x1, wback);
|
||||
@@ -847,11 +844,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, gd, x4, x5);
|
||||
STLXRxw(x4, x1, wback);
|
||||
@@ -869,7 +862,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("LOCK AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
GETGB(x5);
|
||||
if(cpuext.atomics) {
|
||||
@@ -1107,11 +1099,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
@@ -1132,11 +1120,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
@@ -1369,11 +1353,7 @@ 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;
|
||||
MOV64xw(x5, i64);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
@@ -1394,11 +1374,7 @@ 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;
|
||||
MOV64xw(x5, i64);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -68,6 +69,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
@@ -237,6 +239,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -247,10 +251,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(v1, v0, v1); // forget it in any input was a NAN already
|
||||
SHL_64(v1, v1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, v1); // NAN -> -NAN
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FSQRTD(q0, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSQRTD(d1, d0);
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
}
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -259,6 +266,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -277,10 +286,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FADDD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
@@ -288,6 +300,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -306,10 +320,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FMULD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FMULD(v1, d1, d0);
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
@@ -333,6 +350,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -351,10 +370,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FSUBD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSUBD(v1, d1, d0);
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
@@ -372,6 +394,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -390,10 +414,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(d1, v2, d0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FDIVD(v0, v0, v1); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FDIVD(d1, v0, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -52,6 +53,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3)); // reg-reg move reads only low-32 of src
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
@@ -65,6 +67,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd); // store reads only low-32 of Gx, upper-96 untouched
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
@@ -236,6 +239,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -246,16 +251,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHL_32(v1, v1, 31); // only keep the sign bit
|
||||
VORR(d1, d1, v1); // NAN -> -NAN
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FSQRTS(q0, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
}
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
@@ -273,6 +283,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
@@ -285,6 +297,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -304,10 +318,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FADDS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FADDS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
@@ -315,6 +332,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -334,10 +353,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FMULS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FMULS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
@@ -399,6 +421,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -418,16 +442,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FSUBS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSUBS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cCC); //CC invert of CS: NAN or == or Gx > Ex
|
||||
@@ -439,6 +468,26 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
LDRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
TBNZ_MARK2(x5, 9); // set ZE flag if bit 9 is set
|
||||
FCMPS_0(d0);
|
||||
B_MARK3(cNE);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK2;
|
||||
LDRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
MOV32w(x4, 0x4); // ZE flag
|
||||
ORRw_REG(x5, x5, x4);
|
||||
STRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
MARK3;
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -458,16 +507,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FDIVS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FDIVS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPS(v1, v0);
|
||||
B_NEXT(cCC); //CC: invert of CS: NAN or == or Ex > Gx
|
||||
@@ -537,6 +591,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
@@ -767,7 +822,6 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0); // there is only I64 -> Double vector conversion, not from i32
|
||||
break;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -28,6 +29,11 @@
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
if(dyn->n.fpu_scratch >= 8) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU scratch registers at inst=%d\n", ninst);
|
||||
dyn->abort = 1;
|
||||
return SCRATCH0;
|
||||
}
|
||||
int ret = SCRATCH0 + dyn->n.fpu_scratch++;
|
||||
if(dyn->n.ymm_used) {
|
||||
printf_log(LOG_INFO, "Warning, getting a scratch register after getting some YMM at inst=%d", ninst);
|
||||
@@ -44,6 +50,11 @@ int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
// Get 2 consicutive FPU scratch reg
|
||||
int fpu_get_double_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
if(dyn->n.fpu_scratch >= 7) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU double scratch registers at inst=%d\n", ninst);
|
||||
dyn->abort = 1;
|
||||
return SCRATCH0;
|
||||
}
|
||||
int ret = SCRATCH0 + dyn->n.fpu_scratch;
|
||||
if(dyn->n.ymm_used) {
|
||||
printf_log(LOG_INFO, "Warning, getting a double scratch register after getting some YMM at inst=%d", ninst);
|
||||
@@ -76,12 +87,19 @@ void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
dyn->n.xmm_unneeded = 0;
|
||||
dyn->n.ymm_unneeded = 0;
|
||||
dyn->n.xmm_removed = 0;
|
||||
dyn->n.xmm_scalar = 0;
|
||||
dyn->n.xmm_scalar_single = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n)
|
||||
{
|
||||
int i=X870;
|
||||
while (dyn->n.fpuused[i]) ++i;
|
||||
while (i<32 && dyn->n.fpuused[i]) ++i;
|
||||
if(i==32) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU x87 registers at inst=%d\n", ninst);
|
||||
dyn->abort = 1;
|
||||
return X870;
|
||||
}
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[i].n); // mark as purged
|
||||
@@ -109,7 +127,7 @@ void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
dyn->n.ymm_removed |= 1<<n;
|
||||
if(t==NEON_CACHE_YMMW)
|
||||
dyn->n.ymm_write |= 1<<n;
|
||||
if(reg>SCRATCH0)
|
||||
if(reg>=SCRATCH0)
|
||||
dyn->n.ymm_regs |= (8LL+reg-SCRATCH0)<<(n*4);
|
||||
else
|
||||
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(n*4);
|
||||
@@ -429,7 +447,7 @@ static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 0;
|
||||
}
|
||||
for(int i=0; i<24; ++i)
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
@@ -438,6 +456,8 @@ static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
return 0;
|
||||
}
|
||||
if(dyn->insts[ninst].ymm0_out)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
}
|
||||
@@ -638,49 +658,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->ymm_used = 0;
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
{
|
||||
(void)dyn; (void)ninst;
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
tmp+=addr+delta;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
#undef F8
|
||||
#undef F32S64
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
static char buff[20];
|
||||
@@ -720,22 +697,22 @@ static register_mapping_t register_mappings[] = {
|
||||
{ "bx", "x13" },
|
||||
{ "bh", "x13" },
|
||||
{ "bl", "x13" },
|
||||
{ "rsi", "x14" },
|
||||
{ "esi", "w14" },
|
||||
{ "si", "x14" },
|
||||
{ "sil", "x14" },
|
||||
{ "rdi", "x15" },
|
||||
{ "edi", "w15" },
|
||||
{ "di", "x15" },
|
||||
{ "dil", "x15" },
|
||||
{ "rsp", "x16" },
|
||||
{ "esp", "w16" },
|
||||
{ "sp", "x16" },
|
||||
{ "spl", "x16" },
|
||||
{ "rbp", "x17" },
|
||||
{ "ebp", "w17" },
|
||||
{ "bp", "x17" },
|
||||
{ "bpl", "x17" },
|
||||
{ "rsp", "x14" },
|
||||
{ "esp", "w14" },
|
||||
{ "sp", "x14" },
|
||||
{ "spl", "x14" },
|
||||
{ "rbp", "x15" },
|
||||
{ "ebp", "w15" },
|
||||
{ "bp", "x15" },
|
||||
{ "bpl", "x15" },
|
||||
{ "rsi", "x16" },
|
||||
{ "esi", "w16" },
|
||||
{ "si", "x16" },
|
||||
{ "sil", "x16" },
|
||||
{ "rdi", "x17" },
|
||||
{ "edi", "w17" },
|
||||
{ "di", "x17" },
|
||||
{ "dil", "x17" },
|
||||
{ "r8", "x18" },
|
||||
{ "r8d", "w18" },
|
||||
{ "r8w", "x18" },
|
||||
@@ -790,8 +767,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
return;
|
||||
}
|
||||
|
||||
static char buf[4096];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
|
||||
static char buf[8192];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)%d",
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
df_status[dyn->f],
|
||||
@@ -803,7 +780,11 @@ 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->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock);
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock,
|
||||
dyn->insts[ninst].x64.strongmem);
|
||||
if(dyn->insts[ninst].use_lrcpc || dyn->insts[ninst].has_lrcpc) {
|
||||
length += sprintf(buf + length, " LRCPC:%d/%d", dyn->insts[ninst].use_lrcpc, dyn->insts[ninst].has_lrcpc);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_op) {
|
||||
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
|
||||
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
|
||||
@@ -867,6 +848,12 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.xmm_needed) {
|
||||
length += sprintf(buf + length, " xmmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_needed, dyn->insts[ninst].n.xmm_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.xmmh_used || dyn->insts[ninst].n.xmmh_needed || dyn->insts[ninst].n.xmmh_unneeded) {
|
||||
length += sprintf(buf + length, " xmmHused=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmmh_used, dyn->insts[ninst].n.xmmh_needed, dyn->insts[ninst].n.xmmh_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.xmms_used || dyn->insts[ninst].n.xmms_needed || dyn->insts[ninst].n.xmms_unneeded) {
|
||||
length += sprintf(buf + length, " xmmSused=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmms_used, dyn->insts[ninst].n.xmms_needed, dyn->insts[ninst].n.xmms_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.ymm_needed) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_needed, dyn->insts[ninst].n.ymm_unneeded);
|
||||
}
|
||||
@@ -909,7 +896,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
|
||||
}
|
||||
if (BOX64ENV(dynarec_perf_map) && (BOX64ENV(dynarec_perf_map_fd) != -1) && dyn->insts[ninst].size) {
|
||||
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4, name);
|
||||
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size, name);
|
||||
}
|
||||
if(length>sizeof(buf)) printf_log(LOG_NONE, "Warning: buf to small in inst_name_pass3 (%d vs %zd)\n", length, sizeof(buf));
|
||||
}
|
||||
@@ -1233,26 +1220,32 @@ static uint32_t getXYMMMask(dynarec_arm_t* dyn, int ninst)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y, uint16_t mask_xh, uint16_t mask_xs)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
// removed unneeded regs
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_unneeded;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_unneeded;
|
||||
// removed already needed from mask
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_needed;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_needed;
|
||||
// already handled
|
||||
if(!mask_x && !mask_y) return;
|
||||
if(!mask_x && !mask_y && !mask_xh && !mask_xs) return;
|
||||
// added the unneeded value
|
||||
dyn->insts[ninst].n.xmm_needed |= mask_x;
|
||||
dyn->insts[ninst].n.ymm_needed |= mask_y;
|
||||
dyn->insts[ninst].n.xmmh_needed |= mask_xh;
|
||||
dyn->insts[ninst].n.xmms_needed |= mask_xs;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
int j = dyn->insts[ninst].pred[i];
|
||||
// barrier or callret, value is needed
|
||||
if(!(dyn->insts[j].x64.barrier&BARRIER_FLOAT)
|
||||
&& !(dyn->insts[j].x64.has_callret))
|
||||
propagateXYMMNeeded(dyn, j, mask_x, mask_y);
|
||||
propagateXYMMNeeded(dyn, j, mask_x, mask_y, mask_xh, mask_xs);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz)
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
@@ -1265,25 +1258,31 @@ static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x,
|
||||
}
|
||||
}
|
||||
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y, uint16_t mask_xh, uint16_t mask_xs)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
// removed needed regs
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_needed;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_needed;
|
||||
// removed already unneeded from mask
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_unneeded;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_unneeded;
|
||||
// already handled
|
||||
if(!mask_x && !mask_y) return;
|
||||
if(!mask_x && !mask_y && !mask_xh && !mask_xs) return;
|
||||
// barrier or callret, value is needed
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return;
|
||||
if(dyn->insts[ninst].x64.has_callret) return;
|
||||
// added the unneeded value
|
||||
dyn->insts[ninst].n.xmm_unneeded |= mask_x;
|
||||
dyn->insts[ninst].n.ymm_unneeded |= mask_y;
|
||||
dyn->insts[ninst].n.xmmh_unneeded |= mask_xh;
|
||||
dyn->insts[ninst].n.xmms_unneeded |= mask_xs;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y);
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y, mask_xh, mask_xs);
|
||||
if(dyn->insts[ninst].pred_sz)
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
else
|
||||
@@ -1297,24 +1296,46 @@ void updateUneeded(dynarec_arm_t* dyn)
|
||||
|
||||
if(!dyn->use_xmm && !dyn->use_ymm)
|
||||
return;
|
||||
// Upper-64 liveness of the low 16 XMM, seeded here and propagated by the same
|
||||
// needed/unneeded passes below used for whole-xmm and the ymm upper-128 lanes.
|
||||
// A scalar SD op touches only the low 64, so it sits in xmm_scalar and is masked
|
||||
// out of xmmh_used; every full-width reader keeps its bit and pins the upper lane
|
||||
// live. An op may zero the upper in place (skipping the x86 upper-preserve) only
|
||||
// where xmmh_unneeded proves the lane dead.
|
||||
// xmms is the same, one dword lower: the upper-96 [127:32] used by scalar-single ops.
|
||||
// A scalar SD op still reads [63:32], so only scalar-single ops (xmm_scalar_single) are
|
||||
// masked out of xmms_used. An SS op may zero the upper-96 in place only where xmms_unneeded
|
||||
// proves it dead.
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst) {
|
||||
dyn->insts[ninst].n.xmmh_used = dyn->insts[ninst].n.xmm_used & ~dyn->insts[ninst].n.xmm_scalar;
|
||||
dyn->insts[ninst].n.xmmh_unneeded = dyn->insts[ninst].n.xmm_unneeded;
|
||||
dyn->insts[ninst].n.xmms_used = dyn->insts[ninst].n.xmm_used & ~dyn->insts[ninst].n.xmm_scalar_single;
|
||||
dyn->insts[ninst].n.xmms_unneeded = dyn->insts[ninst].n.xmm_unneeded;
|
||||
}
|
||||
// first propagate the needed regs: those which are used and are not unneeded
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
uint16_t xmm_needed = dyn->insts[ninst].n.xmm_used&~dyn->insts[ninst].n.xmm_unneeded;
|
||||
uint16_t ymm_needed = dyn->insts[ninst].n.ymm_used&~dyn->insts[ninst].n.ymm_unneeded;
|
||||
uint16_t xmmh_needed = dyn->insts[ninst].n.xmmh_used&~dyn->insts[ninst].n.xmmh_unneeded;
|
||||
uint16_t xmms_needed = dyn->insts[ninst].n.xmms_used&~dyn->insts[ninst].n.xmms_unneeded;
|
||||
// an unresolved exit (float barrier or jump out of the block) can reach code
|
||||
// that reads the full registers, so pin every lane live there, upper-64/96 included
|
||||
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) || (dyn->insts[ninst].x64.jmp && (dyn->insts[ninst].x64.jmp_insts==-1)))
|
||||
{
|
||||
if(dyn->use_xmm) xmm_needed = 0xffff;
|
||||
if(dyn->use_ymm) ymm_needed = 0xffff;
|
||||
if(dyn->use_xmm) xmmh_needed = 0xffff;
|
||||
if(dyn->use_xmm) xmms_needed = 0xffff;
|
||||
}
|
||||
if(xmm_needed || ymm_needed)
|
||||
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed);
|
||||
if(xmm_needed || ymm_needed || xmmh_needed || xmms_needed)
|
||||
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed, xmmh_needed, xmms_needed);
|
||||
|
||||
}
|
||||
// then proagate the unneeded one: those which are not needed (not used anymore and will be overwritten)
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.xmmh_unneeded || dyn->insts[ninst].n.xmms_unneeded) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded, dyn->insts[ninst].n.xmmh_unneeded, dyn->insts[ninst].n.xmms_unneeded);
|
||||
}
|
||||
}
|
||||
// try to add some preload of XYMM on jump were it would make sense
|
||||
@@ -1493,6 +1514,11 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
|
||||
}
|
||||
|
||||
|
||||
void sse_mark_used(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
}
|
||||
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
{
|
||||
@@ -1552,12 +1578,17 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
|
||||
if(i2 && !dyn->insts[i2-1].x64.has_next) // need a previous opcode to set the preload, unless it's the #0
|
||||
return;
|
||||
// check if there is jump out or outside this loop
|
||||
int has_host_call = 0;
|
||||
for(int i=i2; i<ninst; ++i) {
|
||||
if(!dyn->insts[i].x64.has_next || (dyn->insts[i].x64.barrier&BARRIER_FLOAT))
|
||||
return;
|
||||
// for now, unneeded stop at first jump, so this should also stop there
|
||||
if(dyn->insts[i].x64.jmp/* && ((dyn->insts[i].x64.jmp_insts>ninst) || (dyn->insts[i].x64.jmp_insts<i2))*/)
|
||||
return;
|
||||
if(dyn->insts[i].host_call_clobber)
|
||||
return;
|
||||
if(dyn->insts[i].host_call)
|
||||
has_host_call = 1;
|
||||
}
|
||||
uint16_t ymm_mask = 0;
|
||||
for(int i=0; i<16; ++i) {
|
||||
@@ -1596,9 +1627,9 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
|
||||
}
|
||||
}
|
||||
preload = (preload&0xffff) | (ymm_mask<<16); // update ymm_mask
|
||||
//TODO: should check native calls too?
|
||||
dyn->insts[i2].preload_xmmymm = preload;
|
||||
dyn->insts[i2].preload_from = ninst;
|
||||
dyn->insts[i2].preload_host_call = has_host_call;
|
||||
dyn->insts[i2].n.xmm_unneeded |= preload&0xffff;
|
||||
dyn->insts[i2].n.ymm_unneeded |= ymm_mask;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
@@ -70,10 +71,6 @@ void neoncacheUnwind(neoncache_t* cache);
|
||||
void fpu_save_and_unwind(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
|
||||
void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
|
||||
|
||||
|
||||
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_native_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex);
|
||||
@@ -96,6 +93,9 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached);
|
||||
// add a preload of SSE/AVX register preload before i2, for a jump in ninst. Might not do it if there is jump in between that goes outside this ninst-i2 interval
|
||||
void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload);
|
||||
|
||||
// mark a SSE reg as read by the current opcode, without touching its cache entry
|
||||
void sse_mark_used(dynarec_arm_t* dyn, int ninst, int a);
|
||||
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -34,6 +35,12 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(lock==2) *l = 0;
|
||||
|
||||
if(dyn->insts[ninst].use_lrcpc) {
|
||||
if(!unscaled) {
|
||||
NOLRCPC();
|
||||
} else { absmax = 0; mask=0;}
|
||||
} // there is no "Scaled" version, only Unscaled
|
||||
|
||||
if(rex.is32bits && rex.is67)
|
||||
return geted16(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, rex, s);
|
||||
|
||||
@@ -43,7 +50,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
if(hint>0) ret = hint;
|
||||
if(hint>0 && hint<xRAX) scratch = hint;
|
||||
if(hint>0 && !IS_GPR(hint)) scratch = hint;
|
||||
int absmin = 0;
|
||||
if(s) absmin=-absmax;
|
||||
int seg_done = 0;
|
||||
@@ -197,7 +204,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
ADDy_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
PASS3(int tmp = TO_NAT(sib & 0x07) + (rex.b << 3));
|
||||
PASS3(int tmp = TO_NAT((sib & 0x07) + (rex.b << 3)));
|
||||
if(sub) {
|
||||
SUBy_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -220,8 +227,9 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
ret = hint;
|
||||
}
|
||||
if(rex.seg && !seg_done) {
|
||||
scratch = (hint>0 && !IS_GPR(hint)) ? hint : x2;
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
scratch = xLR; // dead between opcodes, ret+1 can be a guest register
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
ADDx_REGy(hint, scratch, ret);
|
||||
@@ -259,7 +267,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
case 1: offset = F8S; break;
|
||||
case 2: offset = F16S; break;
|
||||
}
|
||||
if(offset && (offset>=absmax && offset<=absmin && !(offset&mask))) {
|
||||
if(offset && (offset>=absmin && offset<=absmax && !(offset&mask))) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
@@ -313,7 +321,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
|
||||
if(rex.seg) {
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
scratch = xLR;
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
if(IS_GPR(ret)) {
|
||||
@@ -342,8 +350,10 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if(dyn->have_purge)
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#endif
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -418,18 +428,22 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
if(dyn->have_purge && !dyn->insts[ninst].x64.has_callret)
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if(BOX64DRENV(dynarec_callret) >= 3 && !dyn->insts[ninst].x64.has_callret)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
BLR(dest); // save LR...
|
||||
#else
|
||||
#endif
|
||||
// #ifdef HAVE_TRACE
|
||||
// The BLR form is only for gdb backtraces, but it breaks the
|
||||
// return-address-stack prediction on every block-to-block jump, which is
|
||||
// not worth it. Uncomment temporarily when debugging with gdb.
|
||||
// BLR(dest); // save LR...
|
||||
// #else
|
||||
if (dyn->insts[ninst].x64.has_callret) {
|
||||
BLR(dest); // save LR...
|
||||
} else {
|
||||
BR(dest);
|
||||
}
|
||||
#endif
|
||||
// #endif
|
||||
}
|
||||
|
||||
void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
@@ -438,21 +452,21 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
CHECK_DFNONE(0);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
if(dyn->have_purge)
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x3);
|
||||
CBNZx(x6, 2*4);
|
||||
RET(xLR);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
#endif
|
||||
NOTEST(x2);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
if(dyn->have_purge && !BOX64DRENV(dynarec_callret))
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(dest);
|
||||
#else
|
||||
@@ -541,6 +555,7 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
CHECK_DFNONE(1);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
@@ -557,10 +572,16 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
#ifdef BOX64EC
|
||||
// R10 and R11 are not preserved by the C call in the EC map
|
||||
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10]));
|
||||
#endif
|
||||
fpu_pushcache(dyn, ninst, savereg, 0);
|
||||
for(int i=0; i<dyn->n.fpu_scratch; ++i)
|
||||
VSTR128_S9_preindex(SCRATCH0+i, xSP, -16);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64C(reg, fnc);
|
||||
BLR(reg);
|
||||
@@ -568,6 +589,8 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
MOVx_REG(ret, xEmu);
|
||||
}
|
||||
if(ret!=-2) {
|
||||
for(int i=dyn->n.fpu_scratch-1; i>=0; --i)
|
||||
VLDR128_S9_postindex(SCRATCH0+i, xSP, 16);
|
||||
LDPx_S7_postindex(xEmu, savereg, xSP, 16);
|
||||
#define GO(A, B) if(ret==x##A) { \
|
||||
LDRx_U12(x##B, xEmu, offsetof(x64emu_t, regs[_##B])); \
|
||||
@@ -581,21 +604,30 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#ifdef BOX64EC
|
||||
GO(R10, R11);
|
||||
#endif
|
||||
#undef GO
|
||||
fpu_popcache(dyn, ninst, savereg, 0); // savereg will not be used
|
||||
}
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// x87pc is x5, the pop above restored an argument: reload it
|
||||
NATIVE_RESTORE_X87PC();
|
||||
#else
|
||||
if(savereg!=x87pc && dyn->need_x87check) {
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
#endif
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1, int arg2, int sav1, int sav2)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
CHECK_DFNONE(1);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
@@ -609,11 +641,14 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
#ifdef BOX64EC
|
||||
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10])); // not preserved by the C call, as in call_c
|
||||
#endif
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_pushcache(dyn, ninst, x87pc, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
if(arg1!=-1)
|
||||
FMOVD(0, arg1);
|
||||
@@ -633,6 +668,9 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#ifdef BOX64EC
|
||||
GO(R10, R11);
|
||||
#endif
|
||||
#undef GO
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_popcache(dyn, ninst, x1, 0); // savereg will not be used
|
||||
@@ -642,6 +680,8 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
dyn->insts[ninst].host_call_clobber = 1;
|
||||
CHECK_DFNONE(1);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
@@ -1162,6 +1202,11 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i]==-1)
|
||||
ret = i;
|
||||
if(ret==-1) {
|
||||
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
|
||||
dyn->abort = 1;
|
||||
return -1;
|
||||
}
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
|
||||
@@ -1290,6 +1335,11 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i]==-1)
|
||||
ret = i;
|
||||
if(ret==-1) {
|
||||
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
|
||||
dyn->abort = 1;
|
||||
return;
|
||||
}
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
|
||||
@@ -1443,7 +1493,7 @@ static int isx87Empty(dynarec_arm_t* dyn)
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
dyn->insts[ninst].mmx_used = 1;
|
||||
if(!dyn->n.x87stack && isx87Empty(dyn))
|
||||
if(dyn->n.x87stack || !isx87Empty(dyn))
|
||||
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
return dyn->n.mmxcache[a];
|
||||
@@ -1456,7 +1506,7 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
dyn->insts[ninst].mmx_used = 1;
|
||||
if(!dyn->n.x87stack && isx87Empty(dyn))
|
||||
if(dyn->n.x87stack || !isx87Empty(dyn))
|
||||
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
return dyn->n.mmxcache[a];
|
||||
@@ -1527,8 +1577,9 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
return dyn->n.ssecache[a].reg;
|
||||
}
|
||||
if(!(dyn->n.xmm_used&(1<<a)))
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.ssecache[a].reg = fpu_get_reg_xmm(dyn, NEON_CACHE_XMMW, a);
|
||||
dyn->n.ssecache[a].write = 1; // it will be write...
|
||||
return dyn->n.ssecache[a].reg;
|
||||
@@ -1537,10 +1588,13 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v==-1)
|
||||
return;
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
|
||||
VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
dyn->n.ymm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v!=-1) {
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
|
||||
VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
|
||||
dyn->n.ssecache[a].v = -1;
|
||||
}
|
||||
// YMM part too
|
||||
if(is_avx_zero_unset(dyn, ninst, a)) {
|
||||
@@ -1558,9 +1612,6 @@ void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
fpu_free_reg(dyn, i);
|
||||
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
|
||||
dyn->n.ssecache[a].v = -1;
|
||||
return;
|
||||
}
|
||||
// purge the SSE cache for XMM0..XMM7 (to use before function native call)
|
||||
void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
@@ -1632,7 +1683,7 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, uint
|
||||
if(!next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
if(next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.xmm_used |= (1<<dyn->n.neoncache[i].n);
|
||||
dyn->n.ymm_used |= (1<<dyn->n.neoncache[i].n);
|
||||
}
|
||||
// All done
|
||||
if(old!=-1) {
|
||||
@@ -1640,36 +1691,6 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, uint
|
||||
}
|
||||
}
|
||||
|
||||
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(dyn->n.ssecache[i].v!=-1) {
|
||||
dyn->n.xmm_used |= 1<<i;
|
||||
if(dyn->n.ssecache[i].write) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
//AVX
|
||||
if(dyn->ymm_zero) {
|
||||
int s1_set = 0;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(is_avx_zero(dyn, ninst, i)) {
|
||||
if(!s1_set) {
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, ymm[0]));
|
||||
s1_set = 1;
|
||||
}
|
||||
STPx_S7_offset(xZR, xZR, s1, i*16);
|
||||
}
|
||||
}
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(dyn->n.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
if((dyn->n.neoncache[i].t == NEON_CACHE_YMMW) || (dyn->n.neoncache[i].t == NEON_CACHE_YMMR))
|
||||
dyn->n.xmm_used |= 1<<dyn->n.neoncache[i].n;
|
||||
}
|
||||
}
|
||||
|
||||
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
@@ -2134,19 +2155,23 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(i2<0)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tCache Transform ---- ninst=%d -> %d\n", ninst, i2);
|
||||
MESSAGE(LOG_DUMP, "\tFPU Cache Transform ---- ninst=%d -> %d\n", ninst, i2);
|
||||
uint32_t unneeded = dyn->insts[i2].n.xmm_unneeded | (dyn->insts[i2].n.ymm_unneeded<<16);
|
||||
if((!i2) || (dyn->insts[i2].x64.barrier&BARRIER_FLOAT)) {
|
||||
if(dyn->insts[i2].preload_host_call)
|
||||
unneeded &= ~dyn->insts[i2].preload_xmmymm;
|
||||
int need_purge = 0;
|
||||
if(dyn->n.stack_next)
|
||||
need_purge = 1;
|
||||
for(int i=0; i<24 && !need_purge; ++i)
|
||||
for(int i=0; i<32 && !need_purge; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
need_purge = 1;
|
||||
if(dyn->ymm_zero)
|
||||
need_purge = 1;
|
||||
if(need_purge) { // there is something at ninst for i
|
||||
fpu_purgecache(dyn, ninst, 1, s1, s2, s3, unneeded);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
MESSAGE(LOG_DUMP, "\t---- FPU Cache Transform (purge)\n");
|
||||
return;
|
||||
}
|
||||
neoncache_t cache_i2 = dyn->insts[i2].n;
|
||||
@@ -2173,7 +2198,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
purge = 0;
|
||||
if(purge) {
|
||||
fpu_purgecache(dyn, ninst, 1, s1, s2, s3, unneeded);
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
MESSAGE(LOG_DUMP, "\t---- FPU Cache Transform (purge)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2248,8 +2273,9 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_I64;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_F && cache_i2.neoncache[i].t == NEON_CACHE_ST_I64) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
VFCVTZSQS(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
FCVT_D_S(i, i);
|
||||
VFCVTZSQD(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_I64;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_I64 && cache_i2.neoncache[i].t == NEON_CACHE_ST_F) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
SCVTFDD(i, i);
|
||||
@@ -2277,9 +2303,9 @@ 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;
|
||||
if(stack_cnt != cache_i2.stack || dyn->n.x87stack != cache_i2.x87stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d / pending %d -> %d -\n", stack_cnt, cache_i2.stack, dyn->n.x87stack, cache_i2.x87stack);
|
||||
int a = dyn->n.x87stack - cache_i2.x87stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
@@ -2353,12 +2379,25 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
|
||||
j64 = (GETMARKF2)-(dyn->native_size);
|
||||
CBZw(x1, j64);
|
||||
}
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
if(dyn->insts[ninst].need_nat_flags) {
|
||||
#ifdef BOX64EC
|
||||
// updateflags uses x1 to x5 and x6 is guest R9: NZCV goes through the emu
|
||||
MRS_nzcv(x1);
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
MRS_nzcv(x6);
|
||||
#endif
|
||||
}
|
||||
TABLE64C(x1, const_updateflags_arm64);
|
||||
BLR(x1);
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
if(dyn->insts[ninst].need_nat_flags) {
|
||||
#ifdef BOX64EC
|
||||
LDRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
MSR_nzcv(x1);
|
||||
#else
|
||||
MSR_nzcv(x6);
|
||||
#endif
|
||||
}
|
||||
MARKF2;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Flags fetch\n");
|
||||
@@ -2445,7 +2484,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
EORx_mask(s2, s2, 1, 35, 0); //mask=1<<NZCV_C
|
||||
}
|
||||
}
|
||||
#undef GL_MRS
|
||||
#undef GO_MRS
|
||||
if(mrs) MSR_nzcv(s2);
|
||||
|
||||
MESSAGE(LOG_DUMP, "\t---- Native Flags transform\n");
|
||||
@@ -2465,7 +2504,6 @@ static void flush_native_flags(dynarec_arm_t* dyn, int ninst, int s1, uint8_t fl
|
||||
{
|
||||
// some flags disapear, and need to be saved
|
||||
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", flags);
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(flags&NF_EQ) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
@@ -2496,7 +2534,6 @@ void additionnal_checks(dynarec_arm_t* dyn, int ninst)
|
||||
int s1 = x1;
|
||||
// check if a opcode generate partial flags that may clober existing native flags and see need to be "moved" to xFlags
|
||||
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before || (dyn->insts[ninst].nat_flags_in!=dyn->insts[ninst].need_nat_flags)) {
|
||||
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that will be generated
|
||||
uint8_t nat_flags_gen = dyn->insts[ninst].set_nat_flags;
|
||||
//TODO: does it need to fetch previous state with getPred?
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
|
||||
@@ -2820,7 +2857,8 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
|
||||
}
|
||||
#endif
|
||||
printf_log(LOG_NONE, "BOX64 Dynarec: Error, unable to free a reg for YMM %d at inst=%d on pass %d\n", ymm, ninst, STEP);
|
||||
return i;
|
||||
dyn->abort = 1;
|
||||
return SCRATCH0;
|
||||
}
|
||||
|
||||
// Get an XMM quad reg and preload it (or do nothing if not possible)
|
||||
@@ -2885,10 +2923,6 @@ void doEnterBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
STLXRw(s3, s2, s1);
|
||||
CBNZw(s3, -3*4);
|
||||
}
|
||||
// set tick
|
||||
LDRx_U12(s2, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(s2, s2, offsetof(box64context_t, tick));
|
||||
STRw_U12(s2, s1, offsetof(dynablock_t, tick)-offsetof(dynablock_t, in_used));
|
||||
MESSAGE(LOG_INFO, "-------- doEnter\n");
|
||||
}
|
||||
void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
@@ -2988,8 +3022,8 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
// grab the dynablock address in x5, as this on will not be erased by crc functions
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
LDRx_literal(x5, delta);
|
||||
// move away xEMU to X6, should be safe there
|
||||
MOVx_REG(x6, xEmu);
|
||||
// move away xEMU to the stack, x6 is guest R9 on Box64EC
|
||||
STPx_S7_preindex(xEmu, xZR, xSP, -16);
|
||||
// prepare and call the crc function
|
||||
TABLE64C(x3, cpuext.crc32?const_native_crc32:const_native_x31);
|
||||
LDRx_U12(xEmu, x5, offsetof(dynablock_t, x64_addr));
|
||||
@@ -2997,10 +3031,14 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
BLR(x3);
|
||||
// done, move away result and restore xEmu
|
||||
MOVw_REG(x1, xEmu);
|
||||
MOVx_REG(xEmu, x6);
|
||||
LDPx_S7_postindex(xEmu, xZR, xSP, 16);
|
||||
LDRw_U12(x2, x5, offsetof(dynablock_t, hash));
|
||||
SUBw_REG(x1, x1, x2);
|
||||
CBZw(x1, 4+2*4);
|
||||
TABLE64C(x3, const_native_next_invalidate);
|
||||
BLR(x3);
|
||||
#ifdef BOX64EC
|
||||
// x5 held the dynablock, which is x87pc here
|
||||
NATIVE_RESTORE_X87PC();
|
||||
#endif
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM64_HELPER_H__
|
||||
#define __DYNAREC_ARM64_HELPER_H__
|
||||
|
||||
@@ -39,6 +40,9 @@
|
||||
#ifndef FEMIT
|
||||
#define FEMIT(A) EMIT(A)
|
||||
#endif
|
||||
#ifndef LEMIT
|
||||
#define LEMIT(A) EMIT(A)
|
||||
#endif
|
||||
#ifndef ENDPREFIX
|
||||
#define ENDPREFIX
|
||||
#endif
|
||||
@@ -83,7 +87,7 @@
|
||||
}
|
||||
#define GETEDw(D) \
|
||||
if (MODREG) { \
|
||||
ed = xEAX + (nextop & 7) + (rex.b << 3); \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -132,7 +136,7 @@
|
||||
#define WBACKx if(wback) {STx(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKw if(wback) {STW(ed, wback, fixedaddress); SMWRITE();}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
//FAKEED like GETED, but doesn't get anything
|
||||
#define FAKEED \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
@@ -167,7 +171,7 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//Compute wback for MDREG only, no fetching
|
||||
//Compute wback for MODREG only, no fetching
|
||||
#define CALCEW() \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
@@ -184,20 +188,6 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
#define GETEW32(i, D) \
|
||||
if (MODREG) { \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
UXTHw(i, wback); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff << 1, (1 << 1) - 1, rex, NULL, 0, D); \
|
||||
LDH(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
|
||||
#define GETSEW(i, D) \
|
||||
if (MODREG) { \
|
||||
@@ -270,27 +260,6 @@
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
#define GETEB32(i, D) \
|
||||
if (MODREG) { \
|
||||
if (rex.rex) { \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
wb2 = 0; \
|
||||
} else { \
|
||||
wback = (nextop & 7); \
|
||||
wb2 = (wback >> 2) * 8; \
|
||||
wback = TO_NAT(wback & 3); \
|
||||
} \
|
||||
UBFXx(i, wback, wb2, 8); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDB(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STB(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
|
||||
// no fetch version of GETGB
|
||||
@@ -334,6 +303,14 @@
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
// Get GX as a quad (might use x1)
|
||||
// mark an XMM reg as accessed scalar-only (upper-64 untouched) in this opcode
|
||||
#define MARK_XMM_SCALAR(a) dyn->n.xmm_scalar |= (1 << (a))
|
||||
// test if the upper-64 of an XMM reg is proven dead in this opcode
|
||||
#define XMMH_UNNEEDED(a) (dyn->insts[ninst].n.xmmh_unneeded & (1 << (a)))
|
||||
// mark an XMM reg as accessed scalar-single (only low-32 touched, upper-96 untouched)
|
||||
#define MARK_XMM_SCALAR_SINGLE(a) ((dyn->n.xmm_scalar |= (1 << (a))), (dyn->n.xmm_scalar_single |= (1 << (a))))
|
||||
// test if the upper-96 of an XMM reg is proven dead in this opcode
|
||||
#define XMMS_UNNEEDED(a) (dyn->insts[ninst].n.xmms_unneeded & (1 << (a)))
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
@@ -498,7 +475,7 @@
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
// Get EX as a quad, (x3 is used)
|
||||
// Get EX as a quad but don't load anything, just reserve an empty reg (x3 is used)
|
||||
#define GETEX_empty_Y(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3)); \
|
||||
@@ -589,7 +566,7 @@
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
#define YMM0(a) ymm_mark_zero(dyn, ninst, a);
|
||||
#define YMM0(a) ymm_mark_zero(dyn, ninst, a)
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
|
||||
@@ -601,15 +578,15 @@
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || BOX64ENV(dynarec_aligned_atomics))
|
||||
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || BOX64ENV(dynarec_aligned_atomics))
|
||||
|
||||
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// CALL will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, x87pc, ret, 1, 0)
|
||||
// CALL_ will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, xLR, ret, 1, 0)
|
||||
// CALL_ will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x87pc, ret, 1, reg)
|
||||
// CALL_S will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, xLR, ret, 1, reg)
|
||||
// CALL_S will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x87pc, ret, 0, 0)
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, xLR, ret, 0, 0)
|
||||
// CALL_D will use x7 for the call address. Use for function having 1 or 2 double args and returning 1 double
|
||||
// All regs are saved, including xmm0-7, will move arg1/arg2 to D0, D1, return D0 to ret (unless any is -1)
|
||||
#define CALL_D(F, ret, arg1, arg2, sav1, sav2) call_d(dyn, ninst, F, ret, arg1, arg2, sav1, sav2)
|
||||
@@ -627,6 +604,26 @@
|
||||
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
|
||||
#define GETMARKSEG dyn->insts[ninst].markseg
|
||||
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
|
||||
#ifdef BOX64EC
|
||||
// x6 is guest R9 and x87pc is x5, so keep the flags in the emu across the retry loop
|
||||
#define MARKLOCK_SAVE_FLAGS() do { \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
MRS_nzcv(x4); \
|
||||
STRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
|
||||
MARKLOCK; \
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
LDRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
|
||||
MSR_nzcv(x4); \
|
||||
} while (0)
|
||||
#else
|
||||
#define MARKLOCK_SAVE_FLAGS() do { \
|
||||
MOVx_REG(x6, xFlags); \
|
||||
MRS_nzcv(x87pc); \
|
||||
MARKLOCK; \
|
||||
MOVx_REG(xFlags, x6); \
|
||||
MSR_nzcv(x87pc); \
|
||||
} while (0)
|
||||
#endif
|
||||
#define GETMARKLOCK dyn->insts[ninst].marklock
|
||||
|
||||
// Branch to MARK if cond (use j64)
|
||||
@@ -700,7 +697,7 @@
|
||||
#define B_MARK3(cond) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
Bcond(cond, j64)
|
||||
// Test bit N of A and branch to MARK3 if not set
|
||||
// Test bit N of A and branch to MARK2 if not set
|
||||
#define TBZ_MARK2(A, N) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
TBZ(A, N, j64)
|
||||
@@ -880,6 +877,56 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_START_D
|
||||
#define X87_ARITH_NAN_START_D(va, vb, tmp) \
|
||||
FMAXD(tmp, va, vb); \
|
||||
FCMEQD(tmp, tmp, tmp)
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_END_D
|
||||
#define X87_ARITH_NAN_END_D(vres, vb, tmp, tmp2) \
|
||||
FCMEQD(tmp2, vres, vres); \
|
||||
VBIC(tmp2, tmp, tmp2); \
|
||||
VSHLQ_64(tmp2, tmp2, 63); \
|
||||
VORR(vres, vres, tmp2); \
|
||||
VSSHRQ_64(tmp2, vres, 63); \
|
||||
FCMEQD(tmp, vres, vres); \
|
||||
VMVNQ(tmp, tmp); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VSSHRQ_64(tmp2, vb, 63); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
FCMEQD(tmp2, vb, vb); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VBIT(vres, vb, tmp)
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_START_S
|
||||
#define X87_ARITH_NAN_START_S(va, vb, tmp) \
|
||||
FMAXS(tmp, va, vb); \
|
||||
FCMEQS(tmp, tmp, tmp)
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_END_S
|
||||
#define X87_ARITH_NAN_END_S(vres, vb, tmp, tmp2) \
|
||||
FCMEQS(tmp2, vres, vres); \
|
||||
VBIC(tmp2, tmp, tmp2); \
|
||||
VSHL_32(tmp2, tmp2, 31); \
|
||||
VORR(vres, vres, tmp2); \
|
||||
VSSHR_32(tmp2, vres, 31); \
|
||||
FCMEQS(tmp, vres, vres); \
|
||||
VMVNQ(tmp, tmp); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VSSHR_32(tmp2, vb, 31); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
FCMEQS(tmp2, vb, vb); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VBIT(vres, vb, tmp)
|
||||
#endif
|
||||
|
||||
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define STP_REGS(A, B) STPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define LDP_REGS(A, B) LDPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
@@ -1002,8 +1049,8 @@
|
||||
#define READFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& (dyn->f==status_unk)) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
TABLE64C(x5, const_updateflags_arm64); \
|
||||
BLR(x5); \
|
||||
dyn->f = status_none; \
|
||||
} else if((A)==X_ALL) flushNative(dyn, ninst);
|
||||
#endif
|
||||
@@ -1011,8 +1058,8 @@
|
||||
#define GRABFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& ((dyn->f==status_unk) || (dyn->f==status_set))) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
TABLE64C(x5, const_updateflags_arm64); \
|
||||
BLR(x5); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
|
||||
@@ -1079,7 +1126,7 @@
|
||||
|
||||
#undef PREFLAGSNEEDED
|
||||
#define PREFLAGSNEEDED() \
|
||||
if(dyn->always_test && ninst && (dyn->insts[ninst].sep || (ninst && dyn->insts[ninst-1].x64.has_callret))) \
|
||||
if(dyn->always_test && ninst && (ninst && dyn->insts[ninst-1].x64.has_callret)) \
|
||||
checkCRC(dyn, ninst);
|
||||
|
||||
#if STEP < 2
|
||||
@@ -1301,7 +1348,7 @@
|
||||
#define x87_get_cache STEPNAME(x87_get_cache)
|
||||
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st_empty)
|
||||
#define x87_free STEPNAME(x87_free)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
@@ -1369,12 +1416,12 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -1456,8 +1503,8 @@ void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
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_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, 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);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arm64_emitter.h"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI \
|
||||
@@ -7,14 +8,18 @@
|
||||
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define READFLAGS(A) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.use_flags = A; if(dyn->f!=status_none_pending) dyn->f = status_none;\
|
||||
if(!BOX64ENV(dynarec_df) && (A)&X_PEND) dyn->insts[ninst].x64.use_flags = X_ALL; \
|
||||
dyn->f = status_none
|
||||
dyn->f = status_none; \
|
||||
} while(0)
|
||||
#define SETFLAGS(A,B) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f=status_none; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }}
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f=status_none; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }} \
|
||||
} while(0)
|
||||
#define EMIT(A) dyn->native_size+=4
|
||||
#define JUMP(A, C) \
|
||||
do { \
|
||||
@@ -33,7 +38,11 @@
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
|
||||
dyn->insts[ninst].host_call = 0; \
|
||||
dyn->insts[ninst].host_call_clobber = 0;\
|
||||
dyn->insts[ninst].x64.strongmem = ((box64_wine && VolatileRangesContains(ip)) ? 0 : BOX64DRENV(dynarec_strongmem)); \
|
||||
if(dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat) dyn->insts[ninst].use_lrcpc = 1; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
|
||||
AREFLAGSNEEDED()
|
||||
|
||||
#define INST_EPILOG \
|
||||
@@ -41,7 +50,11 @@
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && !dyn->insts[ninst].set_nat_flags) \
|
||||
dyn->insts[ninst].nat_flags_op=NAT_FLAG_OP_UNUSABLE; \
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0; \
|
||||
if(dyn->insts[ninst].use_lrcpc && (!dyn->insts[ninst].has_lrcpc || is_addr_lrcpc(ip))) \
|
||||
dyn->insts[ninst].use_lrcpc = 0; \
|
||||
if(dyn->insts[ninst].x64.strongmem && dyn->insts[ninst].use_lrcpc) dyn->insts[ninst].x64.strongmem = 0
|
||||
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
@@ -53,7 +66,8 @@
|
||||
}
|
||||
|
||||
|
||||
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
|
||||
#define FEMIT(A) do {dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE; EMIT(A);} while(0)
|
||||
#define LEMIT(A) do {dyn->insts[ninst].has_lrcpc = 1; EMIT(A);} while(0)
|
||||
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.set_flags)
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
#define LEMIT(A) do {dyn->insts[ninst].has_lrcpc = 1; EMIT(A);} while(0)
|
||||
|
||||
// do not update dyn->f for SETFLAGS(..., SF_SET_PENDING) because it will use either DF_NONE or DF_SET anyway (similar to SF_SET_NODF)
|
||||
#define SETFLAGS(A,B) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
if(((B)&SF_SET_PENDING)!=SF_SET_PENDING) dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):((dyn->f==status_none)?status_none:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; }
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; } \
|
||||
} while(0)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
@@ -17,7 +21,9 @@
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
if(dyn->insts[ninst].use_lrcpc && (!dyn->insts[ninst].has_lrcpc || is_addr_lrcpc(ip))) \
|
||||
dyn->insts[ninst].use_lrcpc = 0
|
||||
|
||||
#define INST_NAME(name)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define INIT dyn->native_size = 0
|
||||
#define FINI \
|
||||
if(ninst) { \
|
||||
@@ -32,9 +33,6 @@
|
||||
} while(0)
|
||||
#define FTABLE64(A, V) do { mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0); } while(0)
|
||||
#define CALLRET_RET(A) do { \
|
||||
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
|
||||
dyn->insts[ninst].size+=sizeof(void*); dyn->native_size+=sizeof(void*); dyn->insts[ninst+1].sep=1; ++dyn->sep_size; \
|
||||
} \
|
||||
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
|
||||
dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); \
|
||||
} \
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define INIT
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
@@ -45,15 +46,6 @@
|
||||
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} while(0)
|
||||
#define CALLRET_RET(A) \
|
||||
do { \
|
||||
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
|
||||
MESSAGE(LOG_DUMP, " Dynablock*\n"); \
|
||||
dyn->block += sizeof(void*); \
|
||||
dyn->native_size+=sizeof(void*); \
|
||||
dyn->insts[ninst].size2 += sizeof(void*); \
|
||||
dyn->sep[dyn->sep_size].x64_offs = addr - dyn->start; \
|
||||
dyn->sep[dyn->sep_size].nat_offs = dyn->native_size; \
|
||||
++dyn->sep_size; \
|
||||
} \
|
||||
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
|
||||
dyn->callrets[dyn->callret_size].type = 0; \
|
||||
dyn->callrets[dyn->callret_size++].offs = dyn->native_size; \
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM_PRIVATE_H_
|
||||
#define __DYNAREC_ARM_PRIVATE_H_
|
||||
|
||||
@@ -50,7 +51,6 @@ typedef union sse_cache_s {
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct callret_s callret_t;
|
||||
typedef struct sep_s sep_t;
|
||||
|
||||
typedef struct neoncache_s {
|
||||
// Neon cache
|
||||
@@ -86,6 +86,14 @@ typedef struct neoncache_s {
|
||||
uint16_t ymm_needed; // 1bit for ymmXX were value is needed
|
||||
uint16_t xmm_unneeded; // 1bit for xmmXX were value is not needed
|
||||
uint16_t ymm_unneeded; // 1bit for ymmXX were value is not needed
|
||||
uint16_t xmmh_used; // [127:64] of low-128 used (scalar-vs-packed liveness)
|
||||
uint16_t xmmh_needed; // 1bit if XMM upper-64 needed
|
||||
uint16_t xmmh_unneeded; // 1bit if XMM upper-64 not needed
|
||||
uint16_t xmms_used; // [127:32] of low-128 used (scalar-single-vs-wider liveness)
|
||||
uint16_t xmms_needed; // 1bit if XMM upper-96 needed
|
||||
uint16_t xmms_unneeded; // 1bit if XMM upper-96 not needed
|
||||
uint16_t xmm_scalar; // regs accessed scalar-only (upper-64 untouched) this op
|
||||
uint16_t xmm_scalar_single; // regs accessed scalar-single-only (upper-96 untouched) this op
|
||||
uint64_t ymm_regs; // 4bits (0-15) position of 16 ymmXX regs removed
|
||||
} neoncache_t;
|
||||
|
||||
@@ -127,7 +135,6 @@ typedef struct instruction_arm64_s {
|
||||
uint8_t last_write:1; // [strongmem] the last write in a SEQ
|
||||
uint8_t lock:1; // [strongmem] lock semantic
|
||||
uint8_t wfe:1; // opcode uses sevl + wfe
|
||||
uint8_t sep:1; // opcode is a secondary entry point
|
||||
uint8_t set_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags_before; // 0 or combinaison of native flags define
|
||||
@@ -149,6 +156,11 @@ typedef struct instruction_arm64_s {
|
||||
unsigned x87_used:1; // no fine tracking, just a global "any reg used"
|
||||
unsigned fpu_used:1; // any xmm/ymm/x87/mmx reg used
|
||||
unsigned fpupurge:1; // this opcode will purge all fpu regs
|
||||
unsigned host_call:1; // this opcode performs a native call
|
||||
unsigned host_call_clobber:1; // native call does not preserve cached xmm0-7 (call_n)
|
||||
unsigned preload_host_call:1; // preload range contains a host call, needs write-back at merge
|
||||
unsigned use_lrcpc:1;// use the various lrcpc opcode here instead of regular LD/ST + memory barrier
|
||||
unsigned has_lrcpc:1;// set if the opcode has some lrcpc opcode in it
|
||||
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
|
||||
@@ -182,14 +194,13 @@ typedef struct dynarec_arm_s {
|
||||
int* jmps; // variable array of jump instructions
|
||||
int jmp_sz;
|
||||
int jmp_cap;
|
||||
int peeking_flags;
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
int callret_size; // size of the array
|
||||
int sep_size; // size of the array
|
||||
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
|
||||
sep_t* sep; // array of secondary entry point
|
||||
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
|
||||
@@ -204,7 +215,6 @@ typedef struct dynarec_arm_s {
|
||||
uint8_t use_mmx:1;
|
||||
uint8_t use_xmm:1;
|
||||
uint8_t use_ymm:1;
|
||||
uint8_t have_purge:1; // set to 1 if block can be purged
|
||||
uint8_t is_file_mapped:1; // if the memory is a mapped file (probably binary, not a memory)
|
||||
void* gdbjit_block;
|
||||
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -45,7 +46,6 @@ void* create_updateflags()
|
||||
// pass 0
|
||||
updateflags_pass0(&helper, jmp_df);
|
||||
// check if all flags are handled
|
||||
helper.have_purge = 0; // force no purge
|
||||
int ok = 1;
|
||||
for(int i=d_none; i<d_unknown; ++i)
|
||||
if(!jmp_df[i]) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -164,7 +165,7 @@ SETMARK(d_inc64);
|
||||
RET(xLR);
|
||||
SETMARK(d_imul8);
|
||||
LDRSH_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
ASRxw(x2, x1, 7);
|
||||
ASRw(x2, x1, 7);
|
||||
CMPSw_REG_ASR(x2, x1, 16);
|
||||
CSETw(x3, cNE);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
@@ -499,24 +500,24 @@ SETMARK(d_cmp64);
|
||||
SETMARK(d_tst8);
|
||||
LDRB_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
MOV32w(x2, 0xff);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_tst16);
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
MOV32w(x2, 0xffff);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_tst32);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
MOV32w(x2, 0xffffffff);
|
||||
rex.w = 0;
|
||||
emit_test32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
emit_test32(dyn, ninst, rex, x1, x2, x3, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_tst64);
|
||||
LDRx_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
MOV64x(x2, 0xffffffffffffffffULL);
|
||||
rex.w = 1;
|
||||
emit_test32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
emit_test32(dyn, ninst, rex, x1, x2, x3, x4);
|
||||
rex.w = 0;
|
||||
RET(xLR);
|
||||
// for ADC & SBB, the emit_adcX cannot be used because the CF state is not saved
|
||||
@@ -822,8 +823,8 @@ SETMARK(d_rol64);
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
} else {
|
||||
LDRx_U12(x2, xEmu, offsetof(x64emu_t, op1));
|
||||
LSRw_IMM(x3, x2, 62);
|
||||
EORw_REG_LSR(x3, x3, x3, 1);
|
||||
LSRx(x3, x2, 62);
|
||||
EORx_REG_LSR(x3, x3, x3, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
BFXILw(xFlags, x1, 0, 1);
|
||||
@@ -831,7 +832,7 @@ SETMARK(d_rol64);
|
||||
SETMARK(d_ror8);
|
||||
LDRB_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
if(BOX64ENV(cputype)) {
|
||||
LSLw_IMM(x2, x1, 6);
|
||||
LSRw(x2, x1, 6);
|
||||
EORw_REG_LSR(x3, x2, x2, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
} else {
|
||||
@@ -844,7 +845,7 @@ SETMARK(d_ror8);
|
||||
SETMARK(d_ror16);
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
if(BOX64ENV(cputype)) {
|
||||
LSLw_IMM(x2, x1, 14);
|
||||
LSRw(x2, x1, 14);
|
||||
EORw_REG_LSR(x3, x2, x2, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
} else {
|
||||
@@ -857,7 +858,7 @@ SETMARK(d_ror16);
|
||||
SETMARK(d_ror32);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
if(BOX64ENV(cputype)) {
|
||||
LSLw_IMM(x2, x1, 30);
|
||||
LSRw(x2, x1, 30);
|
||||
EORw_REG_LSR(x3, x2, x2, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
} else {
|
||||
@@ -870,8 +871,8 @@ SETMARK(d_ror32);
|
||||
SETMARK(d_ror64);
|
||||
LDRx_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
if(BOX64ENV(cputype)) {
|
||||
LSLx_IMM(x2, x1, 62);
|
||||
EORw_REG_LSR(x3, x2, x2, 1);
|
||||
LSRx(x2, x1, 62);
|
||||
EORx_REG_LSR(x3, x2, x2, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
} else {
|
||||
LDRx_U12(x2, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -883,30 +884,33 @@ SETMARK(d_ror64);
|
||||
SETMARK(d_shrd16);
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, op1));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, op2));
|
||||
if(BOX64ENV(cputype)) {
|
||||
LSRw(x4, x1, 14);
|
||||
EORw_REG_LSR(x4, x4, x4, 1);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
ORRw_mask(xFlags, xFlags, 28, 0); // mask = 0x10
|
||||
} else {
|
||||
ANDw_mask(x4, x3, 0, 3); // mask = 0x0f
|
||||
SUBw_U12(x4, x4, 16);
|
||||
NEGw_REG(x4, x4);
|
||||
LSRw_REG(x4, x1, x4);
|
||||
EORw_REG_LSR(x4, x4, x2, 15);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
CBNZw(x3, 4+4);
|
||||
LDRw_U12(x3, xEmu, offsetof(x64emu_t, op2));
|
||||
ANDw_mask(x4, x3, 0, 4); // count = op2 & 0x1f
|
||||
CBNZw(x4, 4+4);
|
||||
RET(xLR);
|
||||
SUBw_U12(x4, x3, 1);
|
||||
LSRw_REG(x4, x2, x4);
|
||||
LSRw(x5, x3, 16); // fill = op2 >> 16
|
||||
if(BOX64ENV(cputype)) {
|
||||
CMPSw_U12(x3, 15);
|
||||
CSELw(x4, x4, xZR, cGT);
|
||||
LSRw(x3, x1, 14);
|
||||
EORw_REG_LSR(x3, x3, x3, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
ORRw_mask(xFlags, xFlags, 28, 0); // mask = 0x10
|
||||
SUBw_U12(x3, x4, 1);
|
||||
LSRw_REG(x3, x2, x3);
|
||||
CMPSw_U12(x4, 16);
|
||||
CSELw(x3, xZR, x3, cGT);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
} else {
|
||||
EORw_REG_LSR(x3, x5, x2, 15);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
CMPSw_U12(x4, 16);
|
||||
SUBw_U12(x3, x4, 1);
|
||||
LSRw_REG(x3, x2, x3); // dest >> (count-1)
|
||||
SUBw_U12(x4, x4, 17);
|
||||
LSRw_REG(x5, x5, x4); // fill >> (count-17)
|
||||
CSELw(x3, x5, x3, cGT);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
LSRw(x4, x1, 15);
|
||||
BFIw(xFlags, x4, F_SF, 1);
|
||||
TSTw_mask(x1, 0, 15);
|
||||
@@ -975,24 +979,37 @@ SETMARK(d_shrd64);
|
||||
SETMARK(d_shld16);
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, op1));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, op2));
|
||||
CBNZw(x3, 4+4);
|
||||
LDRw_U12(x3, xEmu, offsetof(x64emu_t, op2));
|
||||
ANDw_mask(x4, x3, 0, 4); // count = op2 & 0x1f
|
||||
CBNZw(x4, 4+4);
|
||||
RET(xLR);
|
||||
SUBw_U12(x4, x3, 16);
|
||||
NEGw_REG(x4, x4);
|
||||
LSRw_REG(x4, x2, x4);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
LSRw(x5, x3, 16); // fill = op2 >> 16
|
||||
if(BOX64ENV(cputype)) {
|
||||
EORw_REG_LSR(x4, xFlags, x1, 15);
|
||||
CMPSw_U12(x3, 15);
|
||||
CSELw(x4, x4, xFlags, cGT);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
MOV32w(x3, 16);
|
||||
SUBw_REG(x3, x3, x4);
|
||||
LSRw_REG(x3, x2, x3); // dest >> (16-count)
|
||||
CMPSw_U12(x4, 16);
|
||||
CSELw(x3, xZR, x3, cGT);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
EORw_REG_LSR(x3, xFlags, x1, 15);
|
||||
CMPSw_U12(x4, 15);
|
||||
CSELw(x3, xFlags, x3, cGT);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
ORRw_mask(xFlags, xFlags, 28, 0); // mask = 0x10
|
||||
} else {
|
||||
LSRw(x4, x2, 14);
|
||||
EORw_REG_LSR(x4, x4, x4, 1);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
LSRw(x3, x2, 14);
|
||||
EORw_REG_LSR(x3, x3, x3, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
CMPSw_U12(x4, 16);
|
||||
MOV32w(x3, 16);
|
||||
SUBw_REG(x3, x3, x4);
|
||||
LSRw_REG(x3, x2, x3); // dest >> (16-count)
|
||||
MOV32w(x2, 32);
|
||||
SUBw_REG(x2, x2, x4);
|
||||
LSRw_REG(x5, x5, x2); // fill >> (32-count)
|
||||
CSELw(x3, x5, x3, cGT);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
LSRw(x4, x1, 15);
|
||||
BFIw(xFlags, x4, F_SF, 1);
|
||||
|
||||
+169
-44
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
@@ -26,16 +27,54 @@
|
||||
#include "khash.h"
|
||||
#include "rbtree.h"
|
||||
|
||||
// ---- fast hash for block change detection ----
|
||||
static uint32_t normal_fast_hash(void* p, uint32_t len)
|
||||
{
|
||||
const uint8_t* data = (const uint8_t*)p;
|
||||
uint64_t h = len * UINT64_C(0x9E3779B97F4A7C15);
|
||||
|
||||
while (len >= 8) {
|
||||
uint64_t k;
|
||||
__builtin_memcpy(&k, data, 8);
|
||||
k *= UINT64_C(0xBF58476D1CE4E5B9);
|
||||
k ^= k >> 31;
|
||||
h ^= k;
|
||||
h *= UINT64_C(0x94D049BB133111EB);
|
||||
data += 8;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
uint64_t k = 0;
|
||||
switch(len) {
|
||||
case 7: k |= (uint64_t)data[6] << 48; /* fall through */
|
||||
case 6: k |= (uint64_t)data[5] << 40; /* fall through */
|
||||
case 5: k |= (uint64_t)data[4] << 32; /* fall through */
|
||||
case 4: k |= (uint64_t)data[3] << 24; /* fall through */
|
||||
case 3: k |= (uint64_t)data[2] << 16; /* fall through */
|
||||
case 2: k |= (uint64_t)data[1] << 8; /* fall through */
|
||||
case 1: k |= (uint64_t)data[0];
|
||||
}
|
||||
k *= UINT64_C(0xBF58476D1CE4E5B9);
|
||||
k ^= k >> 31;
|
||||
h ^= k;
|
||||
h *= UINT64_C(0x94D049BB133111EB);
|
||||
}
|
||||
|
||||
h ^= h >> 33;
|
||||
h *= UINT64_C(0xFF51AFD7ED558CCD);
|
||||
h ^= h >> 33;
|
||||
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
#ifdef ARCH_CRC
|
||||
ARCH_CRC(addr, len);
|
||||
#endif
|
||||
uint8_t* p = (uint8_t*)addr;
|
||||
int32_t h = *p;
|
||||
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
|
||||
return (uint32_t)h;
|
||||
return normal_fast_hash(addr, (uint32_t)len);
|
||||
}
|
||||
|
||||
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
@@ -46,9 +85,6 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
// remove jumptable without waiting
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sep_size; ++i)
|
||||
if(db->sep[i].active)
|
||||
setJumpTableDefault64(db->x64_addr+db->sep[i].x64_offs);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
@@ -75,24 +111,104 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
return db;
|
||||
}
|
||||
|
||||
static void DeferFreeDynablockMap(dynablock_t* db)
|
||||
static void QueueZombieDynablock(dynablock_t* db);
|
||||
|
||||
static void RetireOrphanDynablocks(void)
|
||||
{
|
||||
for (int i = 0; i < my_context->db_orphan_count; ) {
|
||||
dynablock_t* db = my_context->db_orphan[i];
|
||||
if (db && native_lock_get_d(&db->in_used) > 0) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
my_context->db_orphan[i] = my_context->db_orphan[--my_context->db_orphan_count];
|
||||
// released by its last user: requeue it instead of freeing right away, a thread
|
||||
// may still be running the last instructions of the block (and the enter/leave
|
||||
// pair is not atomic with the code around it)
|
||||
if (db) QueueZombieDynablock(db);
|
||||
}
|
||||
}
|
||||
|
||||
static void QueueOrphanDynablock(dynablock_t* db)
|
||||
{
|
||||
if (my_context->db_orphan_count == my_context->db_orphan_size) {
|
||||
int nsize = my_context->db_orphan_size ? my_context->db_orphan_size * 2 : 64;
|
||||
dynablock_t** nlist = box_malloc(nsize * sizeof(dynablock_t*));
|
||||
if (!nlist) return;
|
||||
if (my_context->db_orphan_count)
|
||||
memcpy(nlist, my_context->db_orphan, my_context->db_orphan_count * sizeof(dynablock_t*));
|
||||
if (my_context->db_orphan) box_free(my_context->db_orphan);
|
||||
my_context->db_orphan = nlist;
|
||||
my_context->db_orphan_size = nsize;
|
||||
}
|
||||
my_context->db_orphan[my_context->db_orphan_count++] = db;
|
||||
}
|
||||
|
||||
static void QueueZombieDynablock(dynablock_t* db)
|
||||
{
|
||||
// enq for a deferred free so any threads still running in this block has a better chance to finish.
|
||||
if (my_context->db_zombie_count == DB_ZOMBIE_SIZE) {
|
||||
if(my_context->db_zombie[my_context->db_zombie_head])
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[my_context->db_zombie_head]->actual_block);
|
||||
// Queue full: free the oldest queued block that no running dynarec chain holds (in_used), compact the queue.
|
||||
int idx = -1; // queue position of the entry to drop, 0 = oldest
|
||||
int idx_in_used = 0; // in_used count of that entry
|
||||
for (int i = 0; i < DB_ZOMBIE_SIZE; ++i) {
|
||||
int slot = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
dynablock_t* z = my_context->db_zombie[slot];
|
||||
if (!z)
|
||||
continue;
|
||||
int cnt = native_lock_get_d(&z->in_used);
|
||||
if (cnt <= 0) {
|
||||
idx = i;
|
||||
idx_in_used = cnt;
|
||||
break;
|
||||
}
|
||||
if (idx < 0) {
|
||||
idx = i; // remember the oldest held block, in case all of them are held
|
||||
idx_in_used = cnt;
|
||||
}
|
||||
}
|
||||
if (idx < 0)
|
||||
idx = 0; // queue is full of empty slots: just drop the oldest one
|
||||
// free the picked entry
|
||||
int slot = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + idx + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
if (idx_in_used > 0) {
|
||||
printf_log(LOG_DEBUG, "Warning, all %d queued dynablocks are still in use, deferring the oldest one (in_used=%d)\n", DB_ZOMBIE_SIZE, idx_in_used);
|
||||
QueueOrphanDynablock(my_context->db_zombie[slot]);
|
||||
} else if (my_context->db_zombie[slot])
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[slot]->actual_block);
|
||||
// shift all newer entries over the dropped one, then queue db at the tail
|
||||
for (int i = idx; i < DB_ZOMBIE_SIZE - 1; ++i) {
|
||||
int cur = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
int nxt = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + 1 + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
my_context->db_zombie[cur] = my_context->db_zombie[nxt];
|
||||
}
|
||||
my_context->db_zombie[(my_context->db_zombie_head - 1 + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE] = db;
|
||||
} else {
|
||||
my_context->db_zombie[my_context->db_zombie_head] = db;
|
||||
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
|
||||
my_context->db_zombie_count++;
|
||||
}
|
||||
my_context->db_zombie[my_context->db_zombie_head] = db;
|
||||
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
|
||||
}
|
||||
|
||||
static void DeferFreeDynablockMap(dynablock_t* db)
|
||||
{
|
||||
if (my_context->db_orphan_count) RetireOrphanDynablocks();
|
||||
QueueZombieDynablock(db);
|
||||
}
|
||||
|
||||
void DeferFreeDynablockClearRange(void* addr, size_t sz)
|
||||
{
|
||||
for(int i=0; i<my_context->db_zombie_count; ++i)
|
||||
if(my_context->db_zombie[i] && ((void*)my_context->db_zombie[i]>=addr) && ((void*)my_context->db_zombie[i]<(addr+sz)))
|
||||
my_context->db_zombie[i] = NULL;
|
||||
int head = my_context->db_zombie_head;
|
||||
for(int i=0; i<my_context->db_zombie_count; ++i) {
|
||||
int idx = (head - my_context->db_zombie_count + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
if(my_context->db_zombie[idx] && ((void*)my_context->db_zombie[idx]>=addr) && ((void*)my_context->db_zombie[idx]<(addr+sz)))
|
||||
my_context->db_zombie[idx] = NULL;
|
||||
}
|
||||
for(int i=0; i<my_context->db_orphan_count; )
|
||||
if(my_context->db_orphan[i] && ((void*)my_context->db_orphan[i]>=addr) && ((void*)my_context->db_orphan[i]<(addr+sz)))
|
||||
my_context->db_orphan[i] = my_context->db_orphan[--my_context->db_orphan_count];
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
@@ -127,9 +243,6 @@ void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
|
||||
// remove jumptable without waiting
|
||||
if(need_remove) {
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sep_size; ++i)
|
||||
if(db->sep[i].active)
|
||||
setJumpTableDefault64(db->x64_addr+db->sep[i].x64_offs);
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
@@ -154,9 +267,6 @@ void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
for(int i=0; i<db->sep_size; ++i)
|
||||
if(db->sep[i].active)
|
||||
setJumpTableIfRef64(db->x64_addr+db->sep[i].x64_offs, db->jmpnext, db->block+db->sep[i].nat_offs);
|
||||
if(!setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) {
|
||||
dynablock_t* old = db;
|
||||
db = getDB((uintptr_t)old->x64_addr);
|
||||
@@ -225,8 +335,10 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
void dynablock_leave_runtime(dynablock_t* db)
|
||||
{
|
||||
if(!db) return;
|
||||
if(!db->tick) return;
|
||||
#ifdef HAVE_IN_USED
|
||||
if(BOX64ENV(dynarec_callret) < 3) return;
|
||||
__atomic_fetch_sub(&db->in_used, 1, __ATOMIC_ACQ_REL);
|
||||
#endif
|
||||
}
|
||||
|
||||
dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
|
||||
@@ -273,12 +385,15 @@ dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int need_lock, int is32bits, int is_new)
|
||||
dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int need_lock, int is32bits, int is_new, dynablock_t* block)
|
||||
{
|
||||
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
|
||||
if(BOX64ENV(nodynarec_delay) && (addr>=BOX64ENV(nodynarec_start)) && (addr<BOX64ENV(nodynarec_end)))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(!block)
|
||||
block = getDB(addr);
|
||||
if(block==SEARCHED_NO_DYNABLOCK)
|
||||
block = NULL;
|
||||
if(block && block->to_delete) {
|
||||
// just delete the block then, so we can create a new one right away
|
||||
FreeDynablock(block, 1, 1);
|
||||
@@ -352,14 +467,6 @@ dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int n
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
rb_inc(my_context->db_sizes, block->x64_size, block->x64_size+1);
|
||||
}
|
||||
for(int i=0; i<block->sep_size; ++i) {
|
||||
uintptr_t x64_offs = block->sep[i].x64_offs;
|
||||
uintptr_t nat_offs = block->sep[i].nat_offs;
|
||||
if(addJumpTableIfDefault64(block->x64_addr+x64_offs, (block->dirty || block->always_test)?block->jmpnext:(block->block+nat_offs)))
|
||||
block->sep[i].active = 1;
|
||||
else
|
||||
block->sep[i].active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
@@ -374,11 +481,21 @@ dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int n
|
||||
void FlushZombieDynablocks(void)
|
||||
{
|
||||
if (!my_context) return;
|
||||
if (my_context->db_orphan_count) {
|
||||
for (int i = 0; i < my_context->db_orphan_count; ++i)
|
||||
if (my_context->db_orphan[i] && native_lock_get_d(&my_context->db_orphan[i]->in_used) <= 0)
|
||||
FreeDynarecMap((uintptr_t)my_context->db_orphan[i]->actual_block);
|
||||
box_free(my_context->db_orphan);
|
||||
my_context->db_orphan = NULL;
|
||||
my_context->db_orphan_size = 0;
|
||||
my_context->db_orphan_count = 0;
|
||||
}
|
||||
if (!my_context->db_zombie_count) return;
|
||||
int head = my_context->db_zombie_head;
|
||||
for (int i = 0; i < my_context->db_zombie_count; ++i) {
|
||||
int idx = (head - my_context->db_zombie_count + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[idx]->actual_block);
|
||||
if (my_context->db_zombie[idx] && native_lock_get_d(&my_context->db_zombie[idx]->in_used) <= 0)
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[idx]->actual_block);
|
||||
}
|
||||
my_context->db_zombie_count = 0;
|
||||
}
|
||||
@@ -386,9 +503,26 @@ void FlushZombieDynablocks(void)
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
{
|
||||
int is_inhotpage = isInHotPage(addr);
|
||||
dynablock_t* db = NULL;
|
||||
if(!is_inhotpage && !BOX64ENV(dynarec_dirty)) {
|
||||
db = getDB(addr);
|
||||
if(db && db->x64_size) {
|
||||
uintptr_t dbstart = (uintptr_t)db->x64_addr;
|
||||
uintptr_t dbend = dbstart + db->x64_size;
|
||||
for(uintptr_t page = (dbstart&~(X86_PAGE_SIZE-1)); page < dbend; page += X86_PAGE_SIZE) {
|
||||
if(page == (addr&~(X86_PAGE_SIZE-1))) continue; // skip the first page
|
||||
if(checkInHotPage(page)) {
|
||||
is_inhotpage = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!db)
|
||||
db = SEARCHED_NO_DYNABLOCK;
|
||||
}
|
||||
if(is_inhotpage && !BOX64ENV(dynarec_dirty))
|
||||
return NULL;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, create, 1, is32bits, 1);
|
||||
db = internalDBGetBlock(emu, addr, create, 1, is32bits, 1, db);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
//if (db->always_test) SchedYield(); // just calm down...
|
||||
uint32_t hash = X31_hash_code((void*)db->x64_readaddr, db->x64_size);
|
||||
@@ -403,7 +537,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X, gone:%d, autocrc:%d, to_delete:%d) for %p\n", db, db->x64_addr, db->x64_addr + db->x64_size, db->hash, db->gone, db->autocrc, db->to_delete, (void*)addr);
|
||||
dynablock_t* old = InvalidDynablock(db, 0);
|
||||
FreeInvalidDynablock(old, 0);
|
||||
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0);
|
||||
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0, SEARCHED_NO_DYNABLOCK);
|
||||
} else {
|
||||
if(is_inhotpage) {
|
||||
db->always_test = 2;
|
||||
@@ -427,15 +561,6 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
}
|
||||
#endif
|
||||
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
|
||||
if(!db->always_test)
|
||||
for(int i=0; i<db->sep_size; ++i) {
|
||||
uint32_t x64_offs = db->sep[i].x64_offs;
|
||||
uint32_t nat_offs = db->sep[i].nat_offs;
|
||||
if(setJumpTableIfRef64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs), db->jmpnext))
|
||||
db->sep[i].active = 1;
|
||||
else
|
||||
db->sep[i].active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
@@ -11,17 +12,10 @@ typedef struct callret_s {
|
||||
uint32_t type:1;
|
||||
} callret_t;
|
||||
|
||||
typedef struct sep_s {
|
||||
uint32_t active:1;
|
||||
uint32_t nat_offs:31;
|
||||
uint32_t x64_offs;
|
||||
} sep_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
uint32_t in_used;// will be 0 if not in_used, >0 if used be some code
|
||||
uint32_t tick; // last "tick" when dynablock was run
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
size_t native_size;
|
||||
@@ -39,11 +33,9 @@ typedef struct dynablock_s {
|
||||
int callret_size; // size of the array
|
||||
int isize;
|
||||
int arch_size; // size of of arch dependant infos
|
||||
int sep_size; // SEP are the Secondary Entry Point
|
||||
instsize_t* instsize;
|
||||
void* arch; // arch dependant per inst info (can be NULL)
|
||||
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
|
||||
sep_t* sep; // secondary entry point, offsets are relative to x64_addr & block
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
size_t table64size;// to check table64
|
||||
void* table64; // to relocate the table64
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNACACHE_RELOC_H__
|
||||
#define __DYNACACHE_RELOC_H__
|
||||
|
||||
|
||||
Loaded 100 of 2342 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user