mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 17:39:19 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62695ceed4 | ||
|
|
605d5a29c0 | ||
|
|
fdc7e9d1e4 | ||
|
|
dcc7ad45bc | ||
|
|
265f153449 | ||
|
|
ba9aa3657c | ||
|
|
115d666fff | ||
|
|
42ce1a3b61 | ||
|
|
a7b912393c | ||
|
|
e82f17842e | ||
|
|
4838c86ca9 | ||
|
|
d6b9fd2860 | ||
|
|
60dac1aa29 | ||
|
|
8dd071bcfa | ||
|
|
d92d693df3 | ||
|
|
d16bd5104e | ||
|
|
d7e8da6321 | ||
|
|
aec3fd524a | ||
|
|
14b0323bf6 | ||
|
|
b482847779 | ||
|
|
8c5752de23 | ||
|
|
267bffb0ec | ||
|
|
0546216228 | ||
|
|
a46ea2c07f | ||
|
|
ed4e1ee0ba | ||
|
|
6ac3716594 | ||
|
|
42bad3ea6b | ||
|
|
f9c4eda1fc | ||
|
|
688665e730 | ||
|
|
a676255231 | ||
|
|
d227edeefd | ||
|
|
34c3e2dab3 | ||
|
|
2c0bbc06b7 | ||
|
|
299551428f | ||
|
|
d0ac9c2a5a | ||
|
|
a69368e855 | ||
|
|
84b0e2f113 | ||
|
|
eb695d5553 | ||
|
|
b5946f3752 | ||
|
|
371435afd0 | ||
|
|
0ba46403c6 | ||
|
|
cac43a1f5f | ||
|
|
7771a67abe | ||
|
|
9cd8812d8b | ||
|
|
4b0b3fc98a | ||
|
|
c6afd44c1c | ||
|
|
dbb84245a0 | ||
|
|
15a7c4d8dd | ||
|
|
a842938cfe | ||
|
|
3f83038061 | ||
|
|
01568f8fd3 | ||
|
|
1ee4d5aaf4 | ||
|
|
f9b74642a2 | ||
|
|
401e3a7282 | ||
|
|
32b2b388c8 | ||
|
|
013643782f | ||
|
|
cb064f9e5a | ||
|
|
52c97c47ab | ||
|
|
5f06d066e7 | ||
|
|
a7a211fc85 | ||
|
|
5540601918 | ||
|
|
22f99601d9 | ||
|
|
2fe2e52249 | ||
|
|
6caa598dd7 | ||
|
|
aeeb9b719a | ||
|
|
36f1808615 | ||
|
|
0ce5f34f8c | ||
|
|
579ae99d1b | ||
|
|
fa702c0240 | ||
|
|
34bc807bd5 | ||
|
|
71d49badcc | ||
|
|
3dfcc278e0 | ||
|
|
e312fa392d | ||
|
|
bda28e5882 | ||
|
|
68c2abc429 | ||
|
|
b0727d6f2b | ||
|
|
c66be063aa | ||
|
|
1f0165f895 | ||
|
|
b1ae5dc2b6 | ||
|
|
df228f8829 | ||
|
|
dc2d54edf2 | ||
|
|
d39c554541 | ||
|
|
314b2a5583 | ||
|
|
ce30c1179e | ||
|
|
cbb3126b28 | ||
|
|
a3413ba96d | ||
|
|
2b625e4aa5 | ||
|
|
df74626ca2 | ||
|
|
10373ca6fc | ||
|
|
3dcd08bd4a | ||
|
|
a945daf96d | ||
|
|
22116dabc3 | ||
|
|
5494d95b6b | ||
|
|
9ab686b3e0 | ||
|
|
5b24440e8c | ||
|
|
44deff987c | ||
|
|
7273ac0d34 | ||
|
|
ceb9834a27 | ||
|
|
4eebf25f1c | ||
|
|
865ef2ff6e | ||
|
|
8138ba6ecb | ||
|
|
f1c0b52677 | ||
|
|
a4cb62d6d6 | ||
|
|
e4062c6031 | ||
|
|
08844f31c9 | ||
|
|
4dfdba001b | ||
|
|
8dbf982ebe | ||
|
|
031255a946 | ||
|
|
8dfbe80b41 | ||
|
|
2bcc997e4b | ||
|
|
263e79be53 | ||
|
|
d031a8b423 | ||
|
|
7bec96e4b2 | ||
|
|
6bb1bacfba | ||
|
|
95a4aaf8fd | ||
|
|
387c64b74c | ||
|
|
4d068eee26 | ||
|
|
ece732ba41 | ||
|
|
8f40dc1a8c | ||
|
|
c9a6d4c05a | ||
|
|
a66b4e257a | ||
|
|
3796805d98 | ||
|
|
a3d09e95d5 | ||
|
|
626846c37b | ||
|
|
8bf1ac6577 | ||
|
|
58c0bce4cf | ||
|
|
3a82dc6aad | ||
|
|
e42b9e2866 | ||
|
|
8a85acff32 | ||
|
|
b450ea24a2 | ||
|
|
4fa92dc069 | ||
|
|
61a80c9b2d | ||
|
|
bcfd0f7ea3 | ||
|
|
c404b3e0ab | ||
|
|
b246133b3b | ||
|
|
5b28d7bc03 | ||
|
|
8adaefcdb9 | ||
|
|
e64b4d5c04 | ||
|
|
59caccfeae | ||
|
|
bbd3333b5f | ||
|
|
1ce7f32b5d | ||
|
|
95f18dbf15 | ||
|
|
9ed2e3bbf2 | ||
|
|
8b3cd23045 | ||
|
|
072241eb10 | ||
|
|
84a8500323 | ||
|
|
a8911fc979 | ||
|
|
04ba0b2f67 | ||
|
|
d1e5bc5c19 | ||
|
|
38364ef07f | ||
|
|
b25d8db994 | ||
|
|
989ed95891 | ||
|
|
d15ffc48a3 | ||
|
|
06df8c7bed | ||
|
|
950241d52f | ||
|
|
a147c12f72 | ||
|
|
874828c2ac | ||
|
|
3369e5e755 | ||
|
|
9b3930ea62 | ||
|
|
987d0db806 | ||
|
|
97530e4095 | ||
|
|
4c285d4d8a | ||
|
|
cd5fbc1492 | ||
|
|
2e379300a6 | ||
|
|
65c19d073c | ||
|
|
eb013f3492 | ||
|
|
b2fd651abe | ||
|
|
d4b02e6a3f | ||
|
|
537cb65f26 | ||
|
|
f61367fc9a | ||
|
|
46e0505336 | ||
|
|
75004d0b56 | ||
|
|
0dc5761ca6 | ||
|
|
df47fb5be8 | ||
|
|
0cedc70eb3 | ||
|
|
1612687acf | ||
|
|
67d587cd9b | ||
|
|
9e97e96b87 | ||
|
|
79c1ad1431 | ||
|
|
c0ebe09521 | ||
|
|
b568cc529e | ||
|
|
dc8e24c7b7 | ||
|
|
ba411303e9 | ||
|
|
8848bc2e7f | ||
|
|
f7798f361a | ||
|
|
6a25427cb6 | ||
|
|
a6c283f4ce | ||
|
|
48bb907d2d | ||
|
|
c2ce5d5557 | ||
|
|
0d30fe90f8 | ||
|
|
c434cef45e | ||
|
|
d01970f731 | ||
|
|
bb9beb75d1 | ||
|
|
ad3a9e6c55 | ||
|
|
9a30b65180 | ||
|
|
cb548fe1fa | ||
|
|
0a8f049ced | ||
|
|
890809069e | ||
|
|
ca9a6fe019 | ||
|
|
94ccae727b | ||
|
|
001e77952e | ||
|
|
ac6a453833 | ||
|
|
307915130c | ||
|
|
3d225ef908 | ||
|
|
1c9123637a | ||
|
|
f1f690552f | ||
|
|
57dcf3401c | ||
|
|
9e5df7957e | ||
|
|
ca63389ea3 | ||
|
|
7b7ee070b9 | ||
|
|
3aee16e9a0 | ||
|
|
06cb3624e2 | ||
|
|
a1f83418b9 | ||
|
|
e5a32ea129 | ||
|
|
eb209abe62 | ||
|
|
13551fd410 | ||
|
|
2493706315 | ||
|
|
b49273c079 | ||
|
|
7c1b161277 | ||
|
|
d8a1dcc1b4 | ||
|
|
f44d60c58f | ||
|
|
dc71840a5a | ||
|
|
07b17cd0f6 | ||
|
|
cf37e8ea83 | ||
|
|
5384489702 | ||
|
|
1ad69d785f | ||
|
|
ef3acd9f33 | ||
|
|
083b42fead | ||
|
|
c6814a6f97 | ||
|
|
9dbd7fc7e0 | ||
|
|
a79eff3b0d | ||
|
|
a89d7a2e2a | ||
|
|
0336f6a987 | ||
|
|
6d68975ba5 | ||
|
|
2b07fd7c6a | ||
|
|
f8cc423f3d | ||
|
|
f4667fa3cf | ||
|
|
d8f929755a | ||
|
|
031685e0a7 | ||
|
|
9f260eb86c | ||
|
|
75878b24cd | ||
|
|
fe0425eb80 | ||
|
|
453003da23 | ||
|
|
eec08973bf | ||
|
|
c65f8da90f | ||
|
|
2970ed5bfd | ||
|
|
bfebcba431 | ||
|
|
dde85b761b | ||
|
|
34809e48d8 | ||
|
|
6749c2d1a6 | ||
|
|
7eb24ff514 | ||
|
|
e367a2bcc9 | ||
|
|
a02283264a | ||
|
|
7a7e9ee9af | ||
|
|
b7f25a48c2 | ||
|
|
4477aa3159 | ||
|
|
4fd23c752c | ||
|
|
60b625bc0f | ||
|
|
d1703b9bc0 | ||
|
|
eb9da7417f | ||
|
|
782f497b20 | ||
|
|
003a83b40b | ||
|
|
2f8d28e7da | ||
|
|
fa591589c7 | ||
|
|
f0ea459c57 | ||
|
|
f3d733c3ff | ||
|
|
19ca78769f | ||
|
|
3e5784cbc5 | ||
|
|
98d9f36f9c | ||
|
|
22bc6872f4 | ||
|
|
f6fe84afad | ||
|
|
4744534fc9 | ||
|
|
af05d7439f | ||
|
|
6e22f4fd6d | ||
|
|
0e3d92148b | ||
|
|
06cf6d2ecc | ||
|
|
7b5654eea4 | ||
|
|
503eb41939 | ||
|
|
a77db3c6a5 | ||
|
|
4e0889469a | ||
|
|
7c5bf62fc0 | ||
|
|
b79f86b8d1 | ||
|
|
b9f5929439 | ||
|
|
3dc396a647 | ||
|
|
c358bf448f | ||
|
|
abd1d56d7f | ||
|
|
22b9c16351 | ||
|
|
0131958136 | ||
|
|
9f70767acf | ||
|
|
bdeb8d7ee2 | ||
|
|
de831ee5ac | ||
|
|
da1cb42f2a | ||
|
|
2c366ef4bd | ||
|
|
bc0f31407f | ||
|
|
0d755e610b | ||
|
|
55ee7fcc33 | ||
|
|
10200d7b55 | ||
|
|
1eab6a0c8e | ||
|
|
fc2d50c7d3 | ||
|
|
aaed0364bd | ||
|
|
9e0139f3c3 | ||
|
|
ec3c3b7eed | ||
|
|
c67632722b | ||
|
|
580fbf47b2 | ||
|
|
4bffdce8af | ||
|
|
f22e9bf1d2 | ||
|
|
95b516127a | ||
|
|
da7474b1de | ||
|
|
27aa9011ce | ||
|
|
d09a48fd03 | ||
|
|
b5c0a857ca | ||
|
|
ab9f848dcd | ||
|
|
1b3350437c | ||
|
|
03749788e8 | ||
|
|
9a571cfb72 | ||
|
|
39303611ef | ||
|
|
fcf0cf00d0 | ||
|
|
2ee846f48e | ||
|
|
9c846a3e40 | ||
|
|
712e8315f8 | ||
|
|
604ab22526 | ||
|
|
85d09df938 | ||
|
|
5ae93f8431 | ||
|
|
3aab8dd332 | ||
|
|
bf9d297dcd | ||
|
|
080cc77208 | ||
|
|
7ebd92be7d | ||
|
|
22b2f63917 | ||
|
|
5bcfa34bea | ||
|
|
48c47423a4 | ||
|
|
229cae16d1 | ||
|
|
9edb89fc22 | ||
|
|
3faabb478d | ||
|
|
2c127fe69c | ||
|
|
3765d9e6f7 |
No files matched your search
@@ -146,9 +146,10 @@ jobs:
|
||||
cd build
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=false BOX64_DYNAREC=0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=true,vlen=128,vext_spec=v1.0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=false,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC_LA64NOEXT=1 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC_TEST=2 BOX64_DYNAREC_LA64NOEXT=1 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
|
||||
+58
-6
@@ -209,9 +209,7 @@ elseif(ARM64)
|
||||
#add_definitions(-pipe -march=native)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+simd")
|
||||
elseif(ARM_DYNAREC)
|
||||
if(NOT ANDROID)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto")
|
||||
endif()
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
@@ -313,6 +311,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/box64context.c"
|
||||
"${BOX64_ROOT}/src/build_info.c"
|
||||
"${BOX64_ROOT}/src/custommem.c"
|
||||
"${BOX64_ROOT}/src/custommmap.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfparser.c"
|
||||
@@ -379,6 +378,7 @@ set(INTERPRETER
|
||||
"${BOX64_ROOT}/src/emu/x64run66dd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67avx.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67_32.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6764_32.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run670f.c"
|
||||
@@ -395,6 +395,18 @@ set(INTERPRETER
|
||||
"${BOX64_ROOT}/src/emu/x64runf0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf20f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runf30f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavx.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavx0f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavx0f38.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavx660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavxf20f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavxf30f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavx660f38.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavx660f3a.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavxf20f38.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavxf30f38.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavxf20f3a.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runavxf30f3a.c"
|
||||
)
|
||||
|
||||
if(STATICBUILD)
|
||||
@@ -639,6 +651,14 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n74.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedidn2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedanl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpsl5.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibssh2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedp11kit.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtasn1.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibnettle8.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibunistring2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibhogweed6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsqlite3.c"
|
||||
)
|
||||
endif()
|
||||
if(ANDROID)
|
||||
@@ -728,6 +748,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67_32.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6764_32.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d8.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d9.c"
|
||||
@@ -745,6 +766,16 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_66f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f3_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_66_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f3a.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -790,6 +821,7 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_df.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_6664.c"
|
||||
@@ -823,6 +855,8 @@ if(LARCH64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_64.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_6664.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f0.c"
|
||||
@@ -960,7 +994,9 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.0 DESTINATION ${INSTALL_PATH})
|
||||
@@ -968,16 +1004,15 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.12 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.7 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.3 DESTINATION ${INSTALL_PATH})
|
||||
# Create symlinks
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${INSTALL_PATH}libssl.so.1.1 ${INSTALL_PATH}libssl.so.1.0.0)")
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${INSTALL_PATH}libcrypto.so.1.1 ${INSTALL_PATH}libcrypto.so.1.0.0)")
|
||||
else()
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.0.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.0.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
@@ -1200,6 +1235,14 @@ add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29 -D TEST_OUTPUT=tmpfile29.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test30 -D TEST_OUTPUT=tmpfile30.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref30.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0;BOX64_AVX=2")
|
||||
|
||||
else()
|
||||
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
@@ -1336,6 +1379,15 @@ add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29_android -D TEST_OUTPUT=tmpfile29.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test30_android -D TEST_OUTPUT=tmpfile30.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref30.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
#
|
||||
#set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0 BOX64_AVX=2")
|
||||
|
||||
|
||||
endif()
|
||||
|
||||
if(NOT ANDROID)
|
||||
|
||||
@@ -64,7 +64,7 @@ An alternative solution is to use Wine with new WoW64, but you will be limited t
|
||||
Notes about Box64 configuration
|
||||
----
|
||||
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box64.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reason, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box64.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](https://github.com/ptitSeb/box64/blob/main/docs/USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reason, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.box64rc` > `/etc/box64.box64rc` > command line
|
||||
So, your settings in `~/.box64rc` may override the setting from your command line...
|
||||
|
||||
@@ -74,7 +74,7 @@ Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games should just work, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers). Also many newer Unity3D (like KSP) games use the BC7 compressed textures, which is not supported on many ARM integrated GPU.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
Hint: on Pi4 and Pi5 use `MESA_GL_VERSION_OVERRIDE=3.2`, with `BOX64_DYNAREC_STRONGMEM=1` to prevent freezes and enable strong memory mode, and use Panfrost `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
|
||||
|
||||
Vendored
+26
@@ -1,3 +1,29 @@
|
||||
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
|
||||
|
||||
-- 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...)
|
||||
|
||||
Vendored
+12
-1
@@ -10,4 +10,15 @@ override_dh_auto_configure:
|
||||
-DNOGIT=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.5 --exclude=libstdc++.so.6
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 \
|
||||
--exclude=libpng12.so.0 \
|
||||
--exclude=libstdc++.so.5 \
|
||||
--exclude=libstdc++.so.6 \
|
||||
--exclude=libmbedcrypto.so.7 \
|
||||
--exclude=libssl.so.1.1 \
|
||||
--exclude=libunwind.so.8 \
|
||||
--exclude=libmbedtls.so.14 \
|
||||
--exclude=libcrypto.so.1.1 \
|
||||
--exclude=libmbedx509.so.1 \
|
||||
--exclude=libcrypto.so.1.0.0 \
|
||||
--exclude=libssl.1.0.0
|
||||
@@ -1,3 +1,27 @@
|
||||
v0.3.0
|
||||
======
|
||||
* 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
|
||||
|
||||
v0.2.8
|
||||
======
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
|
||||
+38
-11
@@ -1,17 +1,11 @@
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
### Debian-based Linux
|
||||
You can use [@ryanfortner](https://github.com/ryanfortner)'s apt repository to install precompiled box64 debs, updated every 24 hours.
|
||||
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-build-packages) for alternatives.
|
||||
|
||||
```
|
||||
sudo wget https://ryanfortner.github.io/box64-debs/box64.list -O /etc/apt/sources.list.d/box64.list
|
||||
wget -qO- https://ryanfortner.github.io/box64-debs/KEY.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/box64-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box64-arm64 -y
|
||||
```
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
## Per-platform compiling instructions
|
||||
----
|
||||
|
||||
### The general approach is:
|
||||
@@ -256,7 +250,7 @@ Also, the Static Build is highly experimental, but feedback are always welcomed.
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
## Testing
|
||||
----
|
||||
A few tests are included with box64.
|
||||
|
||||
@@ -266,6 +260,39 @@ The tests are very basic and only tests some functionality for now.
|
||||
|
||||
----
|
||||
|
||||
Debian Packaging
|
||||
## Debian Packaging
|
||||
----
|
||||
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you might want in `debian/rules`.
|
||||
|
||||
## Pre-build packages
|
||||
----
|
||||
### Debian-based Linux
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
# check if .list file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box64.list ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box64.list || exit 1
|
||||
fi
|
||||
|
||||
# check if .sources file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box64.sources ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box64.sources || exit 1
|
||||
fi
|
||||
|
||||
# download gpg key from specified url
|
||||
if [ -f /usr/share/keyrings/box64-archive-keyring.gpg ]; then
|
||||
sudo rm -f /usr/share/keyrings/box64-archive-keyring.gpg
|
||||
fi
|
||||
sudo mkdir -p /usr/share/keyrings
|
||||
wget -qO- "https://pi-apps-coders.github.io/box64-debs/KEY.gpg" | sudo gpg --dearmor -o /usr/share/keyrings/box64-archive-keyring.gpg
|
||||
|
||||
# create .sources file
|
||||
echo "Types: deb
|
||||
URIs: https://Pi-Apps-Coders.github.io/box64-debs/debian
|
||||
Suites: ./
|
||||
Signed-By: /usr/share/keyrings/box64-archive-keyring.gpg" | sudo tee /etc/apt/sources.list.d/box64.sources >/dev/null
|
||||
|
||||
sudo apt update
|
||||
sudo apt install box64-generic-arm -y
|
||||
```
|
||||
+7
-1
@@ -151,6 +151,7 @@ Dynarec will compare it's execution with the interpreter (super slow, only for t
|
||||
* 0 : No comparison. (Default.)
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different.
|
||||
* 2 : Thread-safe tests, extremely slow.
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynarec is tested (inclusive-exclusive)
|
||||
|
||||
#### BOX64_DYNAREC_BIGBLOCK *
|
||||
Enables/Disables Box64's Dynarec building BigBlock.
|
||||
@@ -252,6 +253,11 @@ Detect libjvm and apply conservative settings
|
||||
* 0 : Don't detect libjvm
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 SSE42=0 if detected (Default)
|
||||
|
||||
#### BOX64_UNITYPLAYER *
|
||||
Detect UnityPlayer.dll and apply strongmem settings
|
||||
* 0 : Don't detect UnityPlayer.dll
|
||||
* 1 : Detect UnityPlayer.dll, and apply BOX64_DYNAREC_STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX64_SDL2_JGUID *
|
||||
Need a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2
|
||||
* 0 : Don't use any workaround
|
||||
@@ -335,7 +341,7 @@ Define x86_64 bash to launch script
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
#### BOX64_RESERVE_HIGH
|
||||
#### BOX64_RESERVE_HIGH *
|
||||
* 0 : Don't try to pe-reserve high memory (beyond 47bits) (Default)
|
||||
* 1 : Try to reserve (without allocating it) memory beyond 47bits (seems unstable)
|
||||
|
||||
|
||||
+3
-1
@@ -33,7 +33,7 @@ Print box64 version and quit.
|
||||
=head1 CONFIGURATION FILE
|
||||
|
||||
B<Box64> now have configurations files. There are 2 files loaded.
|
||||
F</etc/box4.box64rc> and F<~/.box64rc>. Both files have the same syntax, and is
|
||||
F</etc/box64.box64rc> and F<~/.box64rc>. Both files have the same syntax, and is
|
||||
basically an ini files. Section in square brackets define the process name, and
|
||||
the rest is the environment variable. B<Box64> comes with a default file that
|
||||
should be installed for better stability. Note that the priority is:
|
||||
@@ -467,6 +467,8 @@ script. yyyy needs to be a full path to a valid x86_64 version of bash
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting. When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack) then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then simply `set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`. This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
|
||||
=back
|
||||
|
||||
=head1 VARIABLES FOR ENVIRONMENT ONLY
|
||||
|
||||
=over 8
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_REVISION 8
|
||||
#define BOX64_MINOR 3
|
||||
#define BOX64_REVISION 0
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+126
-51
@@ -65,6 +65,7 @@ int box64_mmap32 = 0;
|
||||
#endif
|
||||
int box64_ignoreint3 = 0;
|
||||
int box64_rdtsc = 0;
|
||||
int box64_rdtsc_1ghz = 0;
|
||||
uint8_t box64_rdtsc_shift = 0;
|
||||
#ifdef DYNAREC
|
||||
int box64_dynarec = 1;
|
||||
@@ -86,6 +87,8 @@ int box64_dynarec_missing = 0;
|
||||
int box64_dynarec_aligned_atomics = 0;
|
||||
uintptr_t box64_nodynarec_start = 0;
|
||||
uintptr_t box64_nodynarec_end = 0;
|
||||
uintptr_t box64_dynarec_test_start = 0;
|
||||
uintptr_t box64_dynarec_test_end = 0;
|
||||
#ifdef ARM64
|
||||
int arm64_asimd = 0;
|
||||
int arm64_aes = 0;
|
||||
@@ -99,11 +102,13 @@ int arm64_flagm = 0;
|
||||
int arm64_flagm2 = 0;
|
||||
int arm64_frintts = 0;
|
||||
int arm64_afp = 0;
|
||||
int arm64_rndr = 0;
|
||||
#elif defined(RV64)
|
||||
int rv64_zba = 0;
|
||||
int rv64_zbb = 0;
|
||||
int rv64_zbc = 0;
|
||||
int rv64_zbs = 0;
|
||||
int rv64_vector = 0;
|
||||
int rv64_xtheadba = 0;
|
||||
int rv64_xtheadbb = 0;
|
||||
int rv64_xtheadbs = 0;
|
||||
@@ -124,6 +129,7 @@ int box64_dynarec = 0;
|
||||
#endif
|
||||
int box64_libcef = 1;
|
||||
int box64_jvm = 1;
|
||||
int box64_unityplayer = 1;
|
||||
int box64_sdl2_jguid = 0;
|
||||
int dlsym_error = 0;
|
||||
int cycle_log = 0;
|
||||
@@ -149,6 +155,13 @@ int box64_sse_flushto0 = 0;
|
||||
int box64_x87_no80bits = 0;
|
||||
int box64_sync_rounding = 0;
|
||||
int box64_sse42 = 1;
|
||||
#if defined(DYNAREC) && defined(ARM64)
|
||||
int box64_avx = 1;
|
||||
int box64_avx2 = 1;
|
||||
#else
|
||||
int box64_avx = 0;
|
||||
int box64_avx2 = 0;
|
||||
#endif
|
||||
int fix_64bit_inodes = 0;
|
||||
int box64_dummy_crashhandler = 1;
|
||||
int box64_mapclean = 0;
|
||||
@@ -273,8 +286,6 @@ int getNCpu();
|
||||
#ifdef DYNAREC
|
||||
void GatherDynarecExtensions()
|
||||
{
|
||||
if(box64_dynarec==0) // no need to check if no dynarec
|
||||
return;
|
||||
#ifdef ARM64
|
||||
/*
|
||||
HWCAP_FP
|
||||
@@ -385,6 +396,8 @@ HWCAP2_MTE
|
||||
Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010. => Full Memory Tagging Extension is implemented.
|
||||
HWCAP2_ECV
|
||||
Functionality implied by ID_AA64MMFR0_EL1.ECV == 0b0001.
|
||||
HWCAP2_AFP
|
||||
AFP = 0b0001 => The AArch64-FPCR.{AH, FIZ, NEP} fields are supported. (Alternate floating-point behavior)
|
||||
*/
|
||||
unsigned long hwcap = real_getauxval(AT_HWCAP);
|
||||
if(!hwcap) // no HWCap: provide a default...
|
||||
@@ -401,7 +414,6 @@ HWCAP2_ECV
|
||||
arm64_pmull = 1;
|
||||
if(hwcap&HWCAP_AES)
|
||||
arm64_aes = 1;
|
||||
// ATOMIC use are disable for now. They crashes Batman Arkham Knight, bossibly other (also seems to make steamwebhelper unstable)
|
||||
if(hwcap&HWCAP_ATOMICS)
|
||||
arm64_atomics = 1;
|
||||
#ifdef HWCAP_SHA1
|
||||
@@ -433,6 +445,10 @@ HWCAP2_ECV
|
||||
if(hwcap2&HWCAP2_AFP)
|
||||
arm64_afp = 1;
|
||||
#endif
|
||||
#ifdef HWCAP2_RNG
|
||||
if(hwcap2&HWCAP2_RNG)
|
||||
arm64_rndr = 1;
|
||||
#endif
|
||||
printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD");
|
||||
if(arm64_aes)
|
||||
printf_log(LOG_INFO, " AES");
|
||||
@@ -456,6 +472,8 @@ HWCAP2_ECV
|
||||
printf_log(LOG_INFO, " FRINT");
|
||||
if(arm64_afp)
|
||||
printf_log(LOG_INFO, " AFP");
|
||||
if(arm64_rndr)
|
||||
printf_log(LOG_INFO, " RNDR");
|
||||
#elif defined(LA64)
|
||||
printf_log(LOG_INFO, "Dynarec for LoongArch ");
|
||||
char* p = getenv("BOX64_DYNAREC_LA64NOEXT");
|
||||
@@ -470,13 +488,13 @@ HWCAP2_ECV
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt = (cpucfg2 >> 18) & 0b1)
|
||||
if ((la64_lbt = (cpucfg2 >> 18) & 0b1))
|
||||
printf_log(LOG_INFO, " LBT_X86");
|
||||
if (la64_lam_bh = (cpucfg2 >> 27) & 0b1)
|
||||
printf_log(LOG_INFO, " LAM_BT");
|
||||
if (la64_lamcas = (cpucfg2 >> 28) & 0b1)
|
||||
if ((la64_lam_bh = (cpucfg2 >> 27) & 0b1))
|
||||
printf_log(LOG_INFO, " LAM_BH");
|
||||
if ((la64_lamcas = (cpucfg2 >> 28) & 0b1))
|
||||
printf_log(LOG_INFO, " LAMCAS");
|
||||
if (la64_scq = (cpucfg2 >> 30) & 0b1)
|
||||
if ((la64_scq = (cpucfg2 >> 30) & 0b1))
|
||||
printf_log(LOG_INFO, " SCQ");
|
||||
}
|
||||
#elif defined(RV64)
|
||||
@@ -490,6 +508,7 @@ HWCAP2_ECV
|
||||
if(rv64_zbb) printf_log(LOG_INFO, " Zbb");
|
||||
if(rv64_zbc) printf_log(LOG_INFO, " Zbc");
|
||||
if(rv64_zbs) printf_log(LOG_INFO, " Zbs");
|
||||
if(rv64_vector) printf_log(LOG_INFO, " Vector");
|
||||
if(rv64_xtheadba) printf_log(LOG_INFO, " XTheadBa");
|
||||
if(rv64_xtheadbb) printf_log(LOG_INFO, " XTheadBb");
|
||||
if(rv64_xtheadbs) printf_log(LOG_INFO, " XTheadBs");
|
||||
@@ -505,6 +524,45 @@ HWCAP2_ECV
|
||||
}
|
||||
#endif
|
||||
|
||||
void computeRDTSC()
|
||||
{
|
||||
int hardware = 0;
|
||||
box64_rdtsc_shift = 0;
|
||||
#if defined(ARM64) || defined(RV64)
|
||||
hardware = 1;
|
||||
box64_rdtsc = 0; // allow hardxare counter
|
||||
#else
|
||||
box64_rdtsc = 1;
|
||||
printf_log(LOG_INFO, "Will use time-based emulation for rdtsc, even if hardware counter are available\n");
|
||||
#endif
|
||||
uint64_t freq = ReadTSCFrequency(NULL);
|
||||
if(freq<((box64_rdtsc_1ghz)?1000000000LL:1000000)) {
|
||||
box64_rdtsc = 1;
|
||||
if(hardware) printf_log(LOG_INFO, "Hardware counter to slow (%d kHz), not using it\n", freq/1000);
|
||||
hardware = 0;
|
||||
freq = ReadTSCFrequency(NULL);
|
||||
}
|
||||
uint64_t efreq = freq;
|
||||
while(efreq<2000000000 && box64_rdtsc_shift<31) { // minium 2GHz, but not too much shift
|
||||
++box64_rdtsc_shift;
|
||||
efreq = freq<<box64_rdtsc_shift;
|
||||
}
|
||||
printf_log(LOG_INFO, "Will use %s counter measured at ", box64_rdtsc?"Software":"Hardware");
|
||||
int ghz = freq>=1000000000LL;
|
||||
if(ghz) freq/=100000000LL; else freq/=100000;
|
||||
if(ghz) printf_log(LOG_INFO, "%d.%d GHz", freq/10, freq%10);
|
||||
if(!ghz && (freq>=1000)) printf_log(LOG_INFO, "%d MHz", freq/10);
|
||||
if(!ghz && (freq<1000)) printf_log(LOG_INFO, "%d.%d MHz", freq/10, freq%10);
|
||||
if(box64_rdtsc_shift) {
|
||||
printf_log(LOG_INFO, " emulating ");
|
||||
ghz = efreq>=1000000000LL;
|
||||
if(ghz) efreq/=100000000LL; else efreq/=100000;
|
||||
if(ghz) printf_log(LOG_INFO, "%d.%d GHz", efreq/10, efreq%10);
|
||||
if(!ghz && (efreq>=1000)) printf_log(LOG_INFO, "%d MHz", efreq/10);
|
||||
if(!ghz && (efreq<1000)) printf_log(LOG_INFO, "%d.%d MHz", efreq/10, efreq%10);
|
||||
}
|
||||
printf_log(LOG_INFO, "\n");
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void LoadLogEnv()
|
||||
@@ -784,7 +842,22 @@ void LoadLogEnv()
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='2')
|
||||
box64_dynarec_test = p[0]-'0';
|
||||
box64_dynarec_test_start = 0x0;
|
||||
box64_dynarec_test_end = 0x0;
|
||||
} else if (strchr(p,'-')) {
|
||||
if(sscanf(p, "%ld-%ld", &box64_dynarec_test_start, &box64_dynarec_test_end)!=2) {
|
||||
if(sscanf(p, "0x%lX-0x%lX", &box64_dynarec_test_start, &box64_dynarec_test_end)!=2)
|
||||
sscanf(p, "%lx-%lx", &box64_dynarec_test_start, &box64_dynarec_test_end);
|
||||
}
|
||||
if(box64_dynarec_test_end>box64_dynarec_test_start) {
|
||||
box64_dynarec_test = 1;
|
||||
printf_log(LOG_INFO, "Dynarec test in the range %p - %p\n", (void*)box64_nodynarec_start, (void*)box64_nodynarec_end);
|
||||
} else {
|
||||
box64_dynarec_test = 0;
|
||||
printf_log(LOG_INFO, "Ignoring BOX64_NODYNAREC=%s (%p-%p)\n", p, (void*)box64_nodynarec_start, (void*)box64_nodynarec_end);
|
||||
}
|
||||
}
|
||||
|
||||
if(box64_dynarec_test) {
|
||||
box64_dynarec_fastnan = 0;
|
||||
box64_dynarec_fastround = 0;
|
||||
@@ -857,6 +930,15 @@ void LoadLogEnv()
|
||||
if(!box64_jvm)
|
||||
printf_log(LOG_INFO, "BOX64 will not detect libjvm\n");
|
||||
}
|
||||
p = getenv("BOX64_UNITYPLAYER");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='1')
|
||||
box64_unityplayer = p[0]-'0';
|
||||
}
|
||||
if(!box64_unityplayer)
|
||||
printf_log(LOG_INFO, "BOX64 will not detect UnityPlayer.dll\n");
|
||||
}
|
||||
p = getenv("BOX64_SDL2_JGUID");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
@@ -992,6 +1074,33 @@ void LoadLogEnv()
|
||||
if(!box64_sse42)
|
||||
printf_log(LOG_INFO, "Do not expose SSE 4.2 capabilities\n");
|
||||
}
|
||||
p = getenv("BOX64_AVX");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='0'+2)
|
||||
box64_avx = p[0]-'0';
|
||||
}
|
||||
if(box64_avx)
|
||||
printf_log(LOG_INFO, "Will expose AVX capabilities\n");
|
||||
if(box64_avx==2) {
|
||||
box64_avx=1;
|
||||
box64_avx2 = 1;
|
||||
printf_log(LOG_INFO, "Will expose AVX2 capabilities\n");
|
||||
}
|
||||
if(!box64_avx)
|
||||
printf_log(LOG_INFO, "Will not expose AVX capabilities\n");
|
||||
if(!box64_avx2)
|
||||
printf_log(LOG_INFO, "Will not expose AVX2 capabilities\n");
|
||||
}
|
||||
p = getenv("BOX64_RDTSC_1GHZ");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='0'+1)
|
||||
box64_rdtsc_1ghz = p[0]-'0';
|
||||
}
|
||||
if(!box64_rdtsc_1ghz)
|
||||
printf_log(LOG_INFO, "Will require a hardware counter of 1GHz minimum or will fallback to software\n");
|
||||
}
|
||||
p = getenv("BOX64_FIX_64BIT_INODES");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
@@ -1074,41 +1183,7 @@ void LoadLogEnv()
|
||||
const char* cpuname = getCpuName();
|
||||
printf_log(LOG_INFO, " PageSize:%zd Running on %s with %d Cores\n", box64_pagesize, cpuname, ncpu);
|
||||
// grab and calibrate hardware counter
|
||||
int hardware = 0;
|
||||
#if defined(ARM64) || defined(RV64)
|
||||
hardware = 1;
|
||||
box64_rdtsc = 0; // allow hardxare counter
|
||||
#else
|
||||
box64_rdtsc = 1;
|
||||
printf_log(LOG_INFO, "Will use time-based emulation for rdtsc, even if hardware counter are available\n");
|
||||
#endif
|
||||
uint64_t freq = ReadTSCFrequency(NULL);
|
||||
if(freq<1000000) {
|
||||
box64_rdtsc = 1;
|
||||
if(hardware) printf_log(LOG_INFO, "Hardware counter to slow (%d kHz), not using it\n", freq/1000);
|
||||
hardware = 0;
|
||||
freq = ReadTSCFrequency(NULL);
|
||||
}
|
||||
uint64_t efreq = freq;
|
||||
while(efreq<2000000000) { // minium 2GHz
|
||||
++box64_rdtsc_shift;
|
||||
efreq = freq<<box64_rdtsc_shift;
|
||||
}
|
||||
printf_log(LOG_INFO, "Will use %s counter measured at ", box64_rdtsc?"Software":"Hardware");
|
||||
int ghz = freq>=1000000000LL;
|
||||
if(ghz) freq/=100000000LL; else freq/=100000;
|
||||
if(ghz) printf_log(LOG_INFO, "%d.%d GHz", freq/10, freq%10);
|
||||
if(!ghz && (freq>=1000)) printf_log(LOG_INFO, "%d MHz", freq/10);
|
||||
if(!ghz && (freq<1000)) printf_log(LOG_INFO, "%d.%d MHz", freq/10, freq%10);
|
||||
if(box64_rdtsc_shift) {
|
||||
printf_log(LOG_INFO, " emulating ");
|
||||
ghz = efreq>=1000000000LL;
|
||||
if(ghz) efreq/=100000000LL; else efreq/=100000;
|
||||
if(ghz) printf_log(LOG_INFO, "%d.%d GHz", efreq/10, efreq%10);
|
||||
if(!ghz && (efreq>=1000)) printf_log(LOG_INFO, "%d MHz", efreq/10);
|
||||
if(!ghz && (efreq<1000)) printf_log(LOG_INFO, "%d.%d MHz", efreq/10, efreq%10);
|
||||
}
|
||||
printf_log(LOG_INFO, "\n");
|
||||
computeRDTSC();
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -1203,7 +1278,7 @@ void AddNewLibs(const char* list)
|
||||
}
|
||||
|
||||
void PrintFlags() {
|
||||
printf("Environment Variables:\n");
|
||||
printf("Environment Variables:\n");
|
||||
printf(" BOX64_PATH is the box64 version of PATH (default is '.:bin')\n");
|
||||
printf(" BOX64_LD_LIBRARY_PATH is the box64 version LD_LIBRARY_PATH (default is '.:lib:lib64')\n");
|
||||
printf(" BOX64_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed debug info (level 3 is level 2 + BOX64_DUMP)\n");
|
||||
@@ -1337,31 +1412,31 @@ void LoadEnvVars(box64context_t *context)
|
||||
if (strcmp(getenv("BOX64_SSE_FLUSHTO0"), "1")==0) {
|
||||
box64_sse_flushto0 = 1;
|
||||
printf_log(LOG_INFO, "BOX64: Direct apply of SSE Flush to 0 flag\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getenv("BOX64_X87_NO80BITS")) {
|
||||
if (strcmp(getenv("BOX64_X87_NO80BITS"), "1")==0) {
|
||||
box64_x87_no80bits = 1;
|
||||
printf_log(LOG_INFO, "BOX64: All 80bits x87 long double will be handle as double\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getenv("BOX64_SYNC_ROUNDING")) {
|
||||
if (strcmp(getenv("BOX64_SYNC_ROUNDING"), "1")==0) {
|
||||
box64_sync_rounding = 1;
|
||||
printf_log(LOG_INFO, "BOX64: Rouding mode with be synced with fesetround/fegetround\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getenv("BOX64_PREFER_WRAPPED")) {
|
||||
if (strcmp(getenv("BOX64_PREFER_WRAPPED"), "1")==0) {
|
||||
box64_prefer_wrapped = 1;
|
||||
printf_log(LOG_INFO, "BOX64: Prefering Wrapped libs\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getenv("BOX64_PREFER_EMULATED")) {
|
||||
if (strcmp(getenv("BOX64_PREFER_EMULATED"), "1")==0) {
|
||||
box64_prefer_emulated = 1;
|
||||
printf_log(LOG_INFO, "BOX64: Prefering Emulated libs\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(getenv("BOX64_NOSIGSEGV")) {
|
||||
@@ -1609,7 +1684,7 @@ static void load_rcfiles()
|
||||
char* rcpath = getenv("BOX64_RCFILE");
|
||||
|
||||
if(rcpath && FileExist(rcpath, IS_FILE))
|
||||
LoadRCFile(rcpath);
|
||||
LoadRCFile(rcpath);
|
||||
#ifndef TERMUX
|
||||
else if(FileExist("/etc/box64.box64rc", IS_FILE))
|
||||
LoadRCFile("/etc/box64.box64rc");
|
||||
@@ -1864,7 +1939,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
PrintCollection(&my_context->box64_path, "BOX64 BIN PATH");
|
||||
// lets build argc/argv stuff
|
||||
printf_log(LOG_INFO, "Looking for %s\n", prog);
|
||||
my_context->argv[0] = ResolveFile(prog, &my_context->box64_path);
|
||||
my_context->argv[0] = ResolveFileSoft(prog, &my_context->box64_path);
|
||||
// check if box86 is present
|
||||
{
|
||||
my_context->box86path = box_strdup(my_context->box64path);
|
||||
|
||||
+19
-34
@@ -66,7 +66,7 @@ rbtree* memprot = NULL;
|
||||
int have48bits = 0;
|
||||
static int inited = 0;
|
||||
|
||||
static rbtree* mapallmem = NULL;
|
||||
rbtree* mapallmem = NULL;
|
||||
static rbtree* mmapmem = NULL;
|
||||
|
||||
typedef struct blocklist_s {
|
||||
@@ -1499,15 +1499,12 @@ static void atfork_child_custommem(void)
|
||||
init_mutexes();
|
||||
}
|
||||
|
||||
void reserveHighMem()
|
||||
void my_reserveHighMem()
|
||||
{
|
||||
char* p = getenv("BOX64_RESERVE_HIGH");
|
||||
#if 0//def ADLINK
|
||||
if(p && p[0]=='0')
|
||||
#else
|
||||
if(!p || p[0]=='0')
|
||||
#endif
|
||||
return; // don't reserve by default
|
||||
static int reserved = 0;
|
||||
if(reserved || !have48bits)
|
||||
return;
|
||||
reserved = 1;
|
||||
uintptr_t cur = 1ULL<<47;
|
||||
uintptr_t bend = 0;
|
||||
uint32_t prot;
|
||||
@@ -1522,6 +1519,19 @@ void reserveHighMem()
|
||||
}
|
||||
cur = bend;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void reserveHighMem()
|
||||
{
|
||||
char* p = getenv("BOX64_RESERVE_HIGH");
|
||||
#if 0//def ADLINK
|
||||
if(p && p[0]=='0')
|
||||
#else
|
||||
if(!p || p[0]=='0')
|
||||
#endif
|
||||
return; // don't reserve by default
|
||||
my_reserveHighMem();
|
||||
}
|
||||
|
||||
void init_custommem_helper(box64context_t* ctx)
|
||||
@@ -1713,28 +1723,3 @@ int internal_munmap(void* addr, unsigned long length)
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
|
||||
extern int running32bits;
|
||||
EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
|
||||
{
|
||||
void* ret;
|
||||
if(!addr && ((running32bits && box64_mmap32) || (flags&0x40)))
|
||||
ret = my_mmap64(NULL, addr, length, prot, flags | 0x40, fd, offset);
|
||||
else
|
||||
ret = internal_mmap(addr, length, prot, flags, fd, offset);
|
||||
if(ret!=MAP_FAILED && mapallmem)
|
||||
setProtection((uintptr_t)ret, length, prot);
|
||||
return ret;
|
||||
}
|
||||
EXPORT void* mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset) __attribute__((alias("mmap64")));
|
||||
|
||||
EXPORT int munmap(void* addr, unsigned long length)
|
||||
{
|
||||
int ret = internal_munmap(addr, length);
|
||||
if(!ret && mapallmem) {
|
||||
freeProtection((uintptr_t)addr, length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
#endif
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#ifdef BUILD_DYNAMIC
|
||||
#define EXPORTDYN __attribute__((visibility("default")))
|
||||
#else
|
||||
#define EXPORTDYN
|
||||
#endif
|
||||
|
||||
typedef void x64emu_t;
|
||||
extern void* mapallmem;
|
||||
void setProtection(uintptr_t addr, size_t size, uint32_t prot);
|
||||
void freeProtection(uintptr_t addr, size_t size);
|
||||
void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
int internal_munmap(void* addr, unsigned long length);
|
||||
|
||||
void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
|
||||
extern int running32bits;
|
||||
extern int box64_mmap32;
|
||||
|
||||
EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
|
||||
{
|
||||
void* ret;
|
||||
if(!addr && ((running32bits && box64_mmap32) || (flags&0x40)))
|
||||
ret = my_mmap64(NULL, addr, length, prot, flags | 0x40, fd, offset);
|
||||
else
|
||||
ret = internal_mmap(addr, length, prot, flags, fd, offset);
|
||||
if(ret!=MAP_FAILED && mapallmem)
|
||||
setProtection((uintptr_t)ret, length, prot);
|
||||
return ret;
|
||||
}
|
||||
EXPORT void* mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset) __attribute__((alias("mmap64")));
|
||||
|
||||
EXPORT int munmap(void* addr, unsigned long length)
|
||||
{
|
||||
int ret = internal_munmap(addr, length);
|
||||
if(!ret && mapallmem) {
|
||||
freeProtection((uintptr_t)addr, length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -5,6 +5,41 @@
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
ARM64 Linux Call Convention
|
||||
|
||||
SP The Stack Pointer.
|
||||
r30 LR The Link Register.
|
||||
r29 FP The Frame Pointer
|
||||
r19…r28 Callee-saved registers
|
||||
r18 The Platform Register, if needed; otherwise a temporary register. See notes.
|
||||
r17 IP1 The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r16 IP0 The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r9…r15 Temporary registers
|
||||
r8 Indirect result location register
|
||||
r0…r7 Parameter/result registers
|
||||
|
||||
For SIMD:
|
||||
The first eight registers, v0-v7, are used to pass argument values into a subroutine and to return result values from a function.
|
||||
They may also be used to hold intermediate values within a routine (but, in general, only between subroutine calls).
|
||||
|
||||
Registers v8-v15 must be preserved by a callee across subroutine calls;
|
||||
the remaining registers (v0-v7, v16-v31) do not need to be preserved (or should be preserved by the caller).
|
||||
Additionally, only the bottom 64 bits of each value stored in v8-v15 need to be preserved [8];
|
||||
it is the responsibility of the caller to preserve larger values.
|
||||
|
||||
For SVE:
|
||||
z0-z7 are used to pass scalable vector arguments to a subroutine, and to return scalable vector results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such regisers, the subroutine must ensure that the entire contents of z8-z23 are preserved across the call.
|
||||
In other cases it need only preserve the low 64 bits of z8-z15, as described in SIMD and Floating-Point registers.
|
||||
p0-p3 are used to pass scalable predicate arguments to a subroutine and to return scalable predicate results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such registers, the subroutine must ensure that p4-p15 are preserved across the call.
|
||||
In other cases it need not preserve any scalable predicate register contents.
|
||||
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
@@ -782,8 +817,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define MSR_fpsr(Rt) EMIT(MRS_gen(0, 1, 3, 4, 4, 1, Rt))
|
||||
// mrs x0, cntvct_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b010
|
||||
#define MRS_cntvct_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b010, Rt))
|
||||
// mrs x0, cntpctss_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b101
|
||||
// mrs x0, cntpctss_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b101
|
||||
#define MRS_cntpctss_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b101, Rt))
|
||||
// mrs rt, rndr op0=0b11 op1=0b011 CRn=0b0010 CRm=0b0100 op2=0b000
|
||||
#define MRS_rndr(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b0010, 0b0100, 0b000, Rt))
|
||||
// NEON Saturation Bit
|
||||
#define FPSR_QC 27
|
||||
// NEON Input Denormal Cumulative
|
||||
@@ -1080,6 +1117,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VMOVHto(Wd, Vn, index) EMIT(UMOV_gen(0, ((index)<<2) | 2, Vn, Wd))
|
||||
#define VMOVSto(Wd, Vn, index) EMIT(UMOV_gen(0, ((index)<<3) | 4, Vn, Wd))
|
||||
|
||||
#define SMOV_gen(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 0b01<<13 | 0<<12 | 1<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SMOVQDto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<4) | 8, Vn, Xd))
|
||||
#define SMOVQBto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<1) | 1, Vn, Xd))
|
||||
#define SMOVQHto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<2) | 2, Vn, Xd))
|
||||
#define SMOVQSto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<3) | 4, Vn, Xd))
|
||||
|
||||
#define MVN_vector(Q, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | 0b10000<<17 | 0b00101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VMVNQ(Rd, Rn) EMIT(MVN_vector(1, Rn, Rd))
|
||||
|
||||
@@ -1150,6 +1193,13 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FABSS(Sd, Sn) EMIT(FNEGABS_scalar(0b00, 0b01, Sn, Sd))
|
||||
#define FABSD(Dd, Dn) EMIT(FNEGABS_scalar(0b01, 0b01, Dn, Dd))
|
||||
|
||||
#define FNEGABS_vector(Q, U, sz, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | 1<<23 | (sz)<<22 | 0b10000<<17 | 0b01111<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFNEGS(Vd, Vn) EMIT(FNEGABS_vector(0, 1, 0, Vn, Vd))
|
||||
#define VFNEGQS(Vd, Vn) EMIT(FNEGABS_vector(1, 1, 0, Vn, Vd))
|
||||
#define VFNEGQD(Vd, Vn) EMIT(FNEGABS_vector(1, 1, 1, Vn, Vd))
|
||||
#define VFABSS(Vd, Vn) EMIT(FNEGABS_vector(0, 0, 0, Vn, Vd))
|
||||
#define VFABSQS(Vd, Vn) EMIT(FNEGABS_vector(1, 0, 0, Vn, Vd))
|
||||
#define VFABSQD(Vd, Vn) EMIT(FNEGABS_vector(1, 0, 1, Vn, Vd))
|
||||
|
||||
// MUL
|
||||
#define FMUL_vector(Q, sz, Rm, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11011<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1161,11 +1211,6 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FMULS(Sd, Sn, Sm) EMIT(FMUL_scalar(0b00, Sm, Sn, Sd))
|
||||
#define FMULD(Dd, Dn, Dm) EMIT(FMUL_scalar(0b01, Dm, Dn, Dd))
|
||||
|
||||
#define FMLA_vector(Q, op, sz, Rm, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (op)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFMLAS(Sd, Sn, Sm) EMIT(FMLA_vector(0, 0, 0, Sm, Sn, Sd))
|
||||
#define VFMLAQS(Sd, Sn, Sm) EMIT(FMLA_vector(1, 0, 0, Sm, Sn, Sd))
|
||||
#define VFMLAQD(Dd, Dn, Dm) EMIT(FMLA_vector(1, 0, 1, Dm, Dn, Dd))
|
||||
|
||||
// DIV
|
||||
#define FDIV_vector(Q, sz, Rm, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11111<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFDIVS(Sd, Sn, Sm) EMIT(FDIV_vector(0, 0, Sm, Sn, Sd))
|
||||
@@ -1367,18 +1412,30 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FCVTN(Vd, Vn) EMIT(FCVTN_vector(0, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Double to higher Vd as 2*float, use FPCR rounding
|
||||
#define FCVTN2(Vd, Vn) EMIT(FCVTN_vector(1, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Float to lower Vd as 2*float16 and clears the upper half, use FPCR rounding
|
||||
#define FCVTN16(Vd, Vn) EMIT(FCVTN_vector(0, 0, Vn, Vd))
|
||||
// Convert Vn from 2*Float to higher Vd as 2*float16, use FPCR rounding
|
||||
#define FCVTN162(Vd, Vn) EMIT(FCVTN_vector(1, 0, Vn, Vd))
|
||||
|
||||
#define FCVTXN_vector(Q, sz, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b10110<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert Vn from 2*Double to lower Vd as 2*float and clears the upper half
|
||||
#define FCVTXN(Vd, Vn) EMIT(FCVTXN_vector(0, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Double to higher Vd as 2*float
|
||||
#define FCVTXN2(Vd, Vn) EMIT(FCVTXN_vector(1, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Float to lower Vd as 2*float16 and clears the upper half
|
||||
#define FCVTXN16(Vd, Vn) EMIT(FCVTXN_vector(0, 0, Vn, Vd))
|
||||
// Convert Vn from 2*Float to higher Vd as 2*float16
|
||||
#define FCVTXN162(Vd, Vn) EMIT(FCVTXN_vector(1, 0, Vn, Vd))
|
||||
|
||||
#define FCVTL_vector(Q, sz, Rn, Rd) ((Q)<<30 | 0<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b10111<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert lower Vn from 2*float to Vd as 2*double
|
||||
#define FCVTL(Vd, Vn) EMIT(FCVTL_vector(0, 1, Vn, Vd))
|
||||
// Convert higher Vn from 2*float to Vd as 2*double
|
||||
#define FCVTL2(Vd, Vn) EMIT(FCVTL_vector(1, 1, Vn, Vd))
|
||||
// Convert lower Vn from 2*float16 to Vd as 2*float
|
||||
#define FCVTL16(Vd, Vn) EMIT(FCVTL_vector(0, 0, Vn, Vd))
|
||||
// Convert higher Vn from 2*float16 to Vd as 2*float
|
||||
#define FCVTL162(Vd, Vn) EMIT(FCVTL_vector(1, 0, Vn, Vd))
|
||||
|
||||
#define SCVTF_scalar(sf, type, rmode, opcode, Rn, Rd) ((sf)<<31 | 0b11110<<24 | (type)<<22 | 1<<21 | (rmode)<<19 | (opcode)<<16 | (Rn)<<5 | (Rd))
|
||||
#define SCVTFSw(Sd, Wn) EMIT(SCVTF_scalar(0, 0b00, 0b00, 0b010, Wn, Sd))
|
||||
@@ -1450,6 +1507,37 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// FMAXNM NaN vs Number: number is picked
|
||||
#define FMAXNMD(Dd, Dn, Dm) EMIT(FMINMAX_scalar(0b01, Dm, 0b10, Dn, Dd))
|
||||
|
||||
// Fused Add Multiply
|
||||
#define FMADD_gen(type, o1, Rm, o0, Ra, Rn, Rd) (0b11111<<24 | (type)<<22 | (o1)<<21 | (Rm)<<16 | (o0)<<15 | (Ra)<<10 | (Rn)<<5 | (Rd))
|
||||
// scalar Rd = Ra + Rn*Rm
|
||||
#define FMADD_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 0, Sm, 0, Sa, Sn, Sd))
|
||||
// scalar Rd = Ra + Rn*Rm
|
||||
#define FMADD_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 0, Dm, 0, Da, Dn, Dd))
|
||||
// scalar Rd = -Ra - Rn*Rm
|
||||
#define FNMADD_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 1, Sm, 0, Sa, Sn, Sd))
|
||||
// scalar Rd = -Ra - Rn*Rm
|
||||
#define FNMADD_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 1, Dm, 0, Da, Dn, Dd))
|
||||
// scalar Rd = Ra - Rn*Rm
|
||||
#define FMSUB_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 0, Sm, 1, Sa, Sn, Sd))
|
||||
// scalar Rd = Ra - Rn*Rm
|
||||
#define FMSUB_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 0, Dm, 1, Da, Dn, Dd))
|
||||
// scalar Rd = -Ra + Rn*Rm
|
||||
#define FNMSUB_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 1, Sm, 1, Sa, Sn, Sd))
|
||||
// scalar Rd = -Ra + Rn*Rm
|
||||
#define FNMSUB_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 1, Dm, 1, Da, Dn, Dd))
|
||||
|
||||
#define FMLA_vector(Q, op, sz, Rm, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (op)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
// Vd += Vn*Vm
|
||||
#define VFMLAS(Vd, Vn, Vm) EMIT(FMLA_vector(0, 0, 0, Vm, Vn, Vd))
|
||||
// Vd += Vn*Vm
|
||||
#define VFMLAQS(Vd, Vn, Vm) EMIT(FMLA_vector(1, 0, 0, Vm, Vn, Vd))
|
||||
// Vd += Vn*Vm
|
||||
#define VFMLAQD(Vd, Vn, Vm) EMIT(FMLA_vector(1, 0, 1, Vm, Vn, Vd))
|
||||
// Vd -= Vn*Vm
|
||||
#define VFMLSQS(Vd, Vn, Vm) EMIT(FMLA_vector(1, 1, 0, Vm, Vn, Vd))
|
||||
// Vd -= Vn*Vm
|
||||
#define VFMLSQD(Vd, Vn, Vm) EMIT(FMLA_vector(1, 1, 1, Vm, Vn, Vd))
|
||||
|
||||
// ZIP / UZP
|
||||
#define ZIP_gen(Q, size, Rm, op, Rn, Rd) ((Q)<<30 | 0b001110<<24 | (size)<<22 | (Rm)<<16 | (op)<<14 | 0b11<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VZIP1Q_8(Rt, Rn, Rm) EMIT(ZIP_gen(1, 0b00, Rm, 0, Rn, Rt))
|
||||
@@ -1483,6 +1571,16 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VUZP1Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 0, Rn, Rt))
|
||||
#define VUZP2Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 1, Rn, Rt))
|
||||
|
||||
#define BITBIF_gen(Q, opc2, Rm, Rn, Rd) ((Q)<<30 | 0b101110<<24 | (opc2)<<22 | 1<<21 | (Rm)<<16 | 0b000111<<10 | (Rn)<<5 | (Rd))
|
||||
// Bitwise insert Vn in Vd if Vm is "0"
|
||||
#define VBIF(Vd, Vn,Vm) EMIT(BITBIF_gen(0, 0b11, Vm, Vn, Vd))
|
||||
// Bitwise insert Vn in Vd if Vm is "0"
|
||||
#define VBIFQ(Vd, Vn,Vm) EMIT(BITBIF_gen(1, 0b11, Vm, Vn, Vd))
|
||||
// Bitwise insert Vn in Vd if Vm is "1"
|
||||
#define VBIT(Vd, Vn,Vm) EMIT(BITBIF_gen(0, 0b10, Vm, Vn, Vd))
|
||||
// Bitwise insert Vn in Vd if Vm is "1"
|
||||
#define VBITQ(Vd, Vn,Vm) EMIT(BITBIF_gen(1, 0b10, Vm, Vn, Vd))
|
||||
|
||||
#define DUP_element(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VDUP_8(Vd, Vn, idx) EMIT(DUP_element(0, ((idx)<<1|1), Vn, Vd))
|
||||
#define VDUPQ_8(Vd, Vn, idx) EMIT(DUP_element(1, ((idx)<<1|1), Vn, Vd))
|
||||
@@ -1627,8 +1725,8 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VCHIQQ_64(Rd, Rn, Rm) EMIT(CMG_vector(1, 1, 0b11, 0, Rm, Rn, Rd))
|
||||
|
||||
// Less Than 0
|
||||
#define CMLT_0_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b01010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define CMLT_0_8(Rd, Rn) EMIT(CMLT_0_vector(0, 0b00, Rn, Rd))
|
||||
#define CMLT_0_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b01010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define CMLT_0_8(Rd, Rn) EMIT(CMLT_0_vector(0, 0b00, Rn, Rd))
|
||||
#define CMLT_0_16(Rd, Rn) EMIT(CMLT_0_vector(0, 0b01, Rn, Rd))
|
||||
#define CMLT_0_32(Rd, Rn) EMIT(CMLT_0_vector(0, 0b10, Rn, Rd))
|
||||
#define CMLTQ_0_8(Rd, Rn) EMIT(CMLT_0_vector(1, 0b00, Rn, Rd))
|
||||
@@ -1812,8 +1910,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define MOVI_vector(Q, op, abc, cmode, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
#define MOVIQ_8(Rd, imm8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_16(Rd, imm8, lsl8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b1000|((lsl8)?0b10:0), ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_32(Rd, imm8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b0000, ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_32_lsl(Rd, imm8, lsl8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), (lsl8<<1), ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_64(Rd, imm8) EMIT(MOVI_vector(1, 1, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_8(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_16(Rd, imm8, lsl8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1000|((lsl8)?0b10:0), ((imm8)&0b11111), Rd))
|
||||
#define MOVI_32_lsl(Rd, imm8, lsl8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), (lsl8<<1), ((imm8)&0b11111), Rd))
|
||||
#define MOVI_32(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b0000, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_64(Rd, imm8) EMIT(MOVI_vector(0, 1, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
|
||||
@@ -1915,6 +2017,33 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define UMINQ_32(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b10, Vm, 1, Vn, Vd))
|
||||
//#define UMINQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b11, Vm, 1, Vn, Vd))
|
||||
|
||||
// MIN or MAX accros vector
|
||||
#define MAXMINV_vector(Q, U, size, op, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b11000<<17 | (op)<<16 | 0b1010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define SMAXV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b00, 0, Vn, Vd))
|
||||
#define SMINV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b00, 1, Vn, Vd))
|
||||
#define UMAXV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b00, 0, Vn, Vd))
|
||||
#define UMINV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b00, 1, Vn, Vd))
|
||||
#define SMAXV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b01, 0, Vn, Vd))
|
||||
#define SMINV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b01, 1, Vn, Vd))
|
||||
#define UMAXV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b01, 0, Vn, Vd))
|
||||
#define UMINV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b01, 1, Vn, Vd))
|
||||
#define SMAXV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b10, 0, Vn, Vd))
|
||||
#define SMINV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b10, 1, Vn, Vd))
|
||||
#define UMAXV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b10, 0, Vn, Vd))
|
||||
#define UMINV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b10, 1, Vn, Vd))
|
||||
#define SMAXVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b00, 0, Vn, Vd))
|
||||
#define SMINVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b00, 1, Vn, Vd))
|
||||
#define UMAXVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b00, 0, Vn, Vd))
|
||||
#define UMINVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b00, 1, Vn, Vd))
|
||||
#define SMAXVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b01, 0, Vn, Vd))
|
||||
#define SMINVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b01, 1, Vn, Vd))
|
||||
#define UMAXVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b01, 0, Vn, Vd))
|
||||
#define UMINVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b01, 1, Vn, Vd))
|
||||
#define SMAXVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b10, 0, Vn, Vd))
|
||||
#define SMINVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b10, 1, Vn, Vd))
|
||||
#define UMAXVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b10, 0, Vn, Vd))
|
||||
#define UMINVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b10, 1, Vn, Vd))
|
||||
|
||||
// HADD vector
|
||||
#define HADD_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SHADD_8(Vd, Vn, Vm) EMIT(HADD_vector(0, 0, 0b00, Vm, Vn, Vd))
|
||||
|
||||
@@ -5,82 +5,84 @@
|
||||
|
||||
// Returns the packed valid-N-imms-immr (1-1-6-6 bits); returns 0 if bitmask is not encodable
|
||||
int convert_bitmask(uint64_t bitmask) {
|
||||
if (!bitmask || !~bitmask) return 0;
|
||||
|
||||
uint64_t size, mask, pat;
|
||||
|
||||
for (size = 6; size > 1; --size) {
|
||||
mask = (one << (1 << (size - 1))) - 1;
|
||||
pat = bitmask & mask;
|
||||
// printf("%016lX/%lu: %016lX %016lX %2d\n", bitmask, size, mask, pat, (1 << (size - 1)));
|
||||
if (pat != ((bitmask >> (1 << (size - 1))) & mask)) {
|
||||
// printf("%016lX/%lu: %016lX %016lX xx\n", bitmask, size, pat, (bitmask >> (1 << (size - 1))) & mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mask = (size >= 6) ? ((uint64_t)-1) : ((one << (1 << size)) - 1);
|
||||
pat = bitmask & mask;
|
||||
for (uint64_t i = 1; i < 7 - size; ++i) {
|
||||
uint64_t boff = i * (1 << size);
|
||||
if (((bitmask >> boff) & mask) != pat) {
|
||||
// printf("%016lX/%lu: no %lu %lu %016lX %016lX %016lX\n", bitmask, size, i, size, boff, mask, pat);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Note that here, pat != 0 and ~pat & (1 << size) != 0 (otherwise size = 1 and bitmask = all 0 or all 1)
|
||||
int immr = 0;
|
||||
uint64_t last_bit = one << ((1 << size) - 1);
|
||||
// printf("%016lX/%lu: %016lX %016lX %lu\n", bitmask, size, mask, pat, last_bit);
|
||||
if (pat & 1) {
|
||||
while (pat & last_bit) {
|
||||
pat = ((pat - last_bit) << 1) + 1;
|
||||
++immr;
|
||||
}
|
||||
} else {
|
||||
immr = 1 << size;
|
||||
while (!(pat & 1)) {
|
||||
pat >>= 1;
|
||||
--immr;
|
||||
}
|
||||
}
|
||||
// printf("%016lX/%lu: %016lX %016lX %lu %d\n", bitmask, size, mask, pat, last_bit, immr);
|
||||
if (pat & (pat + 1)) return 0; // Not 0...01...1
|
||||
int to = 1;
|
||||
while (pat & (one << to)) ++to;
|
||||
|
||||
// printf("%016lX/%lu: returning %c%c%02lX%02lX\n", bitmask, size, '2' + (size == 6), (uint64_t)(((0x1E << size) & 0x3F) + (to - 1)), (uint64_t)immr);
|
||||
return 0x2000 + ((size == 6) << 12) + ((((0x1E << size) & 0x3F) + (to - 1)) << 6) + immr;
|
||||
if (bitmask == 0 || bitmask == ~0ULL) return 0;
|
||||
|
||||
uint64_t size, mask, pat;
|
||||
|
||||
for (size = 6; size > 1; --size) {
|
||||
mask = (one << (1 << (size - 1))) - 1;
|
||||
pat = bitmask & mask;
|
||||
|
||||
if (pat != ((bitmask >> (1 << (size - 1))) & mask)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mask = (size >= 6) ? ~0ULL : ((one << (1 << size)) - 1);
|
||||
pat = bitmask & mask;
|
||||
|
||||
for (uint64_t i = 1; i < 7 - size; ++i) {
|
||||
uint64_t boff = i * (1 << size);
|
||||
if (((bitmask >> boff) & mask) != pat) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int immr = 0;
|
||||
uint64_t last_bit = one << ((1 << size) - 1);
|
||||
|
||||
if (pat & 1) {
|
||||
while (pat & last_bit) {
|
||||
pat = ((pat - last_bit) << 1) | 1;
|
||||
++immr;
|
||||
}
|
||||
} else {
|
||||
immr = 1 << size;
|
||||
while (!(pat & 1)) {
|
||||
pat >>= 1;
|
||||
--immr;
|
||||
}
|
||||
}
|
||||
|
||||
if (pat & (pat + 1)) return 0;
|
||||
|
||||
int to = 1;
|
||||
while (pat & (one << to)) ++to;
|
||||
|
||||
return 0x2000 + ((size == 6) << 12) + ((((0x1E << size) & 0x3F) + (to - 1)) << 6) + immr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <unordered_set>
|
||||
int main() {
|
||||
std::unordered_set<uint64_t> okvals;
|
||||
uint64_t val;
|
||||
for (int n = 1; n < 7; ++n) {
|
||||
int imms0 = ((n == 6) ? 0xC0 : 0x80) + ((0x1E << n) & 0x3F);
|
||||
for (int nones = 0; nones < (1 << n) - 1; ++nones) {
|
||||
val = (one << (nones + 1)) - 1;
|
||||
for (int j = 0; j < 6 - n; ++j) {
|
||||
val = val + (val << (1 << (n + j)));
|
||||
}
|
||||
for (int immr = 0; immr < (1 << n); ++immr) {
|
||||
int exp = ((imms0 + nones) << 6) + immr;
|
||||
int got = convert_bitmask(val);
|
||||
if (exp != got) {
|
||||
printf("0x%016lX: expected %04X, got %04X\n", val, exp, got);
|
||||
}
|
||||
okvals.emplace(val);
|
||||
val = (val >> 1) + ((val & 1) << 63);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unordered_set<uint64_t> okvals;
|
||||
uint64_t val;
|
||||
|
||||
for (int n = 1; n < 7; ++n) {
|
||||
int imms0 = ((n == 6) ? 0xC0 : 0x80) + ((0x1E << n) & 0x3F);
|
||||
for (int nones = 0; nones < (1 << n) - 1; ++nones) {
|
||||
val = (one << (nones + 1)) - 1;
|
||||
for (int j = 0; j < 6 - n; ++j) {
|
||||
val += val << (1 << (n + j));
|
||||
}
|
||||
for (int immr = 0; immr < (1 << n); ++immr) {
|
||||
int exp = ((imms0 + nones) << 6) + immr;
|
||||
int got = convert_bitmask(val);
|
||||
if (exp != got) {
|
||||
printf("0x%016lX: expected %04X, got %04X\n", val, exp, got);
|
||||
}
|
||||
okvals.emplace(val);
|
||||
val = (val >> 1) | ((val & 1) << 63);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for
|
||||
for (uint64_t i = 1; i < 0xFFFFFFFFFFFFFFFFu; ++i) {
|
||||
int got = convert_bitmask(val);
|
||||
if (!!got != (okvals.find(val) != okvals.cend())) {
|
||||
printf("0x%016lX: expected %s, got %04X\n", val, (!!got ? "0000" : "non0"), got);
|
||||
}
|
||||
}
|
||||
for (uint64_t i = 1; i < 0xFFFFFFFFFFFFFFFFu; ++i) {
|
||||
int got = convert_bitmask(i);
|
||||
if (!!got != (okvals.find(i) != okvals.cend())) {
|
||||
printf("0x%016lX: expected %s, got %04X\n", i, (!!got ? "non0" : "0000"), got);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -916,7 +916,6 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
// UMOV
|
||||
if(isMask(opcode, "0Q001110000rrrrr001111nnnnnddddd", &a)) {
|
||||
char q = a.Q?'Q':'D';
|
||||
char s = '?';
|
||||
int sz=0;
|
||||
if(a.Q==0 && immr&1) {s='B'; sz=0; }
|
||||
@@ -925,9 +924,24 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
else if(a.Q==1 && (immr&15)==8) {s='D'; sz=3; }
|
||||
int index = (immr)>>(sz+1);
|
||||
if(sz>2)
|
||||
snprintf(buff, sizeof(buff), "MOV %s, %c%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], q, Rn, s, index);
|
||||
snprintf(buff, sizeof(buff), "MOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "UMOV %s, %c%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], q, Rn, s, index);
|
||||
snprintf(buff, sizeof(buff), "UMOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
return buff;
|
||||
}
|
||||
// SMOV
|
||||
if(isMask(opcode, "0Q001110000rrrrr001011nnnnnddddd", &a)) {
|
||||
char s = '?';
|
||||
int sz=0;
|
||||
if(a.Q==0 && immr&1) {s='B'; sz=0; }
|
||||
else if(/*a.Q==0 &&*/ (immr&3)==2) {s='H'; sz=1; }
|
||||
else if(/*a.Q==0 &&*/ (immr&7)==4) {s='S'; sz=2; }
|
||||
else if(a.Q==1 && (immr&15)==8) {s='D'; sz=3; }
|
||||
int index = (immr)>>(sz+1);
|
||||
if(sz>2)
|
||||
snprintf(buff, sizeof(buff), "MOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "SMOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
return buff;
|
||||
}
|
||||
// VEOR
|
||||
@@ -952,6 +966,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "VMUL V%d.%s, V%d.%s, V%d.%s", Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
// VBIT / VBIF
|
||||
if(isMask(opcode, "0Q1011101o1mmmmm000111nnnnnddddd", &a)) {
|
||||
char q = a.Q?'Q':'D';
|
||||
snprintf(buff, sizeof(buff), "VBI%c %c%d, %c%d, %c%d", a.o?'F':'T', q, Rd, q, Rn, q, Rm);
|
||||
return buff;
|
||||
}
|
||||
// CMP
|
||||
if(isMask(opcode, "0Q101110ff1mmmmm100011nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
@@ -1007,6 +1027,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm<<8);
|
||||
return buff;
|
||||
}
|
||||
// MOV immediate 64bits
|
||||
if(isMask(opcode, "0Q10111100000iii111001iiiiiddddd", &a)) {
|
||||
uint64_t tmp64u = 0;
|
||||
for(int i=0; i<8; ++i)
|
||||
if((imm)&(1<<i))
|
||||
tmp64u |= 0xffLL<<(i*8);
|
||||
|
||||
if(a.Q)
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.2D, #0x%016lx", Rd, tmp64u);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "MOVI D%d, #0x%016lx", Rd, tmp64u);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// Shift
|
||||
if(isMask(opcode, "0QU011110hhhhrrr000001nnnnnddddd", &a)) {
|
||||
@@ -1297,6 +1330,28 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "F%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FMADD
|
||||
if(isMask(opcode, "00011111tt0mmmmmoaaaaannnnnddddd", &a)) {
|
||||
char s = (a.t==0b00)?'S':((a.t==0b01)?'D':'?');
|
||||
int n = (a.t==0)?1:2;
|
||||
snprintf(buff, sizeof(buff), "FM%s V%d.%d%c, V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"SUB":"ADD", Rd, n, s, Ra, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FNMADD
|
||||
if(isMask(opcode, "00011111tt1mmmmmoaaaaannnnnddddd", &a)) {
|
||||
char s = (a.t==0b00)?'S':((a.t==0b01)?'D':'?');
|
||||
int n = (a.t==0)?1:2;
|
||||
snprintf(buff, sizeof(buff), "FNM%s V%d.%d%c, V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"SUB":"ADD", Rd, n, s, Ra, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FMLA
|
||||
if(isMask(opcode, "0Q001110of1mmmmm110011nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "FML%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"S":"A", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// NEG
|
||||
if(isMask(opcode, "0Q101110ff100000101110nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
@@ -1596,7 +1651,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
if((imm&0b0001)==0b0001) sz=0;
|
||||
else if((imm&0b0011)==0b0010) sz=1;
|
||||
else if((imm&0b0111)==0b0100) sz=2;
|
||||
int sh=imm - (1<<sz);
|
||||
int sh=(imm>>sz) - 1;
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
const char* Vn = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "DUP V%d.%s, V%d.%s[%d]", Rd, Vd, Rn, Vn, sh);
|
||||
|
||||
@@ -760,7 +760,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("BOUND Gd, Ed");
|
||||
nextop = F8;
|
||||
FAKEED(0);
|
||||
FAKEED;
|
||||
}
|
||||
break;
|
||||
case 0x63:
|
||||
@@ -1012,12 +1012,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
/* inside the block, cache transform */ \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
B(i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
/* inside the block, no cache change */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
@@ -2206,7 +2207,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
vex_t vex = {0};
|
||||
vex.rex = rex;
|
||||
u8 = nextop;
|
||||
vex.m = u8&0b00011111;
|
||||
vex.rex.b = (u8&0b00100000)?0:1;
|
||||
vex.rex.x = (u8&0b01000000)?0:1;
|
||||
vex.rex.r = (u8&0b10000000)?0:1;
|
||||
u8 = F8;
|
||||
vex.p = u8&0b00000011;
|
||||
vex.l = (u8>>2)&1;
|
||||
vex.v = ((~u8)>>3)&0b1111;
|
||||
vex.rex.w = (u8>>7)&1;
|
||||
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
case 0xC5:
|
||||
@@ -2220,7 +2233,18 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
vex_t vex = {0};
|
||||
vex.rex = rex;
|
||||
u8 = nextop;
|
||||
vex.p = u8&0b00000011;
|
||||
vex.l = (u8>>2)&1;
|
||||
vex.v = ((~u8)>>3)&0b1111;
|
||||
vex.rex.r = (u8&0b10000000)?0:1;
|
||||
vex.rex.b = 0;
|
||||
vex.rex.x = 0;
|
||||
vex.rex.w = 0;
|
||||
vex.m = VEX_M_0F;
|
||||
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
@@ -2554,6 +2578,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
UFLAG_DF(x2, d_none);
|
||||
TSTw_mask(xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
@@ -2565,13 +2590,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EBBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x2, 7);
|
||||
B_MARK(cNE);
|
||||
ADDxw_REG_LSR(x3, ed, ed, 7);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
MARK;
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(x2, 7);
|
||||
B_MARK(cNE);
|
||||
EORxw_REG_LSR(x3, ed, ed, 7);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
MARK;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -2580,6 +2608,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
UFLAG_DF(x2, d_none);
|
||||
TSTw_mask(xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
@@ -2589,14 +2618,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EBBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x2, 1);
|
||||
B_MARK(cNE);
|
||||
LSRxw(x2, ed, 6); // x2 = d>>30
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
MARK;
|
||||
BFXILw(xFlags, ed, 7, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(x2, 1);
|
||||
B_MARK(cNE);
|
||||
LSRxw(x2, ed, 6); // x2 = d>>6
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>6) ^ ((d>>6)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
MARK;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, ed, 7, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -2680,6 +2712,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
UFLAG_DF(x2, d_none);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
@@ -2702,13 +2735,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
RORxw_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x3, rex.w?63:31);
|
||||
B_MARK(cNE);
|
||||
ADDxw_REG_LSR(x1, ed, ed, rex.w?63:31);
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
MARK;
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(x3, rex.w?63:31);
|
||||
B_MARK(cNE);
|
||||
ADDxw_REG_LSR(x1, ed, ed, rex.w?63:31);
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
MARK;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -2717,6 +2753,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
UFLAG_DF(x2, d_none);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
@@ -2737,14 +2774,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
RORxw_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x3, 1);
|
||||
B_MARK(cNE);
|
||||
LSRxw(x2, ed, rex.w?62:30); // x2 = d>>30
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
MARK;
|
||||
BFXILxw(xFlags, ed, rex.w?63:31, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(x3, 1);
|
||||
B_MARK(cNE);
|
||||
LSRxw(x2, ed, rex.w?62:30); // x2 = d>>30
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
MARK;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, rex.w?63:31, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
|
||||
@@ -68,15 +68,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
INST_NAME("XGETBV");
|
||||
CMPSw_REG(xRCX, xZR);
|
||||
B_MARK(cEQ);
|
||||
UDF(0);
|
||||
MARK;
|
||||
MOV32w(xRAX, 0b111);
|
||||
MOV32w(xRDX, 0);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -103,7 +101,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
LSRx(xRDX, x1, 32);
|
||||
MOVw_REG(xRAX, x1); // wipe upper part
|
||||
MOVw_REG(xRCX, xZR); // IA32_TSC, 0 for now
|
||||
CALL_(helper_getcpu, x1, x3);
|
||||
MOVw_REG(xRCX, x1); // IA32_TSC, 0 for now
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -389,7 +388,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEM(q1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
SCVTFS(d0, q1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -425,7 +424,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
@@ -463,7 +462,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
@@ -518,7 +517,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
MOVI_8(d0, 0b10000111);
|
||||
VAND(d0, d0, q1); // mask the index
|
||||
VTBL1_8(q0, q0, d0);
|
||||
@@ -542,7 +541,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1_16(v0, q0, q1);
|
||||
VUZP2_16(q0, q0, q1);
|
||||
SQADD_16(q0, q0, v0);
|
||||
@@ -552,8 +551,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UXTL_8(v0, q0); // this is unsigned, so 0 extended
|
||||
SXTL_8(v1, q1); // this is signed
|
||||
VMULQ_16(v0, v0, v1);
|
||||
@@ -565,7 +564,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1_16(v0, q0, q1);
|
||||
VUZP2_16(q0, q0, q1);
|
||||
VSUB_16(q0, v0, q0);
|
||||
@@ -575,7 +574,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1_32(v0, q0, q1);
|
||||
VUZP2_32(q0, q0, q1);
|
||||
VSUB_32(q0, v0, q0);
|
||||
@@ -585,7 +584,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1_16(v0, q0, q1);
|
||||
VUZP2_16(q0, q0, q1);
|
||||
SQSUB_16(q0, v0, q0);
|
||||
@@ -595,8 +594,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
CMGT_0_8(v0, q1);
|
||||
VAND(v0, v0, q0);
|
||||
CMLT_0_8(v1, q1);
|
||||
@@ -608,8 +607,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
CMGT_0_16(v0, q1);
|
||||
VAND(v0, v0, q0);
|
||||
CMLT_0_16(v1, q1);
|
||||
@@ -621,8 +620,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
CMGT_0_32(v0, q1);
|
||||
VAND(v0, v0, q0);
|
||||
CMLT_0_32(v1, q1);
|
||||
@@ -663,10 +662,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(v0, v0, v0);
|
||||
if(arm64_sha1) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVeS(v1, 0, q0, 3);
|
||||
SHA1H(v1, v1);
|
||||
VMOVeS(v0, 3, v1, 0);
|
||||
@@ -682,7 +681,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(v0, q1, q0, 8);
|
||||
VEORQ(q0, q0, v0);
|
||||
break;
|
||||
@@ -698,7 +697,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(q0==q1)
|
||||
v0 = q0;
|
||||
else {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(v0, q1, q1, 8);
|
||||
VREV64Q_32(v0, v0);
|
||||
}
|
||||
@@ -735,14 +734,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(MODREG) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
} else
|
||||
v1 = q1;
|
||||
VREV64Q_32(q0, q0);
|
||||
VREV64Q_32(v1, q1);
|
||||
if(q0==q1) {
|
||||
VMOVQ(v1, q0);
|
||||
} else {
|
||||
VREV64Q_32(v1, q1);
|
||||
}
|
||||
VZIP1Q_64(v0, v1, q0);
|
||||
VZIP2Q_64(v1, v1, q0);
|
||||
SHA256H(v1, v0, d0);
|
||||
@@ -801,9 +804,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_sha2) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(v1, v1, v1);
|
||||
VMOVQ(v0, q0);
|
||||
SHA256SU1(v0, v1, q1); // low v0 are ok and also need to be feed again SHA256SU1 to get the high part
|
||||
@@ -874,7 +877,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(u8>15) {
|
||||
VEOR(q0, q0, q0);
|
||||
} else if(u8>7) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEOR(d0, d0, d0);
|
||||
VEXT_8(q0, q0, d0, u8-8);
|
||||
} else {
|
||||
@@ -889,17 +892,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8&3;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(v0, q0, q0, 8);
|
||||
VREV64Q_32(v0, v0);
|
||||
VEORQ(d1, d1, d1);
|
||||
if(MODREG) {
|
||||
if(q0==q1)
|
||||
v1 = v0;
|
||||
else
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
} else
|
||||
v1 = q1;
|
||||
if(v1!=v0) {
|
||||
@@ -1025,10 +1025,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
// more precise
|
||||
if(q1==q0)
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
v1 = q1;
|
||||
VFRSQRTEQS(v0, q0);
|
||||
@@ -1043,10 +1043,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
if(q0 == q1)
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
v1 = q1;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFRECPEQS(v0, q0);
|
||||
VFRECPSQS(v1, v0, q0);
|
||||
VFMULQS(q1, v0, v1);
|
||||
@@ -1128,14 +1128,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, v1, q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
}
|
||||
VFMINQS(v0, v0, v1);
|
||||
if(!box64_dynarec_fastnan && (v0!=v1)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source is NaN
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
@@ -1151,14 +1149,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, v1, q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
}
|
||||
VFMAXQS(v0, v0, v1);
|
||||
if(!box64_dynarec_fastnan && (v0!=v1)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source is NaN
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gm,Em");
|
||||
@@ -1186,7 +1182,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVeD(q0, 0, d0, 0);
|
||||
VMOVeD(q0, 1, d1, 0);
|
||||
SQXTN_8(d0, q0);
|
||||
@@ -1216,7 +1212,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("PACKUSWB Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
@@ -1252,7 +1248,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("PACKSSDW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
if(MODREG) {
|
||||
GETEM(v1, 0);
|
||||
@@ -1339,7 +1335,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
(4)|(5<<8),
|
||||
(6)|(7<<8)
|
||||
};
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
tmp64u = swp[(u8>>(0*2))&3] | (swp[(u8>>(1*2))&3]<<16);
|
||||
tmp64u |= (swp[(u8>>(2*2))&3]<<32) | (swp[(u8>>(3*2))&3]<<48);
|
||||
MOV64x(x2, tmp64u);
|
||||
@@ -1805,6 +1801,24 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STW(x4, ed, fixedaddress);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("XSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.is32bits);
|
||||
CALL((void*)fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.is32bits);
|
||||
CALL((void*)fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
@@ -2124,7 +2138,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SETFLAGS(X_ZF, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -2134,12 +2148,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
RBITxw(x1, ed); // reverse
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == BSF
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFX(X_ZF) {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SETFLAGS(X_ZF, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -2150,8 +2166,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SUBxw_U12(gd, gd, rex.w?63:31);
|
||||
NEGxw_REG(gd, gd); // complement
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFX(X_ZF) {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
@@ -2222,7 +2240,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 2: VFCMGEQS(v0, v1, v0); break; // Less or equal
|
||||
case 3: VFCMEQQS(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
}
|
||||
@@ -2233,7 +2251,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6: VFCMGEQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
|
||||
case 7: VFCMEQQS(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
}
|
||||
@@ -2296,7 +2314,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else if(v0==v1 && (u8==0xe5)) { // easy special case
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
// first two elements from Gx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v0, (u8>>(i*2))&3);
|
||||
@@ -2319,8 +2337,30 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC7:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
if(MODREG) switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
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(arm64_rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?((void*)get_random64):((void*)get_random32), x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
MOVxw_REG(ed, x1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
} else switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SMREAD();
|
||||
@@ -2346,6 +2386,30 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("Unsupported XSAVEC Ed");
|
||||
FAKEED;
|
||||
UDF(0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
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(arm64_rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?((void*)get_random64):((void*)get_random32), x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
STxw(x1, wback, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -2368,12 +2432,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
if(MODREG) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
else {
|
||||
q0 = d1;
|
||||
}
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVBto(x1, d1, 0);
|
||||
MOVZw(x2, 16);
|
||||
SUBSw_REG(x2, x2, x1);
|
||||
@@ -2393,12 +2457,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
if(MODREG) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
else {
|
||||
q0 = d1;
|
||||
}
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVBto(x1, d1, 0);
|
||||
MOVZw(x2, 32);
|
||||
SUBSw_REG(x2, x2, x1);
|
||||
@@ -2417,7 +2481,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
//MOVI_64(v0, 64); not 64!
|
||||
MOV32w(x1, 64);
|
||||
VMOVQDfrom(v0, 0, x1);
|
||||
@@ -2443,9 +2507,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xD7:
|
||||
nextop = F8;
|
||||
INST_NAME("PMOVMSKB Gd, Em");
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEM(q0, 0);
|
||||
GETGD;
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
@@ -2524,8 +2588,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 15);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +15 values
|
||||
@@ -2538,8 +2602,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 31);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +31 values
|
||||
@@ -2560,7 +2624,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VSMULL_16(q0, v0, v1);
|
||||
SQSHRN_16(v0, q0, 16);
|
||||
break;
|
||||
@@ -2620,7 +2684,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SQADD_16(d0, d0, d1);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("PMAXSW Gx,Ex");
|
||||
INST_NAME("PMAXSW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(q0, 0);
|
||||
@@ -2645,7 +2709,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVHto(x1, d1, 0);
|
||||
VDUPH(v0, x1);
|
||||
USHL_16(d0, d0, v0);
|
||||
@@ -2655,8 +2719,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 32);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +32 values
|
||||
@@ -2668,8 +2732,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 64);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +64 values
|
||||
@@ -2687,7 +2751,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VSMULL_16(q0, v0, v1);
|
||||
VADDPQ_32(q0, q0, q0); //ADDP from Q to non-Q?
|
||||
VMOVQ(v0, q0);
|
||||
@@ -2697,8 +2761,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VEOR(d1, d1, d1); // is it necessary?
|
||||
UABDL_8(d0, q0, q1);
|
||||
UADDLVQ_16(d1, d0);
|
||||
@@ -2709,8 +2773,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VSSHR_8(d1, q1, 7); // d1 = byte slection mask
|
||||
VLDR64_U12(d0, xRDI, 0);
|
||||
VBIC(d0, d0, d1); // d0 = clear masked byte
|
||||
|
||||
@@ -428,6 +428,24 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
case 0x73:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
case 0x76:
|
||||
case 0x77:
|
||||
case 0x78:
|
||||
case 0x79:
|
||||
case 0x7A:
|
||||
case 0x7B:
|
||||
case 0x7C:
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
// just use regular conditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
case 0x80:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -969,6 +987,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xEB:
|
||||
// just use regular inconditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
@@ -757,7 +758,34 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
SMWRITELOCK(lock);
|
||||
break;
|
||||
|
||||
case 0xA4:
|
||||
SMREAD();
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRB_S9_postindex(x1, xRSI, 1);
|
||||
STRB_S9_postindex(x1, xRDI, 1);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRB_S9_postindex(x1, xRSI, -1);
|
||||
STRB_S9_postindex(x1, xRDI, -1);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
GETDIR(x3, 1);
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
STRB_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xA5:
|
||||
SMREAD();
|
||||
if(rep) {
|
||||
@@ -951,7 +979,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (u8) {
|
||||
SETFLAGS(X_CF | X_OF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
@@ -964,7 +992,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 15) {
|
||||
SETFLAGS(X_CF | X_OF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
@@ -1244,6 +1272,54 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD9:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, 1);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDD:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("FRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_frstor16, -1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_fsave16, -1);
|
||||
CALL(reset_fpu, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
@@ -135,9 +135,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VLD1_64(v0, 1, ed);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
ADDx_U12(x1, ed, 8);
|
||||
VLD1_64(v0, 1, x1);
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
@@ -243,7 +243,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
@@ -283,7 +283,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
if (i) {
|
||||
@@ -322,7 +322,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
MOVIQ_8(d0, 0b10001111);
|
||||
VANDQ(d0, d0, q1); // mask the index
|
||||
VTBLQ1_8(q0, q0, d0);
|
||||
@@ -346,7 +346,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_16(v0, q0, q1);
|
||||
VUZP2Q_16(q0, q0, q1);
|
||||
SQADDQ_16(q0, q0, v0);
|
||||
@@ -356,26 +356,31 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(q0==q1)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
d0 = q0;
|
||||
UXTL_8(v0, q0); // this is unsigned, so 0 extended
|
||||
SXTL_8(v1, q1); // this is signed
|
||||
VMULQ_16(v0, v0, v1);
|
||||
SADDLPQ_16(v1, v0);
|
||||
UXTL2_8(v0, q0); // this is unsigned
|
||||
SQXTN_16(q0, v1); // SQXTN reset the vector so need to grab the high part first
|
||||
SQXTN_16(d0, v1); // SQXTN reset the vector so need to grab the high part first
|
||||
SXTL2_8(v1, q1); // this is signed
|
||||
VMULQ_16(v0, v0, v1);
|
||||
SADDLPQ_16(v0, v0);
|
||||
SQXTN2_16(q0, v0);
|
||||
SQXTN2_16(d0, v0);
|
||||
if(q0!=d0)
|
||||
VMOVQ(q0, d0);
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("PHSUBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP2Q_16(v0, q0, q1);
|
||||
VUZP1Q_16(q0, q0, q1);
|
||||
VSUBQ_16(q0, q0, v0);
|
||||
@@ -385,7 +390,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP2Q_32(v0, q0, q1);
|
||||
VUZP1Q_32(q0, q0, q1);
|
||||
VSUBQ_32(q0, q0, v0);
|
||||
@@ -395,7 +400,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP2Q_16(v0, q0, q1);
|
||||
VUZP1Q_16(q0, q0, q1);
|
||||
SQSUBQ_16(q0, q0, v0);
|
||||
@@ -405,8 +410,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
NEGQ_8(v0, q0); // get NEG
|
||||
CMLTQ_0_8(v1, q1); // calculate mask
|
||||
VBICQ(q0, q0, v1); // apply not mask on dest
|
||||
@@ -420,8 +425,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
NEGQ_16(v0, q0); // get NEG
|
||||
CMLTQ_0_16(v1, q1); // calculate mask
|
||||
VBICQ(q0, q0, v1); // apply not mask on dest
|
||||
@@ -435,8 +440,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
NEGQ_32(v0, q0); // get NEG
|
||||
CMLTQ_0_32(v1, q1); // calculate mask
|
||||
VBICQ(q0, q0, v1); // apply not mask on dest
|
||||
@@ -459,7 +464,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(q0!=q1) {
|
||||
VSSHRQ_8(v1, v0, 7); // bit[7]-> bit[7..0]
|
||||
VBICQ(q0, q0, v1);
|
||||
@@ -474,7 +479,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(q0!=q1) {
|
||||
VSSHRQ_32(v1, v0, 31); // bit[31]-> bit[31..0]
|
||||
VBICQ(q0, q0, v1);
|
||||
@@ -488,7 +493,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(q0!=q1) {
|
||||
VSSHRQ_64(v1, v0, 63); // bit[63]-> bit[63..0]
|
||||
VBICQ(q0, q0, v1);
|
||||
@@ -503,7 +508,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGX(q0, 0);
|
||||
GETEX(q1, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
IFX(X_ZF) {
|
||||
VANDQ(v1, q1, q0);
|
||||
CMEQQ_0_64(v1, v1);
|
||||
@@ -606,7 +611,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v0 = q0;
|
||||
} else {
|
||||
if(MODREG)
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
v0 = q1;
|
||||
VUZP1Q_32(v0, q1, q1);
|
||||
@@ -632,8 +637,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(v0, v0, v0);
|
||||
SMAXQ_32(v1, v0, q0); // values < 0 => 0
|
||||
UQXTN_16(q0, v1);
|
||||
@@ -787,19 +792,23 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(arm64_aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn); // ARM64 internal operation differs a bit from x86_64
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
VEORQ(v0, q0, q1);
|
||||
AESE(v0, q1);
|
||||
AESMC(v0, v0);
|
||||
VEORQ(q0, v0, q1);
|
||||
} else {
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
if(MODREG && (gd==(nextop&7)+(rex.b<<3))) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, q1);
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aese, -1);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
break;
|
||||
case 0xDD:
|
||||
@@ -808,18 +817,22 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(arm64_aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn); // ARM64 internal operation differs a bit from x86_64
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
VEORQ(v0, q0, q1);
|
||||
AESE(v0, q1);
|
||||
VEORQ(q0, v0, q1);
|
||||
} else {
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
if(MODREG && (gd==(nextop&7)+(rex.b<<3))) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, q1);
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aeselast, -1);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
break;
|
||||
case 0xDE:
|
||||
@@ -828,19 +841,23 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(arm64_aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn); // ARM64 internal operation differs a bit from x86_64
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
VEORQ(v0, q0, q1);
|
||||
AESD(v0, q1);
|
||||
AESIMC(v0, v0);
|
||||
VEORQ(q0, v0, q1);
|
||||
} else {
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
if(MODREG && (gd==(nextop&7)+(rex.b<<3))) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, q1);
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesd, -1);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
break;
|
||||
case 0xDF:
|
||||
@@ -849,18 +866,22 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(arm64_aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn); // ARM64 internal operation differs a bit from x86_64
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
VEORQ(v0, q0, q1);
|
||||
AESD(v0, q1);
|
||||
VEORQ(q0, v0, q1);
|
||||
} else {
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
if(MODREG && (gd==(nextop&7)+(rex.b<<3))) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, q1);
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesdlast, -1);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
@@ -894,6 +915,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STH(x1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF6:
|
||||
INST_NAME("ADCX Gd, Ed");
|
||||
nextop = F8;
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
MRS_nzvc(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(x3); // load CC into ARM CF
|
||||
IFX(X_CF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
CSETw(x3, cCS);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
} else {
|
||||
ADCxw_REG(gd, gd, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -908,7 +949,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q1, 0, 1);
|
||||
GETGX_empty(q0);
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTISQ(q0, q1);
|
||||
@@ -923,7 +964,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q1, 0, 1);
|
||||
GETGX_empty(q0);
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(q0, q1);
|
||||
@@ -938,7 +979,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEXSS(q1, 0, 1);
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FRINTXS(v1, q1);
|
||||
@@ -954,7 +995,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEXSD(q1, 0, 1);
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FRINTXD(v1, q1);
|
||||
@@ -1038,7 +1079,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(u8>31) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else if(u8>15) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(d0, d0, d0);
|
||||
VEXTQ_8(q0, q0, d0, u8-16);
|
||||
} else {
|
||||
@@ -1127,7 +1168,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("INSERTPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, q0);
|
||||
if (MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
@@ -1166,7 +1207,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMULQS(v0, q0, q1);
|
||||
// mask some, duplicate all, mask some
|
||||
for(int i=0; i<4; ++i)
|
||||
@@ -1252,7 +1293,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
switch(u8&1) {
|
||||
case 0b00:
|
||||
VDUPQB(q0, x1); // load the low 8bits of the mask
|
||||
@@ -1293,13 +1334,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 0);
|
||||
GETEX(v1, 0, 1);
|
||||
u8 = F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&1) {
|
||||
//16bits
|
||||
VCMEQQ_16(q0, v0, v1); // equal => mask regs
|
||||
XTN_8(q0, q0); // 8 bits mask, in lower 64bits
|
||||
// transform that a mask in x1
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VSHL_8(q0, q0, 7); // keep only bit 0x80
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
VLDR64_U12(q1, x1, 0); // load shift
|
||||
@@ -1310,8 +1351,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
//8 bits
|
||||
VCMEQQ_8(q0, v0, v1); // equal => mask regs
|
||||
// transform that a mask in x1
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VSHL_8(d0, q0, 7); // keep only bit 0x80
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
VLDR64_U12(q1, x1, 0); // load shift
|
||||
@@ -1369,28 +1410,29 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF|X_SF) {
|
||||
MOV32w(x4, 8);
|
||||
MOV32w(x4, (u8&1)?8:16);
|
||||
IFX(X_ZF) {
|
||||
CMPSw_REG(x3, x4);
|
||||
CSETw(x4, cLT);
|
||||
BFIw(xFlags, x4, F_ZF, 1);
|
||||
CSETw(x5, cLT);
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
}
|
||||
IFX(F_SF) {
|
||||
CMPSw_REG(x2, x4);
|
||||
CSETw(x4, cLT);
|
||||
BFIw(xFlags, x4, F_SF, 1);
|
||||
CSETw(x5, cLT);
|
||||
BFIw(xFlags, x5, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
CMPSw_U12(x1, 0);
|
||||
BFCw(wFlags, F_AF, 1);
|
||||
/*CMPSw_U12(x1, 0);
|
||||
CSETw(x4, cEQ);
|
||||
CMPSw_U12(x3, (u8&1)?8:16);
|
||||
CSETw(x5, cEQ);
|
||||
ANDw_REG(x4, x4, x5);
|
||||
BFIw(xFlags, x4, F_AF, 1);
|
||||
BFIw(xFlags, x4, F_AF, 1);*/
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFCw(xFlags, F_PF, 1);
|
||||
@@ -1455,7 +1497,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CALL(sse42_compare_string_implicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
switch(u8&1) {
|
||||
case 0b00:
|
||||
VDUPQB(q0, x1); // load the low 8bits of the mask
|
||||
@@ -1573,11 +1615,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("PMOVMSKD Gd, Ex");
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
VMOVQDto(x1, q0, 1);
|
||||
VMOVQDto(gd, q0, 0);
|
||||
LSRx(x1, x1, 63);
|
||||
LSRx(gd, gd, 63);
|
||||
BFIx(gd, x1, 1, 1);
|
||||
VMOVQDto(x1, q0, 0);
|
||||
VMOVQDto(gd, q0, 1);
|
||||
LSRx(gd, gd, 62);
|
||||
BFXILx(gd, x1, 63, 1);
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTPD Gx, Ex");
|
||||
@@ -1585,8 +1626,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFCMEQQD(v0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQD(q1, q0);
|
||||
@@ -1640,8 +1681,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1660,8 +1701,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1699,11 +1740,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
MOV32w(x4, 0x80000000);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -1724,8 +1763,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1746,7 +1785,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQD(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, v1, q0);
|
||||
@@ -1760,8 +1799,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1782,7 +1821,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQD(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, v1, q0);
|
||||
@@ -1991,7 +2030,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
(8)|(9<<8)|(10<<16)|(11<<24),
|
||||
(12)|(13<<8)|(14<<16)|(15<<24)
|
||||
};
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
tmp64u = swp[(u8>>(0*2))&3] | (swp[(u8>>(1*2))&3]<<32);
|
||||
MOV64x(x2, tmp64u);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
@@ -2134,7 +2173,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(u8>15) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(q1, q1, q1);
|
||||
VEXTQ_8(q0, q0, q1, u8);
|
||||
}
|
||||
@@ -2162,7 +2201,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(u8>15) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else if(u8>0) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(q1, q1, q1);
|
||||
VEXTQ_8(q0, q1, q0, 16-u8);
|
||||
}
|
||||
@@ -2202,8 +2241,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q1, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VTRNQ1_64(v0, q1, q0);
|
||||
@@ -2224,7 +2263,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_64(v0, q0, q1);
|
||||
VUZP2Q_64(q0, q0, q1);
|
||||
VFSUBQD(q0, v0, q0);
|
||||
@@ -2476,7 +2515,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
BFIxw(ed, x4, u8, 1);
|
||||
EWBACK(x1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ew, Ib");
|
||||
@@ -2489,7 +2528,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
BFCxw(ed, u8, 1);
|
||||
EWBACK(x1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ew, Ib");
|
||||
@@ -2503,7 +2542,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
EWBACK(x1);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2620,7 +2659,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 2: VFCMGEQD(v0, v1, v0); break; // Less or equal
|
||||
case 3: VFCMEQQD(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQD(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
}
|
||||
@@ -2631,7 +2670,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 6: VFCMGEQD(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
|
||||
case 7: VFCMEQQD(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQD(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
}
|
||||
@@ -2679,7 +2718,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
} else {
|
||||
if(v0==v1)
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
q0 = v0;
|
||||
VMOVeD(q0, 0, v0, (u8&1));
|
||||
@@ -2708,13 +2747,23 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("ADDSUBPD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFSUBQD(v0, q0, q1);
|
||||
VFADDQD(q0, q0, q1);
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
break;
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 16);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +16 values
|
||||
@@ -2722,23 +2771,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VDUPQ_16(v0, v0, 0); // only the low 8bits will be used anyway
|
||||
USHLQ_16(q0, q0, v0); // SHR x8
|
||||
break;
|
||||
case 0xD0:
|
||||
INST_NAME("ADDSUBPD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VFSUBQD(v0, q0, q1);
|
||||
VFADDQD(q0, q0, q1);
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
break;
|
||||
case 0xD2:
|
||||
INST_NAME("PSRLD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 32);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +32 values
|
||||
@@ -2751,8 +2790,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 64);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +64 values
|
||||
@@ -2791,9 +2830,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xD7:
|
||||
nextop = F8;
|
||||
INST_NAME("PMOVMSKB Gd, Ex");
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
@@ -2867,7 +2906,6 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q0, 0, 0);
|
||||
VBICQ(v0, q0, v0);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("PAVGB Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -2875,14 +2913,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 0);
|
||||
URHADDQ_8(v0, v0, v1);
|
||||
break;
|
||||
|
||||
case 0xE1:
|
||||
INST_NAME("PSRAW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 15);
|
||||
UMIN_32(v0, v0, v1); // limit to -15 .. +15 values
|
||||
@@ -2895,8 +2932,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 31);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +31 values
|
||||
@@ -2916,8 +2953,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VUMULL_16(q0, v0, v1);
|
||||
VUMULL2_16(q1, v0, v1);
|
||||
UQSHRN_16(v0, q0, 16);
|
||||
@@ -2928,8 +2965,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VSMULL_16(q0, v0, v1);
|
||||
VSMULL2_16(q1, v0, v1);
|
||||
SQSHRN_16(v0, q0, 16);
|
||||
@@ -2948,7 +2985,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -3047,8 +3084,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 16);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +16 values
|
||||
@@ -3060,8 +3097,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 32);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +32 values
|
||||
@@ -3073,8 +3110,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, q1);
|
||||
MOVI_32(v1, 64);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +64 values
|
||||
@@ -3086,10 +3123,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(q0, v0, v0); //A3 A2 A1 A0 -> A3 A1 A2 A0
|
||||
if(MODREG) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
q1 = v1;
|
||||
}
|
||||
@@ -3101,8 +3138,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VSMULL_16(q0, v0, v1);
|
||||
VSMULL2_16(q1, v0, v1);
|
||||
VADDPQ_32(v0, q0, q1);
|
||||
@@ -3112,8 +3149,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VEOR(d1, d1, d1); // is it necessary?
|
||||
UABDL_8(d0, q0, q1);
|
||||
UADDLVQ_16(d1, d0);
|
||||
@@ -3127,10 +3164,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VLDR128_U12(v0, xRDI, 0);
|
||||
if(MODREG)
|
||||
v1 = fpu_get_scratch(dyn); // need to preserve the register
|
||||
v1 = fpu_get_scratch(dyn, ninst); // need to preserve the register
|
||||
else
|
||||
v1 = q1;
|
||||
VSSHRQ_8(v1, q1, 7); // get the mask
|
||||
|
||||
@@ -61,7 +61,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
|
||||
@@ -37,6 +37,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int16_t i16;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
@@ -56,9 +57,14 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
GETREX();
|
||||
|
||||
while(opcode==0x67) opcode = F8;
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
while((opcode==0xF2) || (opcode==0xF3) || (opcode>=0x40 && opcode<=0x4F)) {
|
||||
if((opcode==0xF2) || (opcode==0xF3))
|
||||
rep = opcode-0xF1;
|
||||
if(opcode>=0x40 && opcode<=0x4F)
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
@@ -201,7 +207,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
@@ -656,6 +662,111 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETREX();
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOVZw(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
@@ -982,6 +1093,53 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC4:
|
||||
nextop = F8;
|
||||
if(rex.is32bits && !(MODREG)) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
if(rex.is32bits) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
vex_t vex = {0};
|
||||
vex.rex = rex;
|
||||
u8 = nextop;
|
||||
vex.m = u8&0b00011111;
|
||||
vex.rex.b = (u8&0b00100000)?0:1;
|
||||
vex.rex.x = (u8&0b01000000)?0:1;
|
||||
vex.rex.r = (u8&0b10000000)?0:1;
|
||||
u8 = F8;
|
||||
vex.p = u8&0b00000011;
|
||||
vex.l = (u8>>2)&1;
|
||||
vex.v = ((~u8)>>3)&0b1111;
|
||||
vex.rex.w = (u8>>7)&1;
|
||||
addr = dynarec64_67_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
case 0xC5:
|
||||
nextop = F8;
|
||||
if(rex.is32bits && !(MODREG)) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
if(rex.is32bits) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
vex_t vex = {0};
|
||||
vex.rex = rex;
|
||||
u8 = nextop;
|
||||
vex.p = u8&0b00000011;
|
||||
vex.l = (u8>>2)&1;
|
||||
vex.v = ((~u8)>>3)&0b1111;
|
||||
vex.rex.r = (u8&0b10000000)?0:1;
|
||||
vex.rex.b = 0;
|
||||
vex.rex.x = 0;
|
||||
vex.rex.w = 0;
|
||||
vex.m = VEX_M_0F;
|
||||
addr = dynarec64_67_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Eb, Ib");
|
||||
nextop=F8;
|
||||
@@ -1233,6 +1391,20 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETED32(0);
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETED32(0);
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF((box64_dynarec_safeflags>1) ||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
switch(p) {
|
||||
case VEX_P_NONE: return "0";
|
||||
case VEX_P_66: return "66";
|
||||
case VEX_P_F2: return "F2";
|
||||
case VEX_P_F3: return "F3";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
static const char* avx_map_string(uint16_t m)
|
||||
{
|
||||
switch(m) {
|
||||
case VEX_M_NONE: return "0";
|
||||
case VEX_M_0F: return "0F";
|
||||
case VEX_M_0F38: return "0F38";
|
||||
case VEX_M_0F3A: return "0F3A";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2)) {
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
GETVD;
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
UMULH(x3, xRDX, ed);
|
||||
MULx(vd, xRDX, ed);
|
||||
MOVx_REG(gd, x3);
|
||||
} else {
|
||||
// 32bits mul
|
||||
UMULL(x3, xRDX, ed);
|
||||
MOVw_REG(vd, x3);
|
||||
LSRx(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
}
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing)) {
|
||||
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
switch(p) {
|
||||
case VEX_P_NONE: return "0";
|
||||
case VEX_P_66: return "66";
|
||||
case VEX_P_F2: return "F2";
|
||||
case VEX_P_F3: return "F3";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
static const char* avx_map_string(uint16_t m)
|
||||
{
|
||||
switch(m) {
|
||||
case VEX_M_NONE: return "0";
|
||||
case VEX_M_0F: return "0F";
|
||||
case VEX_M_0F38: return "0F38";
|
||||
case VEX_M_0F3A: return "0F3A";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = PK(0);
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_F3))
|
||||
addr = dynarec64_AVX_F3_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing)) {
|
||||
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,712 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, ed, 0, gd, -1, -1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, ed, -1, -1);
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
if(vex.l) {
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVUPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, ed, gd, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
GETVX(v2, 0);
|
||||
if(MODREG) {
|
||||
INST_NAME("VMOVHLPS Gx, Vx, Ex");
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
if((v0!=v2) && (v0!=v1))
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeD(v0, 0, v1, 1);
|
||||
if((v0!=v2) && (v0==v1))
|
||||
VMOVeD(v0, 1, v2, 1);
|
||||
} else {
|
||||
INST_NAME("VMOVLPS Gx, Vx, Ex");
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(v0!=v2)
|
||||
VMOVQ(v0, v2);
|
||||
VLD1_64(v0, 0, ed);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVLPS Ex, Vx, Gx");
|
||||
GETGX(v0, 0);
|
||||
GETVX(v2, 0);
|
||||
if(v1!=v2)
|
||||
VMOVQ(v0, v2);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
if(v0!=v1) VMOVeD(v1, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("VUNPCKLPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VZIP1Q_32(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VZIP1Q_32(v0, v2, v1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("VUNPCKHPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VZIP2Q_32(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VZIP2Q_32(v0, v2, v1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
INST_NAME("VMOVLHPS Gx, Vx, Ex");
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
if(v0!=v2 && v0!=v1) VMOVQ(v0, v2);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
if(v0!=v2 && v0==v1) VMOVeD(v0, 0, v2, 0);
|
||||
} else {
|
||||
INST_NAME("VMOVHPS Gx, Vx, Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VMOVHPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
INST_NAME("VMOVAPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("VMOVAPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("VMOVNTPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("VCOMISS Gx, Ex");} else {INST_NAME("VUCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
INST_NAME("VMOVMSPKPS Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
MOV32w(gd, 0);
|
||||
if(MODREG) {
|
||||
// EX is an xmm reg
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v0, 0, 0); } else { GETEY(v0); }
|
||||
SQXTN_16(q0, v0); // reduces the 4 32bits to 4 16bits
|
||||
VMOVQDto(x1, q0, 0);
|
||||
LSRx(x1, x1, 15);
|
||||
BFIx(gd, x1, 0+(l*4), 1);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 1+(l*4), 1);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 2+(l*4), 1);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 3+(l*4), 1);
|
||||
}
|
||||
} else {
|
||||
// EX is memory
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0xfff<<3)-24, 7, rex, NULL, 0, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
LDRx_U12(x1, ed, fixedaddress+16*l);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 0+(l*4), 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 1+(l*4), 1);
|
||||
LDRx_U12(x1, ed, fixedaddress+8+16*l);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 2+(l*4), 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 3+(l*4), 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(q0, q1, 0); } else { GETGY_empty_EY(q0, q1); }
|
||||
VFSQRTQS(q0, q1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("VRSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMOVSQ_8(v0, 0b01110000); //1.0f
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(q0, q1, 0); } else { GETGY_empty_EY(q0, q1); }
|
||||
#if 0
|
||||
// the aproximation doesn't not work on Death Stranding. code around 0x1419c9100 fail...
|
||||
if(!l) {
|
||||
if(q1==q0)
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
v1 = q1;
|
||||
}
|
||||
// more precise
|
||||
VFRSQRTEQS(v0, q1);
|
||||
VFMULQS(v1, v0, q1);
|
||||
VFRSQRTSQS(v1, v1, v0);
|
||||
VFMULQS(q0, v1, v0);
|
||||
#else
|
||||
VFSQRTQS(q0, q1);
|
||||
VFDIVQS(q0, v0, q0);
|
||||
#endif
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("VRCPPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMOVSQ_8(q0, 0b01110000); //1.0f
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
#if 0
|
||||
if(v0==v1)
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
#endif
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
}
|
||||
#if 0
|
||||
if(v0!=v1) q1 = v0;
|
||||
VFRECPEQS(q0, v1);
|
||||
VFRECPSQS(q1, q0, v1);
|
||||
VFMULQS(v0, q0, q1);
|
||||
#else
|
||||
VFDIVQS(v0, q0, v1);
|
||||
#endif
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("VANDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VANDQ(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VANDQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VBICQ(v0, v1, v2);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VBICQ(v0, v1, v2);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VORRQ(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VORRQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VEORQ(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VEORQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFADDQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VFADDQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFMULQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VFMULQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(q0, -1, -1, -1);
|
||||
FCVTL2(q0, v1);
|
||||
} else YMM0(gd)
|
||||
FCVTL(v0, v1);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTDQ2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
SCVTQFS(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
SCVTQFS(v0, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFSUBQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VFSUBQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
VFMINQS(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan && (v2!=v1)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source is NaN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFDIVQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VFDIVQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
VFMAXQS(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan && (v2!=v1)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source is NaN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x77:
|
||||
if(!vex.l) {
|
||||
INST_NAME("VZEROUPPER");
|
||||
if(vex.v!=0) {
|
||||
UDF(0);
|
||||
} else {
|
||||
for(int i=0; i<(rex.is32bits?8:16); ++i) {
|
||||
YMM0(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
INST_NAME("VZEROALL");
|
||||
if(vex.v!=0) {
|
||||
UDF(0);
|
||||
} else {
|
||||
for(int i=0; i<(rex.is32bits?8:16); ++i) {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, i);
|
||||
VEORQ(v0, v0, v0);
|
||||
YMM0(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("VLDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if(box64_sse_flushto0) {
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
LSRw_IMM(x3, ed, 15); // get FZ bit
|
||||
BFIw(x1, x3, 24, 1); // inject FZ bit
|
||||
EORw_REG_LSR(x3, x3, ed, 1); // FZ xor DAZ
|
||||
BFIw(x1, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("VSTMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STW(x4, ed, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12) || ((u8&15)==13) || ((u8&15)==14)) {
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(((u8&15)==7)?v0:q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
switch(u8&0xf) {
|
||||
// the inversion of the params in the comparison is there to handle NaN the same way SSE does
|
||||
case 0x00: VFCMEQQS(v0, v2, v1); break; // Equal, not unordered
|
||||
case 0x01: VFCMGTQS(v0, v1, v2); break; // Less than
|
||||
case 0x02: VFCMGEQS(v0, v1, v2); break; // Less or equal
|
||||
case 0x03: VMVNQ(v0, q0); break; // unordered
|
||||
case 0x04: VFCMEQQS(v0, v2, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 0x05: VFCMGTQS(v0, v1, v2); VMVNQ(v0, v0); break; // Greater or equal or unordered
|
||||
case 0x06: VFCMGEQS(v0, v1, v2); VMVNQ(v0, v0); break; // Greater or unordered
|
||||
case 0x07: break; // ordered
|
||||
case 0x08: VFCMEQQS(v0, v2, v1); VORNQ(v0, v0, q0); break; // Equal, or unordered
|
||||
case 0x09: VFCMGTQS(v0, v1, v2); VORNQ(v0, v0, q0); break; // Less than or unordered
|
||||
case 0x0a: VFCMGEQS(v0, v1, v2); VORNQ(v0, v0, q0); break; // Less or equal or unordered
|
||||
case 0x0b: VEORQ(v0, v0, v0); break; // false
|
||||
case 0x0c: VFCMEQQS(v0, v2, v1); VBICQ(v0, q0, v0); break;
|
||||
case 0x0d: VFCMGEQS(v0, v2, v1); break;
|
||||
case 0x0e: VFCMGTQS(v0, v2, v1); break;
|
||||
case 0x0f: MOVIQ_64(v0, 0xff); break; //true
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("VSHUFPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETVX(v2, 0);
|
||||
if(!MODREG) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = -1; // to avoid a warning
|
||||
} else
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = F8;
|
||||
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v2, u8&3);
|
||||
} else if(v2==v1 && (u8==0xe0)) { // easy special case
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v2==v1 && (u8==0xe5)) { // easy special case
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(MODREG && u8==0x88) {
|
||||
VUZP1Q_32(v0, v2, v1);
|
||||
} else if(MODREG && u8==0xdd) {
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
} else {
|
||||
if((v0==v1) || (v0==v2)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst); s0 = 0;
|
||||
} else {
|
||||
d0 = v0; s0 = 1;
|
||||
}
|
||||
// first two elements from Vx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v2, (u8>>(i*2))&3);
|
||||
}
|
||||
// second two from Ex
|
||||
if(MODREG) {
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, ((u8>>(i*2))&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
}
|
||||
}
|
||||
if(v0!=d0) VMOVQ(v0, d0);
|
||||
}
|
||||
if(vex.l) {
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1);
|
||||
GETGY_empty_VY(v0, v2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v2, u8&3);
|
||||
} else if(v2==v1 && (u8==0xe0)) {
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v2==v1 && (u8==0xe5)) {
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(MODREG && u8==0x88) {
|
||||
VUZP1Q_32(v0, v2, v1);
|
||||
} else if(MODREG && u8==0xdd) {
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
} else {
|
||||
if(s0) d0 = v0;
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v2, (u8>>(i*2))&3);
|
||||
}
|
||||
if(MODREG) {
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, 16+((u8>>(i*2))&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
}
|
||||
}
|
||||
VMOVQ(v0, d0);
|
||||
}
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF2:
|
||||
INST_NAME("ANDN Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
BICxw(gd, ed, vd);
|
||||
break;
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("BLSR Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
SUBxw_U12(x3, ed, 1);
|
||||
IFX(X_ZF)
|
||||
ANDSxw_REG(vd, ed, x3);
|
||||
else
|
||||
ANDxw_REG(vd, ed, x3);
|
||||
IFX(X_ZF) {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
if(box64_dynarec_test) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("BZHI Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
UXTBw(x1, vd);
|
||||
CMPSw_U12(x1, rex.w?64:32);
|
||||
CSETxw(x2, cPL);
|
||||
IFX(F_CF) {
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
MVNxw_REG(x2, x2); //prepare mask
|
||||
B_MARK(cPL);
|
||||
LSLxw_REG(x2, x2, x1);
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
BICSxw(gd, ed, x2);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
} else
|
||||
BICxw(gd, ed, x2);
|
||||
IFX(X_SF) {
|
||||
LSRxw(x3, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,778 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
if(opcode) {INST_NAME("VPERMPD Gx, Ex, Imm8");} else {INST_NAME("VPERMQ Gx, Ex, Imm8");}
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, q0, 1);
|
||||
u8 = F8;
|
||||
if(v0==q0) d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(v0==q0 || !MODREG) d1 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = d1;
|
||||
GETGY_empty_EY(v1, q1);
|
||||
if(v0==q0) { VMOVQ(d0, q0); VMOVQ(d1, q1); } else {d1 = q1; d0 = q0;}
|
||||
VMOVeD(v0, 0, ((u8>>1)&1)?d1:d0, (u8>>0)&1);
|
||||
VMOVeD(v0, 1, ((u8>>3)&1)?d1:d0, (u8>>2)&1);
|
||||
VMOVeD(v1, 0, ((u8>>5)&1)?d1:d0, (u8>>4)&1);
|
||||
VMOVeD(v1, 1, ((u8>>7)&1)?d1:d0, (u8>>6)&1);
|
||||
break;
|
||||
case 0x02:
|
||||
INST_NAME("VPBLENDD Gx, Vx, Ex, u8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8;} else { GETGY_empty_VYEY(v0, v2, v1); u8 >>=4;}
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q0, q0); // expand 16bits to 32bits...
|
||||
if(v0==v1) {
|
||||
VBIFQ(v0, v2, q0);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
INST_NAME("VPERMILPS Gx, Ex, Imm8");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if(v0==v1) {q1 = fpu_get_scratch(dyn, ninst); VMOVQ(q1, v1);}
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
if(v0==v1) {VMOVQ(q1, v1);}
|
||||
}
|
||||
if(u8==0x00 || u8==0x55 || u8==0xAA || u8==0xFF)
|
||||
VDUPQ_32(v0, (v0==v1)?q1:v1, u8&3);
|
||||
else if(u8==0x50)
|
||||
VZIP1Q_32(v0, v1, v1);
|
||||
else if(u8==0xFA)
|
||||
VZIP2Q_32(v0, v1, v1);
|
||||
else if(u8==0xA0)
|
||||
VTRNQ1_32(v0, v1, v1);
|
||||
else if(u8==0xF5)
|
||||
VTRNQ2_32(v0, v1, v1);
|
||||
else for(int i=0; i<4; ++i)
|
||||
VMOVeS(v0, i, (v0==v1)?q1:v1, (u8>>(i*2))&3);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("VPERMILD Gx, Ex, Imm8");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if(v0==v1) {q1 = fpu_get_scratch(dyn, ninst); VMOVQ(q1, v1);}
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
if(v0==v1) {VMOVQ(q1, v1);}
|
||||
}
|
||||
if(((u8>>(l*2))&1)==((u8>>(1+l*2))&1))
|
||||
VDUPQ_64(v0, (v0==v1)?q1:v1, ((u8>>(l*2))&1));
|
||||
else for(int i=0; i<2; ++i)
|
||||
VMOVeD(v0, i, (v0==v1)?q1:v1, (u8>>(i+l*2))&1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x06:
|
||||
case 0x46:
|
||||
if(opcode==0x06) { INST_NAME("VPERM2F128 Gx, Vx, Ex, Imm8"); } else { INST_NAME("VPERM2I128 Gx, Vx, Ex, Imm8"); }
|
||||
nextop = F8;
|
||||
if(!vex.l) UDF(0);
|
||||
if(MODREG) {
|
||||
s0 = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, s0, 0);
|
||||
} 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);
|
||||
}
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
if((v0==v2) && ((u8&0xf0)==0)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v2);
|
||||
v2 = q0;
|
||||
}
|
||||
if((v0==v1) && ((u8&0xf0)==0x20)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q1, v1);
|
||||
v1 = q1;
|
||||
}
|
||||
switch(u8&0x0f) {
|
||||
case 0: if(v0!=v2) VMOVQ(v0, v2); break;
|
||||
case 1: d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); VMOVQ(v0, d2); break;
|
||||
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
|
||||
case 3: if(MODREG) { d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
|
||||
default: VEORQ(v0, v0, v0);
|
||||
}
|
||||
if((u8&0xf0)==0x10) { if((u8&0x0f)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
|
||||
if(MODREG && ((u8&0xf0)==0x30)) { if((u8&0x0f)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, s0, -1);
|
||||
switch((u8>>4)&0x0f) {
|
||||
case 0: VMOVQ(v0, v2); break;
|
||||
case 1: if(v0!=d2) VMOVQ(v0, d2); break;
|
||||
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
|
||||
case 3: if(MODREG) { if(v0!=d1) VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
|
||||
default: VEORQ(v0, v0, v0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
INST_NAME("VROUNDPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 1); u8 = F8; } else { GETGY_empty_EY(v0, v1); }
|
||||
if(u8&4) {
|
||||
if(!l) wb1 = sse_setround(dyn, ninst, x1, x2, x4);
|
||||
VFRINTISQ(v0, v1);
|
||||
if(l || !vex.l) x87_restoreround(dyn, ninst, wb1);
|
||||
} else {
|
||||
VFRINTRSQ(v0, v1, round_round[u8&3]);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("VROUNDPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 1); u8 = F8; } else { GETGY_empty_EY(v0, v1); }
|
||||
if(u8&4) {
|
||||
if(!l) wb1 = sse_setround(dyn, ninst, x1, x2, x4);
|
||||
VFRINTIDQ(v0, v1);
|
||||
if(l || !vex.l) x87_restoreround(dyn, ninst, wb1);
|
||||
} else {
|
||||
VFRINTRDQ(v0, v1, round_round[u8&3]);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("VROUNDSS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSS(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FRINTXS(d1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
FRINTRRS(d1, v1, round_round[u8&3]);
|
||||
}
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("VROUNDSD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FRINTXD(d1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
FRINTRRD(d1, v1, round_round[u8&3]);
|
||||
}
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x0C:
|
||||
INST_NAME("VBLENDPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(q0, q2, q1, 1);
|
||||
u8 = F8;
|
||||
if((u8&0xf)==0xf) {
|
||||
if(q0!=q1) VMOVQ(q0, q1);
|
||||
} else if(q0==q1) {
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i)) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
} else if(q0!=q2)
|
||||
VMOVeS(q0, i, q2, i);
|
||||
} else {
|
||||
if(q0!=q2)
|
||||
VMOVQ(q0, q2);
|
||||
if((u8&15)==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
} else if((u8&15)==0b1100) {
|
||||
VMOVeD(q0, 1, q1, 1);
|
||||
} else for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i)) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
}
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(q0, q2, q1);
|
||||
if((u8&0xf0)==0xf0) {
|
||||
if(q0!=q1) VMOVQ(q0, q1);
|
||||
} else if(q0==q1) {
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<(i+4))) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
} else if(q0!=q2)
|
||||
VMOVeS(q0, i, q2, i);
|
||||
} else {
|
||||
if(q0!=q2)
|
||||
VMOVQ(q0, q2);
|
||||
if((u8>>4)==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
} else if((u8>>4)==0b1100) {
|
||||
VMOVeD(q0, 1, q1, 1);
|
||||
} else for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<(i+4))) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
}
|
||||
}
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("VPBLENDPD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 1); u8 = F8; } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
switch(u8>>(l*2)&3) {
|
||||
case 0b00: if(q0!=q2) VMOVQ(q0, q2); break; // VxVx
|
||||
case 0b01: if(q0!=q1) VMOVeD(q0, 0, q1, 0); if(q0!=q2) VMOVeD(q0, 1, q2, 1); break; // Ex[0]Vx[1]
|
||||
case 0b10: if(q0!=q2) VMOVeD(q0, 0, q2, 0); if(q0!=q1) VMOVeD(q0, 1, q1, 1); break; // Vx[0]Ex[1]
|
||||
case 0b11: if(q0!=q1) VMOVQ(q0, q1); break; // ExEx
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0E:
|
||||
INST_NAME("VPBLENDW Gx, Vx, Ex, u8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8;} else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!l) {
|
||||
MOVI_64(q0, u8);
|
||||
SXTL_8(q0, q0); // expand 8bits to 16bits...
|
||||
}
|
||||
if(v0==v1) {
|
||||
VBIFQ(v0, v2, q0);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0F:
|
||||
INST_NAME("VPALIGNR Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
u8 = F8;
|
||||
} else {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(u8>31) {
|
||||
VEORQ(v0, v0, v0);
|
||||
} else if(u8>15) {
|
||||
if(!l) VEORQ(d0, d0, d0);
|
||||
VEXTQ_8(v0, v2, d0, u8-16);
|
||||
} else {
|
||||
VEXTQ_8(v0, v1, v2, u8);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
INST_NAME("VPEXTRB Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVBto(ed, v0, u8&0x0f);
|
||||
if(!MODREG) {
|
||||
STB(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("VPEXTRW Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVHto(ed, v0, u8&7);
|
||||
if(!MODREG) {
|
||||
STH(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
INST_NAME("VPEXTRD/Q Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
if(rex.w) {
|
||||
VMOVQDto(ed, v0, u8&1);
|
||||
} else {
|
||||
VMOVSto(ed, v0, u8&3);
|
||||
}
|
||||
if(!MODREG) {
|
||||
STxw(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VEXTRACTPS Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVSto(ed, v0, u8&3);
|
||||
if(!MODREG) {
|
||||
STW(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
case 0x38:
|
||||
if(opcode==0x18) {INST_NAME("VINSERTF128 Gx, Vx, Ex, imm8");} else {INST_NAME("VINSERTI128 Gx, Vx, Ex, imm8");}
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
|
||||
v1 = -1; // to avoid a warning
|
||||
}
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
if(v0==v2 && u8==1) {
|
||||
GETGY_empty(q0, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
q2 = q0;
|
||||
} else {
|
||||
GETGY_empty_VY(q0, q2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
}
|
||||
if(MODREG)
|
||||
VMOVQ((u8&1)?q0:v0, v1);
|
||||
else
|
||||
VLD128((u8&1)?q0:v0, ed, fixedaddress);
|
||||
if(v0!=v2)
|
||||
VMOVQ((u8&1)?v0:q0, (u8&1)?v2:q2);
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x39:
|
||||
if(opcode==0x19) {INST_NAME("VEXTRACTF128 Ex, Gx, imm8");} else {INST_NAME("VEXTRACTI128 Ex, Gx, imm8");}
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
GETGX(v0, 0);
|
||||
if(u8&1) {GETGY(v0, ((nextop&7)+(rex.b<<3)==gd && MODREG)?1:0, -1, -1, -1);}
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
if((nextop&7)+(rex.b<<3)==gd && (u8&1))
|
||||
VEORQ(v0, v0, v0); // special case like vextractf128 xmm3, ymm3, 0x01
|
||||
else
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
F8; // read u8, but it's been already handled
|
||||
break;
|
||||
|
||||
case 0x1D:
|
||||
INST_NAME("VCVTPS2PH Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<(3+vex.l), vex.l?15:7, rex, NULL, 0, 1);
|
||||
}
|
||||
if(vex.l && v0==v1) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v0);
|
||||
v0 = q0;
|
||||
}
|
||||
u8 = F8;
|
||||
if(u8&4) {
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
} 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);
|
||||
BFIx(x1, x2, 22, 2); // inject new round
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
s0 = x6;
|
||||
}
|
||||
FCVTN16(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1,-1);
|
||||
FCVTN162(v1, v0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, s0);
|
||||
if(MODREG) {
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
if(vex.l) {
|
||||
VST128(v1, ed, fixedaddress);
|
||||
} else {
|
||||
VST64(v1, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v2);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVQBfrom(v0, u8&0xf, ed);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("VINSERTPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
u8 = F8;
|
||||
if(v0==v1) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, v1);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, (u8>>4)&3, d0, (u8>>6)&3);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, (u8>>4)&3, v1, (u8>>6)&3);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
LDW(x2, wback, fixedaddress);
|
||||
VMOVQSfrom(v0, (u8>>4)&3, x2);
|
||||
}
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
if (zmask & (1<<i)) {
|
||||
VMOVQSfrom(v0, i, wZR);
|
||||
}
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v2);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
if(rex.w)
|
||||
VMOVQDfrom(v0, u8&1, ed);
|
||||
else
|
||||
VMOVQSfrom(v0, u8&3, ed);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
INST_NAME("VDPPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// first mask
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q0, q0); // expand 16bits to 32bits...
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// second mask
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if((u8>>4)&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q1, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q1, q1); // expand 16bits to 32bits...
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VFMULQS(v0, v2, v1);
|
||||
VANDQ(v0, v0, q1); // second mask
|
||||
VFADDPQS(v0, v0, v0);
|
||||
FADDPS(v0, v0);
|
||||
VDUPQ_32(v0, v0, 0);
|
||||
VANDQ(v0, v0, q0); // first mask
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_pmull) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
u8 = F8;
|
||||
} else {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
switch (u8&0b00010001) {
|
||||
case 0b00000000:
|
||||
PMULL_128(v0, v2, v1);
|
||||
break;
|
||||
case 0b00010001:
|
||||
PMULL2_128(v0, v2, v1);
|
||||
break;
|
||||
case 0b00000001:
|
||||
VEXTQ_8(d0, v2, v2, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(v0, d0, v1);
|
||||
break;
|
||||
case 0b00010000:
|
||||
VEXTQ_8(d0, v2, v2, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(v0, d0, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_reflect_reg(dyn, ninst, vex.v);
|
||||
}
|
||||
MOV32w(x1, gd); // gx
|
||||
MOV32w(x2, vex.v); // vx
|
||||
if(MODREG) {
|
||||
if(!l) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
}
|
||||
MOV32w(x3, ed);
|
||||
} else {
|
||||
if(!l) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
} else {
|
||||
ADDx_U12(x3, ed, 16);
|
||||
}
|
||||
}
|
||||
if(!l) u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL_(l?native_pclmul_y:native_pclmul_x, -1, x3);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
//case 0x46: // see 0x06
|
||||
|
||||
case 0x4A:
|
||||
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_32(q0, q1, 31); // create mask
|
||||
if(v0==v1)
|
||||
VBIFQ(v0, v2, q0);
|
||||
else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x4B:
|
||||
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_64(q0, q1, 63); // create mask
|
||||
if(v0==v1)
|
||||
VBIFQ(v0, v2, q0);
|
||||
else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x4C:
|
||||
INST_NAME("VBLENDPVB Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_8(q0, q1, 7); // create mask
|
||||
if(v0==v1)
|
||||
VBIFQ(v0, v2, q0);
|
||||
else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,484 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u, u64;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVSD Gx, [Vx,] Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
if(v0!=v1) VMOVeD(v0, 0, v1, 0);
|
||||
if(v0!=v2) VMOVeD(v0, 1, v2, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVSD Ex, Vx, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
GETVXEX(v2, 0, v1, 1, 0);
|
||||
if(v0!=v1) VMOVeD(v1, 0, v0, 0);
|
||||
if(v1!=v2) VMOVeD(v1, 1, v2, 1);
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("VMOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLDQ1R_64(v0, ed);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
ADDx_U12(x3, ed, 16);
|
||||
VLDQ1R_64(v0, ed);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("VCVTSI2SD Gx, Vx, Ed");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FRINTID(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FCMEQD(q0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSQRTD(d1, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FCMEQD(q1, d1, d1); // 0 => out is NAN
|
||||
VBIC(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("VADDSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FADDD(d1, v2, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FMULD(d1, v2, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSD2SS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCVT_S_D(d1, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FSUBD(d1, v2, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
// VMINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPD(v2, v1);
|
||||
FCSELD(d1, v1, v2, cCS);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q0, v2, v1); // propagate NAN
|
||||
FCMEQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FDIVD(d1, v2, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
FCMEQD(q1, d1, d1); // 0 => out is NAN
|
||||
VBIC(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCSELD(d1, v1, v2, cCS);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
if(v0==v1) {
|
||||
VMOVQ(d0, v1);
|
||||
}
|
||||
VDUP_16(v0, v1, u8&3);
|
||||
if(v0==v1)
|
||||
v1 = d0;
|
||||
} else {
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
if(!l) {
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
}
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
}
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("VHADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VFADDPQS(v0, v2, v1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
FCMPD(v2, v1);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
switch(u8&7) {
|
||||
case 0: CSETMx(x2, cEQ); break; // Equal
|
||||
case 1: CSETMx(x2, cCC); break; // Less than
|
||||
case 2: CSETMx(x2, cLS); break; // Less or equal
|
||||
case 3: CSETMx(x2, cVS); break; // NaN
|
||||
case 4: CSETMx(x2, cNE); break; // Not Equal or unordered
|
||||
case 5: CSETMx(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMx(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: CSETMx(x2, cVC); break; // not NaN
|
||||
}
|
||||
VMOVQDfrom(v0, 0, x2);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("VADDSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
TABLE64(x2, (uintptr_t)&addsubps);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); if(v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(v0==v1) {
|
||||
VFMULQS(q1, v1, q0);
|
||||
VFADDQS(v0, v2, q1);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
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);
|
||||
if(!box64_dynarec_fastround || vex.l)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
GETEY(v1);
|
||||
}
|
||||
if(box64_dynarec_fastround) {
|
||||
VFRINTIDQ(l?d0:v0, v1);
|
||||
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(!l) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
|
||||
CSELx(x1, x1, x4, cEQ);
|
||||
VMOVQSfrom(v0, i+l*2, x1);
|
||||
}
|
||||
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 7, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
UMULH(x3, xRDX, ed);
|
||||
MULx(vd, xRDX, ed);
|
||||
MOVx_REG(gd, x3);
|
||||
} else {
|
||||
// 32bits mul
|
||||
UMULL(x3, xRDX, ed);
|
||||
MOVw_REG(vd, x3);
|
||||
LSRx(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("SHRX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
ANDx_mask(x3, vd, 1, 0, rex.w?5:4); // mask 0x3f/0x1f
|
||||
LSRxw_REG(gd, ed, x3);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("RORX Gd, Ed, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
RORxw(gd, ed, u8);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u, u64;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVSS Gx, Ex [,Vx]");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
if((v0!=v2) && (v0!=v1)) VMOVQ(v0, v2);
|
||||
if(v0!=v1) VMOVeS(v0, 0, v1, 0);
|
||||
if((v0!=v2) && (v0==v1)) { VMOVeS(v0, 1, v2, 1); VMOVeD(v0, 1, v2, 1);}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v0, ed, fixedaddress);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVSS Ex, Gx [,Vx]");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGXVXEX_empty(v0, v2, v1, 0);
|
||||
if((v2!=v1) && (v2!=v0)) VMOVQ(v2, v1);
|
||||
if(v2!=v0) VMOVeS(v2, 0, v0, 0);
|
||||
if((v2!=v1) && (v2==v0)) { VMOVeS(v2, 1, v0, 1); VMOVeD(v2, 1, v0, 1);}
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("VMOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(q0, q1);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(q0, q1);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("VCVTSI2SS Gx, Vx, Ed");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX_empty_VX(v0, v1);
|
||||
GETED(0);
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FRINTIS(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEXSS(d0, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FSQRTS(d1, d0);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("VRSQRTSS Gx, Vx Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
// and want 1.0f = 0x3f800000
|
||||
// so 00111111 10000000 00000000 00000000
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
FMOVS_8(d0, 0b01110000);
|
||||
FSQRTS(d1, v1);
|
||||
FDIVS(d0, d0, d1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("VADDSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0!=v2) {
|
||||
if(v0==v1) {
|
||||
VMOV(d1, v1);
|
||||
v1 = d1;
|
||||
}
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
FADDS(d1, v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0!=v2) {
|
||||
if(v0==v1) {
|
||||
VMOV(d1, v1);
|
||||
v1 = d1;
|
||||
}
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
FMULS(d1, v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0!=v2) {
|
||||
if(v0==v1) {
|
||||
VMOV(d1, v1);
|
||||
v1 = d1;
|
||||
}
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
FCVT_D_S(d1, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!box64_dynarec_fastround) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(box64_dynarec_fastround) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FSUBS(d1, v2, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPS(v2, v1);
|
||||
FCSELS(d1, v1, v2, cCS);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FDIVS(d1, v2, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPS(v1, v2);
|
||||
FCSELS(d1, v1, v2, cCS);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("VMOVDQU Gx, Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, -12, -1);
|
||||
GETGY_empty(v0, (nextop&7)+(rex.b<<3), -1, -1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
VDUP_16(d0, v1, 4+(u8&3));
|
||||
} else {
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
if(!l) {
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+8)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+9)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
}
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
}
|
||||
VMOVeD(v0, 1, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("VMOVDQU Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, (nextop&7) + (rex.b<<3), -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3), gd, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} // no ymm raz here it seems
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPSS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSS(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
if(((u8&15)!=11) && ((u8&15)!=15)) {
|
||||
if((u8&15)>7)
|
||||
FCMPS(v1, v2);
|
||||
else
|
||||
FCMPS(v2, v1);
|
||||
}
|
||||
// TODO: create a test for this one, there might be an issue with cases 9, 10 and 13
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
switch(u8&15) {
|
||||
case 0x00: CSETMw(x2, cEQ); break; // Equal
|
||||
case 0x01: CSETMw(x2, cCC); break; // Less than
|
||||
case 0x02: CSETMw(x2, cLS); break; // Less or equal
|
||||
case 0x03: CSETMw(x2, cVS); break; // NaN
|
||||
case 0x04: CSETMw(x2, cNE); break; // Not Equal or unordered
|
||||
case 0x05: CSETMw(x2, cCS); break; // Greater or equal or unordered
|
||||
case 0x06: CSETMw(x2, cHI); break; // Greater or unordered
|
||||
case 0x07: CSETMw(x2, cVC); break; // not NaN
|
||||
case 0x08: CSETMw(x2, cEQ); CSETMw(x3, cVS); ORRw_REG(x2, x2, x3); break; // Equal or unordered
|
||||
case 0x09: CSETMw(x2, cHI); break; // Less than or unordered
|
||||
case 0x0a: CSETMw(x2, cCS); break; // Less or equal or unordered
|
||||
case 0x0b: MOV32w(x2, 0); break; // false
|
||||
case 0x0c: CSETMw(x2, cNE); CSETMw(x3, cVS); BICw(x2, x2, x3); break; // Not Equal not unordered
|
||||
case 0x0d: CSETMw(x2, cLS); break; // Greater or equal not unordered
|
||||
case 0x0e: CSETMw(x2, cCC); break; // Greater not unordered
|
||||
case 0x0f: MOV32w(x2, 0xffffffff); break; // true
|
||||
}
|
||||
VMOVQSfrom(v0, 0, x2);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(vex.l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
} else {
|
||||
GETEXSD(v1, 0, 0);
|
||||
}
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(vex.l) {
|
||||
q0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
SXTL2_32(q0, v1);
|
||||
SCVTQFD(q0, q0);
|
||||
} else YMM0(gd);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -187,7 +187,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -200,7 +200,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -213,7 +213,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -227,7 +227,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -242,7 +242,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -255,7 +255,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -268,7 +268,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -281,7 +281,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
|
||||
@@ -165,6 +165,12 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
// load tag
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(i2<0) {
|
||||
LSLw_IMM(x3, x3, -i2*2);
|
||||
} else if(i2>0) {
|
||||
ORRw_mask(x3, x3, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(x3, x3, i2*2);
|
||||
}
|
||||
TSTw_mask(x3, 0, 1); // 0b11
|
||||
B_MARK3(cNE); // empty: C3,C2,C0 = 101
|
||||
// load x2 with ST0 anyway, for sign extraction
|
||||
@@ -331,7 +337,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
@@ -379,7 +385,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
@@ -490,7 +496,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_S_D(s0, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
|
||||
@@ -143,7 +143,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -153,7 +153,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -163,7 +163,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -174,7 +174,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -186,7 +186,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -196,7 +196,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -206,7 +206,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
@@ -216,7 +216,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
|
||||
@@ -194,7 +194,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
FRINT32ZD(s0, v1);
|
||||
FCVTZSwD(x5, s0);
|
||||
@@ -220,7 +220,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(x5, s0);
|
||||
@@ -246,7 +246,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(x5, s0);
|
||||
|
||||
@@ -185,7 +185,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FADDD(v1, v1, v2);
|
||||
@@ -193,7 +193,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FMULD(v1, v1, v2);
|
||||
@@ -201,7 +201,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
@@ -210,7 +210,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
@@ -220,7 +220,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v1, v2);
|
||||
@@ -228,7 +228,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FSUBD(v1, v2, v1);
|
||||
@@ -236,7 +236,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v1, v2);
|
||||
@@ -244,7 +244,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FDIVD(v1, v2, v1);
|
||||
|
||||
@@ -158,7 +158,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(ST_IS_I64(0)) {
|
||||
VST64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
|
||||
@@ -186,7 +186,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -197,7 +197,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -208,7 +208,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -220,7 +220,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -233,7 +233,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -244,7 +244,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -255,7 +255,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
@@ -266,7 +266,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
VLD16(v2, wback, fixedaddress);
|
||||
SXTL_16(v2, v2);
|
||||
|
||||
@@ -155,7 +155,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
#if 0
|
||||
// this version needs ARM v8.5, and doesn't handle saturation for 32bits integer not fitting 16bits
|
||||
FRINT32ZD(s0, v1);
|
||||
@@ -194,7 +194,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
@@ -234,7 +234,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
#if 0
|
||||
FRINT32XD(s0, v1);
|
||||
// no saturation instruction on Arm, so using NEON
|
||||
@@ -323,7 +323,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(ST_IS_I64(0)) {
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
|
||||
@@ -48,7 +48,7 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -500,7 +500,7 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -580,7 +580,7 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +626,6 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
@@ -67,7 +67,7 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -593,7 +593,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -707,7 +707,7 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
BFIxw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,7 +743,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,7 +780,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,7 +830,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
BFIxw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,7 +878,7 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,7 +926,7 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,7 +980,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,7 +1050,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1096,7 +1096,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1150,7 +1150,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1217,7 +1217,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1273,7 +1273,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1345,7 +1345,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1392,7 +1392,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1447,7 +1447,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,7 +1514,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1561,7 +1561,7 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1611,7 +1611,7 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1660,6 +1660,6 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
MOV32w(s3, 1);
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
} else
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
@@ -422,7 +422,7 @@ void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
LSRw(s3, s1, 7);
|
||||
@@ -577,7 +577,7 @@ void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +622,7 @@ void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
MOV32w(s3, 1);
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
} else
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
@@ -679,7 +679,7 @@ void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,7 +720,7 @@ void emit_shr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,7 +754,7 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +788,7 @@ void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1238,7 +1238,7 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1293,7 +1293,7 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1341,7 +1341,7 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1387,7 +1387,7 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1431,7 +1431,7 @@ void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1468,7 +1468,7 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1519,7 +1519,7 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1559,6 +1559,6 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
@@ -201,7 +201,7 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
@@ -223,7 +223,7 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,9 +252,8 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,9 +282,8 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,8 +312,7 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
LSRw(s4, s5, 7);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
|
||||
GETREX();
|
||||
SKIPTEST(x1); // DYNAREC_TEST doesn't work, by nature, on atomic opration
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
|
||||
@@ -84,14 +84,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
VDUPQ_64(v0, d0, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLDQ1R_64(v0, ed);
|
||||
}
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
@@ -99,7 +98,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
@@ -140,7 +139,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FRINTID(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
@@ -207,10 +206,10 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
FCMLTD_0(v1, d0);
|
||||
SHL_64(v1, v1, 63);
|
||||
FSQRTD(d1, d0);
|
||||
@@ -225,11 +224,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -247,11 +246,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -270,7 +269,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_S_D(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
@@ -279,11 +278,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -304,7 +303,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMINNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
@@ -317,11 +316,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(d0, v0, v1); // propagate NAN
|
||||
FCMEQD(d0, d0, d0); // 0 if NAN, 1 if not NAN
|
||||
@@ -342,7 +341,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMAXNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
@@ -361,7 +360,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
u8 = F8;
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
if(v0==v1) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, v1);
|
||||
}
|
||||
VDUP_16(v0, v1, u8&3);
|
||||
@@ -375,7 +374,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
@@ -393,7 +392,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(v1, ed, fixedaddress);
|
||||
}
|
||||
VFADDPQS(v0, v0, v1);
|
||||
@@ -406,14 +405,28 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(v1, ed, fixedaddress);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(d0, v0, v1);
|
||||
VUZP2Q_32(v0, v0, v1);
|
||||
VFSUBQS(v0, d0, v0);
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("(unsupported) UWAIT Ed");
|
||||
FAKEED;
|
||||
UDF(0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -439,7 +452,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
TABLE64(x2, (uintptr_t)&addsubps);
|
||||
@@ -472,7 +485,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
|
||||
@@ -84,7 +84,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
@@ -99,7 +99,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
@@ -117,7 +117,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
@@ -158,7 +158,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FRINTIS(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
@@ -172,11 +172,41 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38: /* MAP */
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF6:
|
||||
INST_NAME("ADOX Gd, Ed");
|
||||
nextop = F8;
|
||||
READFLAGS(X_OF);
|
||||
SETFLAGS(X_OF, SF_SUBSET);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
MRS_nzvc(x3);
|
||||
LSRw(x4, xFlags, F_OF);
|
||||
BFIx(x3, x4, 29, 1); // set C
|
||||
MSR_nzvc(x3); // load CC into ARM CF
|
||||
IFX(X_OF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
CSETw(x3, cCS);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
} else {
|
||||
ADCxw_REG(gd, gd, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -186,8 +216,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);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
// and want 1.0f = 0x3f800000
|
||||
// so 00111111 10000000 00000000 00000000
|
||||
@@ -203,7 +233,7 @@ 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);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
@@ -213,7 +243,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -222,7 +252,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -232,7 +262,7 @@ 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);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_D_S(d0, v1);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
@@ -248,7 +278,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -261,12 +291,11 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -278,7 +307,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMINNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
@@ -291,7 +320,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
@@ -303,7 +332,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMAXNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
@@ -333,7 +362,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 1) ;
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if (u8 == 0b00000000 || u8 == 0b01010101 || u8 == 0b10101010 || u8 == 0b11111111) {
|
||||
VDUPQ_16(d0, v1, (u8 & 3) + 4);
|
||||
} else {
|
||||
@@ -381,12 +410,40 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("(unsupported) WRFSBASE Ed");
|
||||
FAKEED;
|
||||
UDF(0);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("(unsupported) WRGSBASE Ed");
|
||||
FAKEED;
|
||||
UDF(0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("(unsupported) INCSSPD/INCSSPQ Ed");
|
||||
FAKEED;
|
||||
UDF(0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("(unsupported) UMONITOR Ed");
|
||||
FAKEED;
|
||||
UDF(0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
GETED(0);
|
||||
@@ -424,14 +481,18 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
}
|
||||
RBITxw(x3, ed); // reverse
|
||||
CLZxw(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
@@ -440,13 +501,17 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
}
|
||||
CLZxw(gd, ed); // x2 gets leading 0 == LZCNT
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
@@ -489,7 +554,7 @@ 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);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0); // there is only I64 -> Double vector conversion, not from i32
|
||||
break;
|
||||
|
||||
@@ -26,26 +26,55 @@
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn)
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
return SCRATCH0 + dyn->n.fpu_scratch++; // return an Sx
|
||||
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\n", ninst);
|
||||
if(dyn->n.neoncache[ret].t==NEON_CACHE_YMMR || dyn->n.neoncache[ret].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[ret].n); // mark as purged
|
||||
dyn->n.neoncache[ret].v = 0; // reset it
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Get 2 consicutive FPU scratch reg
|
||||
int fpu_get_double_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
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\n", ninst);
|
||||
if(dyn->n.neoncache[ret].t==NEON_CACHE_YMMR || dyn->n.neoncache[ret].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[ret].n); // mark as purged
|
||||
dyn->n.neoncache[ret].v = 0; // reset it
|
||||
}
|
||||
if(dyn->n.neoncache[ret+1].t==NEON_CACHE_YMMR || dyn->n.neoncache[ret+1].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[ret+1].n); // mark as purged
|
||||
dyn->n.neoncache[ret+1].v = 0; // reset it
|
||||
}
|
||||
dyn->n.fpu_scratch+=2;
|
||||
return ret;
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->n.fpu_scratch = 0;
|
||||
dyn->n.ymm_used = 0;
|
||||
dyn->n.ymm_regs = 0;
|
||||
dyn->n.ymm_write = 0;
|
||||
dyn->n.ymm_removed = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int t, int n)
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n)
|
||||
{
|
||||
int i=X870;
|
||||
while (dyn->n.fpuused[i]) ++i;
|
||||
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
|
||||
dyn->n.neoncache[i].v = 0; // reset it
|
||||
}
|
||||
dyn->n.fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
@@ -57,17 +86,34 @@ void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
dyn->n.fpuused[reg] = 0;
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_YMMR || dyn->n.neoncache[reg].t==NEON_CACHE_YMMW) {
|
||||
dyn->n.ymm_removed |= 1<<dyn->n.neoncache[reg].n;
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_YMMW)
|
||||
dyn->n.ymm_write |= 1<<dyn->n.neoncache[reg].n;
|
||||
if(reg>SCRATCH0)
|
||||
dyn->n.ymm_regs |= (8LL+reg-SCRATCH0)<<(dyn->n.neoncache[reg].n*4);
|
||||
else
|
||||
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(dyn->n.neoncache[reg].n*4);
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_I64)
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
if(dyn->n.fpu_scratch && reg==SCRATCH0+dyn->n.fpu_scratch-1)
|
||||
--dyn->n.fpu_scratch;
|
||||
}
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int ninst, int emm)
|
||||
{
|
||||
dyn->n.fpuused[EMM0 + emm] = 1;
|
||||
dyn->n.neoncache[EMM0 + emm].t = NEON_CACHE_MM;
|
||||
dyn->n.neoncache[EMM0 + emm].n = emm;
|
||||
dyn->n.news |= (1<<(EMM0 + emm));
|
||||
return EMM0 + emm;
|
||||
int ret = EMM0 + emm;
|
||||
if(dyn->n.neoncache[ret].t==NEON_CACHE_YMMR || dyn->n.neoncache[ret].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[ret].n); // mark as purged
|
||||
dyn->n.neoncache[ret].v = 0; // reset it
|
||||
}
|
||||
dyn->n.fpuused[ret] = 1;
|
||||
dyn->n.neoncache[ret].t = NEON_CACHE_MM;
|
||||
dyn->n.neoncache[ret].n = emm;
|
||||
dyn->n.news |= (1<<(ret));
|
||||
return ret;
|
||||
}
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
|
||||
@@ -84,14 +130,48 @@ int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
|
||||
dyn->n.news |= (1<<i);
|
||||
return i;
|
||||
}
|
||||
int internal_mark_ymm(dynarec_arm_t* dyn, int t, int ymm, int reg)
|
||||
{
|
||||
if((dyn->n.neoncache[reg].t==NEON_CACHE_YMMR) || (dyn->n.neoncache[reg].t==NEON_CACHE_YMMW)) {
|
||||
if(dyn->n.neoncache[reg].n == ymm) {
|
||||
// already there!
|
||||
if(t==NEON_CACHE_YMMW)
|
||||
dyn->n.neoncache[reg].t=t;
|
||||
return reg;
|
||||
}
|
||||
} else if(!dyn->n.neoncache[reg].v) {
|
||||
// found a slot!
|
||||
dyn->n.neoncache[reg].t=t;
|
||||
dyn->n.neoncache[reg].n=ymm;
|
||||
return reg;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int is_ymm_to_keep(dynarec_arm_t* dyn, int reg, int k1, int k2, int k3)
|
||||
{
|
||||
if((k1!=-1) && (dyn->n.neoncache[reg].n==k1))
|
||||
return 1;
|
||||
if((k2!=-1) && (dyn->n.neoncache[reg].n==k2))
|
||||
return 1;
|
||||
if((k3!=-1) && (dyn->n.neoncache[reg].n==k3))
|
||||
return 1;
|
||||
if((dyn->n.neoncache[reg].t==NEON_CACHE_YMMR || dyn->n.neoncache[reg].t==NEON_CACHE_YMMW) && (dyn->n.ymm_used&(1<<dyn->n.neoncache[reg].n)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset fpu regs counter
|
||||
static void fpu_reset_reg_neoncache(neoncache_t* n)
|
||||
{
|
||||
n->fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i) {
|
||||
for (int i=0; i<32; ++i) {
|
||||
n->fpuused[i]=0;
|
||||
n->neoncache[i].v = 0;
|
||||
}
|
||||
n->ymm_regs = 0;
|
||||
n->ymm_removed = 0;
|
||||
n->ymm_used = 0;
|
||||
n->ymm_write = 0;
|
||||
|
||||
}
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
@@ -343,10 +423,11 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
return ((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT))?0:(isCacheEmpty(dyn, ninst)?0:1);
|
||||
int ret = 0;
|
||||
if(!i2) { // just purge
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
if(dyn->insts[ninst].n.stack_next)
|
||||
return 1;
|
||||
}
|
||||
for(int i=0; i<24 && !ret; ++i)
|
||||
if(dyn->insts[ninst].ymm0_out)
|
||||
return 1;
|
||||
for(int i=0; i<32 && !ret; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
@@ -361,10 +442,12 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
if(dyn->insts[ninst].n.stack_next != dyn->insts[i2].n.stack-dyn->insts[i2].n.stack_push) {
|
||||
return 1;
|
||||
}
|
||||
if(dyn->insts[ninst].ymm0_out && (dyn->insts[ninst].ymm0_out&~dyn->insts[i2].ymm0_in))
|
||||
return 1;
|
||||
neoncache_t cache_i2 = dyn->insts[i2].n;
|
||||
neoncacheUnwind(&cache_i2);
|
||||
|
||||
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(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
ret = 1;
|
||||
@@ -374,6 +457,8 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
}
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{/* nothing */ }
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_YMMR && cache_i2.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
{/* nothing */ }
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
@@ -446,7 +531,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
cache->mmxcount = 0;
|
||||
cache->fpu_scratch = 0;
|
||||
cache->fpu_extra_qscratch = 0;
|
||||
cache->fpu_reg = 0;
|
||||
for(int i=0; i<8; ++i) {
|
||||
cache->x87cache[i] = -1;
|
||||
@@ -456,7 +540,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->ssecache[i*2+1].v = -1;
|
||||
}
|
||||
int x87reg = 0;
|
||||
for(int i=0; i<24; ++i) {
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(cache->neoncache[i].v) {
|
||||
cache->fpuused[i] = 1;
|
||||
switch (cache->neoncache[i].t) {
|
||||
@@ -471,6 +555,10 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_YMMR:
|
||||
case NEON_CACHE_YMMW:
|
||||
cache->fpuused[i] = 0; // YMM does not mark the fpu reg as used
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
case NEON_CACHE_ST_D:
|
||||
case NEON_CACHE_ST_I64:
|
||||
@@ -488,6 +576,24 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->fpuused[i] = 0;
|
||||
}
|
||||
}
|
||||
// add back removed YMM
|
||||
if(cache->ymm_removed) {
|
||||
for(int i=0; i<16; ++i)
|
||||
if(cache->ymm_removed&(1<<i)) {
|
||||
int reg = cache->ymm_regs>>(i*4)&15;
|
||||
if(reg>7)
|
||||
reg = reg - 8 + SCRATCH0;
|
||||
else
|
||||
reg = reg + EMM0;
|
||||
if(cache->neoncache[reg].v)
|
||||
printf_log(LOG_INFO, "Warning, recreating YMM%d on non empty slot %s", i, getCacheName(cache->neoncache[reg].t, cache->neoncache[reg].n));
|
||||
cache->neoncache[reg].t = (cache->ymm_write&(1<<i))?NEON_CACHE_YMMW:NEON_CACHE_YMMR;
|
||||
cache->neoncache[reg].n = i;
|
||||
}
|
||||
cache->ymm_regs = 0;
|
||||
cache->ymm_write = cache->ymm_removed = 0;
|
||||
}
|
||||
cache->ymm_used = 0;
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
@@ -543,6 +649,8 @@ const char* getCacheName(int t, int n)
|
||||
case NEON_CACHE_MM: sprintf(buff, "MM%d", n); break;
|
||||
case NEON_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
|
||||
case NEON_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
|
||||
case NEON_CACHE_YMMW: sprintf(buff, "YMM%d", n); break;
|
||||
case NEON_CACHE_YMMR: sprintf(buff, "ymm%d", n); break;
|
||||
case NEON_CACHE_SCR: sprintf(buff, "Scratch"); break;
|
||||
case NEON_CACHE_NONE: buff[0]='\0'; break;
|
||||
}
|
||||
@@ -574,13 +682,17 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);
|
||||
}
|
||||
if(!dyn->insts[ninst].x64.alive)
|
||||
dynarec_log(LOG_NONE, " not executed");
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)
|
||||
dynarec_log(LOG_NONE, ", jmp=out");
|
||||
if(dyn->insts[ninst].x64.has_callret)
|
||||
dynarec_log(LOG_NONE, ", callret");
|
||||
if(dyn->last_ip)
|
||||
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);
|
||||
for(int ii=0; ii<24; ++ii) {
|
||||
for(int ii=0; ii<32; ++ii) {
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) {
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
@@ -588,11 +700,27 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_YMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_YMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
//case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_NONE:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if(memcmp(dyn->insts[ninst].n.neoncache, dyn->n.neoncache, sizeof(dyn->n.neoncache))) {
|
||||
dynarec_log(LOG_NONE, " %s(Change:", (box64_dynarec_dump>1)?"\e[1;91m":"");
|
||||
for(int ii=0; ii<32; ++ii) if(dyn->insts[ninst].n.neoncache[ii].v!=dyn->n.neoncache[ii].v) {
|
||||
dynarec_log(LOG_NONE, " V%d:%s", ii, getCacheName(dyn->n.neoncache[ii].t, dyn->n.neoncache[ii].n));
|
||||
dynarec_log(LOG_NONE, "->%s", getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n));
|
||||
}
|
||||
dynarec_log(LOG_NONE, ")%s", (box64_dynarec_dump>1)?"\e[0;32m":"");
|
||||
}
|
||||
if(dyn->insts[ninst].n.ymm_used)
|
||||
dynarec_log(LOG_NONE, " ymmUsed=%04x", dyn->insts[ninst].n.ymm_used);
|
||||
if(dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out)
|
||||
dynarec_log(LOG_NONE, " ymm0=(%04x/%04x+%04x-%04x=%04x)", dyn->ymm_zero, dyn->insts[ninst].ymm0_in, dyn->insts[ninst].ymm0_add ,dyn->insts[ninst].ymm0_sub, dyn->insts[ninst].ymm0_out);
|
||||
if(dyn->insts[ninst].purge_ymm)
|
||||
dynarec_log(LOG_NONE, " purgeYmm=%04x", dyn->insts[ninst].purge_ymm);
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack)
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack);
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
@@ -640,22 +768,27 @@ static void sse_reset(neoncache_t* n)
|
||||
{
|
||||
for (int i=0; i<16; ++i)
|
||||
n->ssecache[i].v = -1;
|
||||
for (int i=0; i<32; ++i)
|
||||
if(n->neoncache[i].t==NEON_CACHE_YMMR || n->neoncache[i].t==NEON_CACHE_YMMW)
|
||||
n->neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
void fpu_reset(dynarec_native_t* dyn)
|
||||
{
|
||||
x87_reset(&dyn->n);
|
||||
mmx_reset(&dyn->n);
|
||||
sse_reset(&dyn->n);
|
||||
fpu_reset_reg(dyn);
|
||||
dyn->ymm_zero = 0;
|
||||
}
|
||||
|
||||
void fpu_reset_ninst(dynarec_arm_t* dyn, int ninst)
|
||||
void fpu_reset_ninst(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
x87_reset(&dyn->insts[ninst].n);
|
||||
mmx_reset(&dyn->insts[ninst].n);
|
||||
sse_reset(&dyn->insts[ninst].n);
|
||||
fpu_reset_reg_neoncache(&dyn->insts[ninst].n);
|
||||
|
||||
}
|
||||
|
||||
int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st)
|
||||
|
||||
@@ -4,21 +4,32 @@
|
||||
#include "../dynarec_native_functions.h"
|
||||
|
||||
#define SCRATCH0 24
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn);
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst);
|
||||
// Get 2 consecutive FPU scratch reg
|
||||
int fpu_get_double_scratch(dynarec_arm_t* dyn, int ninst);
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
// Get an x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int t, int n);
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n);
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm);
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int ninst, int emm);
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm);
|
||||
// Free a FPU/MMX/XMM reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg);
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
// internal YMM handling
|
||||
int internal_mark_ymm(dynarec_arm_t* dyn, int t, int ymm, int reg);
|
||||
// is ymm neoncache[reg] one of k1, k2, k3?
|
||||
int is_ymm_to_keep(dynarec_arm_t* dyn, int reg, int k1, int k2, int k3);
|
||||
|
||||
// ---- Neon cache functions
|
||||
// Get type for STx
|
||||
|
||||
@@ -743,7 +743,6 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
if(saveflags) {
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
fpu_pushcache(dyn, ninst, reg, 0);
|
||||
if(ret!=-2) {
|
||||
STPx_S7_preindex(xEmu, savereg, xSP, -16); // ARM64 stack needs to be 16byte aligned
|
||||
STPx_S7_offset(xRAX, xRCX, xEmu, offsetof(x64emu_t, regs[_AX])); // x9..x15, x16,x17,x18 those needs to be saved by caller
|
||||
@@ -751,6 +750,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
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]));
|
||||
fpu_pushcache(dyn, ninst, savereg, 0);
|
||||
}
|
||||
TABLE64(reg, (uintptr_t)fnc);
|
||||
BLR(reg);
|
||||
@@ -772,8 +772,8 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#undef GO
|
||||
fpu_popcache(dyn, ninst, savereg, 0); // savereg will not be used
|
||||
}
|
||||
fpu_popcache(dyn, ninst, reg, 0);
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
@@ -958,7 +958,7 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
++dyn->n.x87cache[i];
|
||||
else if(ret==-1) {
|
||||
dyn->n.x87cache[i] = 0;
|
||||
ret=dyn->n.x87reg[i]=fpu_get_reg_x87(dyn, t, 0);
|
||||
ret=dyn->n.x87reg[i]=fpu_get_reg_x87(dyn, ninst, t, 0);
|
||||
dyn->n.neoncache[ret].t = X87_ST0;
|
||||
}
|
||||
}
|
||||
@@ -998,7 +998,7 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
dyn->abort = 1;
|
||||
}
|
||||
}
|
||||
void static internal_x87_dopop(dynarec_arm_t* dyn)
|
||||
static void internal_x87_dopop(dynarec_arm_t* dyn)
|
||||
{
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
@@ -1009,7 +1009,7 @@ void static internal_x87_dopop(dynarec_arm_t* dyn)
|
||||
}
|
||||
}
|
||||
}
|
||||
int static internal_x87_dofree(dynarec_arm_t* dyn)
|
||||
static int internal_x87_dofree(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->n.tags&0b11) {
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 FREED ST0, poping 1 more\n");
|
||||
@@ -1119,12 +1119,20 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[i], s1, s3); // save the value
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
FCVT_D_S(SCRATCH, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s3); // save the value
|
||||
{
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_D_S(scratch, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(scratch, s1, s3); // save the value
|
||||
fpu_free_reg(dyn, scratch);
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
SCVTFDD(SCRATCH, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s3); // save the value
|
||||
{
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
SCVTFDD(scratch, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(scratch, s1, s3); // save the value
|
||||
fpu_free_reg(dyn, scratch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!next) {
|
||||
@@ -1199,8 +1207,10 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
ADDw_U12(s3, s2, dyn->n.x87cache[i]);
|
||||
ANDw_mask(s3, s3, 0, 2); // mask=7 // (emu->top + i)&7
|
||||
if(neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[i])>=0) {
|
||||
FCVT_D_S(SCRATCH0, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(SCRATCH0, s1, s3);
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_D_S(scratch, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(scratch, s1, s3);
|
||||
fpu_free_reg(dyn, scratch);
|
||||
} else
|
||||
VSTR64_REG_LSL3(dyn->n.x87reg[i], s1, s3);
|
||||
}
|
||||
@@ -1274,7 +1284,7 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
|
||||
ret = i;
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, NEON_CACHE_ST_D, st);
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
|
||||
if(populate) {
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
@@ -1342,11 +1352,15 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_D_S(scratch, reg);
|
||||
VSTR64_REG_LSL3(scratch, s1, s2);
|
||||
fpu_free_reg(dyn, scratch);
|
||||
} else if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_I64) {
|
||||
SCVTFDD(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
SCVTFDD(scratch, reg);
|
||||
VSTR64_REG_LSL3(scratch, s1, s2);
|
||||
fpu_free_reg(dyn, scratch);
|
||||
} else {
|
||||
VSTR64_REG_LSL3(reg, s1, s2);
|
||||
}
|
||||
@@ -1394,7 +1408,7 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
ret = i;
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, NEON_CACHE_ST_D, st);
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, x87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
int a = st - dyn->n.x87stack;
|
||||
@@ -1436,11 +1450,15 @@ void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st)
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7 // (emu->top + i)&7
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F) {
|
||||
FCVT_D_S(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_D_S(scratch, reg);
|
||||
VSTR64_REG_LSL3(scratch, s1, s2);
|
||||
fpu_free_reg(dyn, scratch);
|
||||
} else if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_I64) {
|
||||
SCVTFDD(SCRATCH, reg);
|
||||
VSTR64_REG_LSL3(SCRATCH, s1, s2);
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
SCVTFDD(scratch, reg);
|
||||
VSTR64_REG_LSL3(scratch, s1, s2);
|
||||
fpu_free_reg(dyn, scratch);
|
||||
} else {
|
||||
VSTR64_REG_LSL3(reg, s1, s2);
|
||||
}
|
||||
@@ -1544,7 +1562,7 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
return dyn->n.mmxcache[a];
|
||||
++dyn->n.mmxcount;
|
||||
int ret = dyn->n.mmxcache[a] = fpu_get_reg_emm(dyn, a);
|
||||
int ret = dyn->n.mmxcache[a] = fpu_get_reg_emm(dyn, ninst, a);
|
||||
VLDR64_U12(ret, xEmu, offsetof(x64emu_t, mmx[a]));
|
||||
return ret;
|
||||
}
|
||||
@@ -1556,7 +1574,7 @@ int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
return dyn->n.mmxcache[a];
|
||||
++dyn->n.mmxcount;
|
||||
int ret = dyn->n.mmxcache[a] = fpu_get_reg_emm(dyn, a);
|
||||
int ret = dyn->n.mmxcache[a] = fpu_get_reg_emm(dyn, ninst, a);
|
||||
return ret;
|
||||
}
|
||||
// purge the MMX cache only(needs 3 scratch registers)
|
||||
@@ -1630,6 +1648,22 @@ void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
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]));
|
||||
}
|
||||
// YMM part too
|
||||
if(is_avx_zero_unset(dyn, ninst, a)) {
|
||||
//only ymm[0] can be accessed with STP :(
|
||||
if(!a)
|
||||
STPx_S7_offset(xZR, xZR, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
else {
|
||||
STRx_U12(xZR, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
STRx_U12(xZR, xEmu, offsetof(x64emu_t, ymm[a])+8);
|
||||
}
|
||||
} else for(int i=0; i<32; ++i)
|
||||
if(((dyn->n.neoncache[i].t == NEON_CACHE_YMMW) || (dyn->n.neoncache[i].t == NEON_CACHE_YMMR)) && (dyn->n.neoncache[i].n==a)) {
|
||||
if(dyn->n.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
fpu_free_reg(dyn, i);
|
||||
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
|
||||
dyn->n.ssecache[a].v = -1;
|
||||
return;
|
||||
@@ -1673,6 +1707,36 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
dyn->n.ssecache[i].v = -1;
|
||||
}
|
||||
}
|
||||
//AVX
|
||||
if(dyn->ymm_zero) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge %sSSE Cache ------\n", next?"locally ":"");
|
||||
++old;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if(!next)
|
||||
avx_mark_zero_reset(dyn, ninst);
|
||||
}
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge %sSSE Cache ------\n", next?"locally ":"");
|
||||
++old;
|
||||
}
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
}
|
||||
if(!next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
// All done
|
||||
if(old!=-1) {
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge SSE Cache\n");
|
||||
}
|
||||
@@ -1684,10 +1748,37 @@ static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
if(dyn->n.ssecache[i].v!=-1 && 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]));
|
||||
}
|
||||
|
||||
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if(is_avx_zero(dyn, ninst, a)) {
|
||||
//only ymm[0] can be accessed with STP :(
|
||||
if(!a)
|
||||
STPx_S7_offset(xZR, xZR, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
else {
|
||||
STRx_U12(xZR, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
STRx_U12(xZR, xEmu, offsetof(x64emu_t, ymm[a])+8);
|
||||
}
|
||||
} else for(int i=0; i<32; ++i)
|
||||
if((dyn->n.neoncache[i].t == NEON_CACHE_YMMW) && (dyn->n.neoncache[i].n == a)) {
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
}
|
||||
if(dyn->n.ssecache[a].v==-1)
|
||||
return;
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
|
||||
@@ -1697,21 +1788,106 @@ void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
}
|
||||
}
|
||||
|
||||
// AVX Helpers
|
||||
// get neon register for a YMM upper reg, create the entry if needed
|
||||
int ymm_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite, int k1, int k2, int k3)
|
||||
{
|
||||
// look if already exist
|
||||
for(int i=0; i<32; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) && dyn->n.neoncache[i].n==a) {
|
||||
if(forwrite) {
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_YMMW;
|
||||
}
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
dyn->n.ymm_used|=(1<<a);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_sub |= (1<<a);
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
// nope, grab a new one
|
||||
if(dyn->ymm_zero&(1<<a))
|
||||
forwrite = 1; // if the reg was zero, then it will need to be write back
|
||||
int ret = fpu_get_reg_ymm(dyn, ninst, forwrite?NEON_CACHE_YMMW:NEON_CACHE_YMMR, a, k1, k2, k3);
|
||||
if(dyn->ymm_zero&(1<<a)) {
|
||||
VEORQ(ret, ret, ret);
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
} else {
|
||||
VLDR128_U12(ret, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
}
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_sub |= (1<<a);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
// get neon register for a YMM reg, but don't try to synch it if it needed to be created
|
||||
int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int k2, int k3)
|
||||
{
|
||||
// look if already exist
|
||||
for(int i=0; i<32; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) && dyn->n.neoncache[i].n==a) {
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_YMMW;
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
dyn->n.ymm_used|=(1<<a);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_sub |= (1<<a);
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
// nope, grab a new one
|
||||
int ret = fpu_get_reg_ymm(dyn, ninst, NEON_CACHE_YMMW, a, k1, k2, k3);
|
||||
if(dyn->ymm_zero&(1<<a))
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_sub |= (1<<a);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ymm_mark_zero(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
// look if already exist
|
||||
for(int i=0; i<32; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) && dyn->n.neoncache[i].n==a) {
|
||||
if(dyn->n.ymm_used&(1<<a)) {
|
||||
// special case, the reg was just added in the opcode and cannot be marked as 0, so just RAZ it now
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_YMMW;
|
||||
VEORQ(i, i, i);
|
||||
return;
|
||||
}
|
||||
fpu_free_reg(dyn, i);
|
||||
}
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_add |= (1<<a);
|
||||
#endif
|
||||
avx_mark_zero(dyn, ninst, a);
|
||||
}
|
||||
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
{
|
||||
int start = not07?8:0;
|
||||
// only SSE regs needs to be push back to xEmu (needs to be "write")
|
||||
int n=0;
|
||||
for (int i=start; i<16; i++)
|
||||
for (int i=start; i<16; i++) {
|
||||
if((dyn->n.ssecache[i].v!=-1) && (dyn->n.ssecache[i].write))
|
||||
++n;
|
||||
}
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPush XMM Cache (%d)------\n", n);
|
||||
for (int i=start; i<16; ++i)
|
||||
for (int i=start; i<16; ++i) {
|
||||
if((dyn->n.ssecache[i].v!=-1) && (dyn->n.ssecache[i].write)) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
}
|
||||
// push the YMM values
|
||||
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]));
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t------- Push XMM Cache (%d)\n", n);
|
||||
}
|
||||
|
||||
@@ -1723,6 +1899,9 @@ void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
for (int i=start; i<16; i++)
|
||||
if(dyn->n.ssecache[i].v!=-1)
|
||||
++n;
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR)
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPop XMM Cache (%d)------\n", n);
|
||||
@@ -1732,6 +1911,9 @@ void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
|
||||
/*dyn->n.ssecache[i].write = 0; // OPTIM: it's sync, so not write anymore
|
||||
dyn->n.neoncache[dyn->n.ssecache[i].reg].t = NEON_CACHE_XMMR;*/
|
||||
}
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR)
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
MESSAGE(LOG_DUMP, "\t------- Pop XMM Cache (%d)\n", n);
|
||||
}
|
||||
|
||||
@@ -1748,7 +1930,7 @@ static int findCacheSlot(dynarec_arm_t* dyn, int ninst, int t, int n, neoncache_
|
||||
{
|
||||
neon_cache_t f;
|
||||
f.n = n; f.t = t;
|
||||
for(int i=0; i<24; ++i) {
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(cache->neoncache[i].v == f.v)
|
||||
return i;
|
||||
if(cache->neoncache[i].n == n) {
|
||||
@@ -1779,6 +1961,14 @@ static int findCacheSlot(dynarec_arm_t* dyn, int ninst, int t, int n, neoncache_
|
||||
if(t==NEON_CACHE_XMMR)
|
||||
return i;
|
||||
break;
|
||||
case NEON_CACHE_YMMR:
|
||||
if(t==NEON_CACHE_YMMW)
|
||||
return i;
|
||||
break;
|
||||
case NEON_CACHE_YMMW:
|
||||
if(t==NEON_CACHE_YMMR)
|
||||
return i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1790,9 +1980,9 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
if (i==j)
|
||||
return;
|
||||
int quad = 0;
|
||||
if(cache->neoncache[i].t==NEON_CACHE_XMMR || cache->neoncache[i].t==NEON_CACHE_XMMW)
|
||||
if(cache->neoncache[i].t==NEON_CACHE_XMMR || cache->neoncache[i].t==NEON_CACHE_XMMW || cache->neoncache[i].t==NEON_CACHE_YMMR || cache->neoncache[i].t==NEON_CACHE_YMMW)
|
||||
quad =1;
|
||||
if(cache->neoncache[j].t==NEON_CACHE_XMMR || cache->neoncache[j].t==NEON_CACHE_XMMW)
|
||||
if(cache->neoncache[j].t==NEON_CACHE_XMMR || cache->neoncache[j].t==NEON_CACHE_XMMW || cache->neoncache[j].t==NEON_CACHE_YMMR || cache->neoncache[j].t==NEON_CACHE_YMMW)
|
||||
quad =1;
|
||||
|
||||
if(!cache->neoncache[i].v) {
|
||||
@@ -1811,17 +2001,15 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
neon_cache_t tmp;
|
||||
MESSAGE(LOG_DUMP, "\t - Swapping %d <-> %d\n", i, j);
|
||||
// There is no VSWP in Arm64 NEON to swap 2 register contents!
|
||||
// so use a scratch...
|
||||
if(quad) {
|
||||
VMOVQ(SCRATCH, i);
|
||||
VMOVQ(i, j);
|
||||
VMOVQ(j, SCRATCH);
|
||||
VEORQ(i, i, j);
|
||||
VEORQ(j, i, j);
|
||||
VEORQ(i, i, j);
|
||||
} else {
|
||||
VMOV(SCRATCH, i);
|
||||
VMOV(i, j);
|
||||
VMOV(j, SCRATCH);
|
||||
VEOR(i, i, j);
|
||||
VEOR(j, i, j);
|
||||
VEOR(i, i, j);
|
||||
}
|
||||
#undef SCRATCH
|
||||
tmp.v = cache->neoncache[i].v;
|
||||
cache->neoncache[i].v = cache->neoncache[j].v;
|
||||
cache->neoncache[j].v = tmp.v;
|
||||
@@ -1831,9 +2019,9 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
{
|
||||
if(cache->neoncache[i].v) {
|
||||
int quad = 0;
|
||||
if(t==NEON_CACHE_XMMR || t==NEON_CACHE_XMMW)
|
||||
if(t==NEON_CACHE_XMMR || t==NEON_CACHE_XMMW || t==NEON_CACHE_YMMR || t==NEON_CACHE_YMMW)
|
||||
quad = 1;
|
||||
if(cache->neoncache[i].t==NEON_CACHE_XMMR || cache->neoncache[i].t==NEON_CACHE_XMMW)
|
||||
if(cache->neoncache[i].t==NEON_CACHE_XMMR || cache->neoncache[i].t==NEON_CACHE_XMMW || cache->neoncache[i].t==NEON_CACHE_YMMR || cache->neoncache[i].t==NEON_CACHE_YMMW)
|
||||
quad = 1;
|
||||
int j = i+1;
|
||||
while(cache->neoncache[j].v)
|
||||
@@ -1852,6 +2040,11 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
break;
|
||||
case NEON_CACHE_YMMR:
|
||||
case NEON_CACHE_YMMW:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, ymm[n]));
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
VLDR64_U12(i, xEmu, offsetof(x64emu_t, mmx[n]));
|
||||
@@ -1900,12 +2093,17 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
{
|
||||
switch(t) {
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_YMMR:
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring %s\n", getCacheName(t, n));
|
||||
break;
|
||||
case NEON_CACHE_XMMW:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
break;
|
||||
case NEON_CACHE_YMMW:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[n]));
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR64_U12(i, xEmu, offsetof(x64emu_t, mmx[n]));
|
||||
@@ -1950,7 +2148,6 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
|
||||
static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
#if STEP > 1
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(i2<0)
|
||||
return;
|
||||
@@ -1985,29 +2182,48 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
int stack_cnt = dyn->n.stack_next;
|
||||
int s3_top = 0xffff;
|
||||
neoncache_t cache = dyn->n;
|
||||
int s1_val = 0;
|
||||
int s2_val = 0;
|
||||
// unload every uneeded cache
|
||||
// check SSE first, than MMX, in order, for optimisation issue
|
||||
// ymm0 first
|
||||
int s3_top = 1;
|
||||
uint16_t to_purge = dyn->ymm_zero&~dyn->insts[i2].ymm0_in;
|
||||
if(dyn->ymm_zero && (dyn->insts[i2].purge_ymm|to_purge)) {
|
||||
MESSAGE(LOG_DUMP, "\t- YMM Zero %04x / %04x\n", dyn->ymm_zero, (dyn->insts[i2].purge_ymm|to_purge));
|
||||
for(int i=0; i<16; ++i)
|
||||
if(is_avx_zero(dyn, ninst, i) && (dyn->insts[i2].purge_ymm|to_purge)&(1<<i)) {
|
||||
if(s3_top) {
|
||||
ADDx_U12(s3, xEmu,offsetof(x64emu_t, ymm[0]));
|
||||
s3_top = 0;
|
||||
}
|
||||
STPx_S7_offset(xZR, xZR, s3, i*16);
|
||||
}
|
||||
}
|
||||
s3_top = 0xffff;
|
||||
// check SSE first, than MMX, in order, to optimise successive memory write
|
||||
for(int i=0; i<16; ++i) {
|
||||
int j=findCacheSlot(dyn, ninst, NEON_CACHE_XMMW, i, &cache);
|
||||
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_XMMW, i, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n);
|
||||
}
|
||||
for(int i=0; i<16; ++i) {
|
||||
int j=findCacheSlot(dyn, ninst, NEON_CACHE_YMMW, i, &cache);
|
||||
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_YMMW, i, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n);
|
||||
}
|
||||
for(int i=0; i<8; ++i) {
|
||||
int j=findCacheSlot(dyn, ninst, NEON_CACHE_MM, i, &cache);
|
||||
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_MM, i, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n);
|
||||
}
|
||||
for(int i=0; i<24; ++i) {
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(cache.neoncache[i].v)
|
||||
if(findCacheSlot(dyn, ninst, cache.neoncache[i].t, cache.neoncache[i].n, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, i, cache.neoncache[i].t, cache.neoncache[i].n);
|
||||
}
|
||||
// and now load/swap the missing one
|
||||
for(int i=0; i<24; ++i) {
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(cache_i2.neoncache[i].v) {
|
||||
if(cache_i2.neoncache[i].v != cache.neoncache[i].v) {
|
||||
int j;
|
||||
@@ -2045,13 +2261,20 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
SCVTFDD(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{ cache.neoncache[i].t = NEON_CACHE_XMMW; }
|
||||
else if(cache.neoncache[i].t == NEON_CACHE_XMMW && cache_i2.neoncache[i].t == NEON_CACHE_XMMR) {
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW) {
|
||||
cache.neoncache[i].t = NEON_CACHE_XMMW;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_YMMR && cache_i2.neoncache[i].t == NEON_CACHE_YMMW) {
|
||||
cache.neoncache[i].t = NEON_CACHE_YMMW;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_XMMW && cache_i2.neoncache[i].t == NEON_CACHE_XMMR) {
|
||||
// refresh cache...
|
||||
MESSAGE(LOG_DUMP, "\t - Refreh %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, xmm[cache.neoncache[i].n]));
|
||||
cache.neoncache[i].t = NEON_CACHE_XMMR;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_YMMW && cache_i2.neoncache[i].t == NEON_CACHE_YMMR) {
|
||||
// refresh cache...
|
||||
MESSAGE(LOG_DUMP, "\t - Refreh %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[cache.neoncache[i].n]));
|
||||
cache.neoncache[i].t = NEON_CACHE_YMMR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2089,16 +2312,14 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
stack_cnt = cache_i2.stack;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
#endif
|
||||
}
|
||||
static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
int j64;
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return;
|
||||
if(dyn->f.dfnone) // flags are fully known, nothing we can do more
|
||||
if(dyn->f.dfnone || (dyn->insts[jmp].f_exit.dfnone_here && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone)?1:0;
|
||||
@@ -2132,21 +2353,27 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
CALL_(UpdateFlags, -1, 0);
|
||||
MARKF2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3) {
|
||||
if(cacheupd&2)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
if(cacheupd&1)
|
||||
flagsCacheTransform(dyn, ninst, s1);
|
||||
if(cacheupd&2)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
}
|
||||
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_reflectcache(dyn, ninst, s1, s2, s3);
|
||||
mmx_reflectcache(dyn, ninst, s1);
|
||||
sse_reflectcache(dyn, ninst, s1);
|
||||
//sse_reflectcache(dyn, ninst, s1); // no need, it's pushed/unpushed during call
|
||||
// but ymm0 needs to be pushed
|
||||
if(dyn->ymm_zero) {
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, ymm[0]));
|
||||
for(int i=0; i<16; ++i)
|
||||
if(dyn->ymm_zero&(1<<i))
|
||||
STPx_S7_offset(xZR, xZR, s1, 16*i);
|
||||
}
|
||||
}
|
||||
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
@@ -2155,17 +2382,14 @@ void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
x87_unreflectcache(dyn, ninst, s1, s2, s3);
|
||||
}
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s4)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
ANDw_mask(s3, s1, 0b011011, 0b000010); // mask=0xE0
|
||||
LSRw(s3, s3, 5);
|
||||
TABLE64(s4, (uintptr_t)GetParityTab());
|
||||
LDRw_REG_LSL2(s4, s4, s3);
|
||||
ANDw_mask(s3, s1, 0, 0b000100); //0x1f
|
||||
LSRw_REG(s4, s4, s3);
|
||||
MAYUSE(s1); MAYUSE(s4);
|
||||
// by xor'ing all the bit 2 by two with a shift, pair of bits are removed, and only 1 is left if bit number if odd
|
||||
EORw_REG_LSR(s4, s1, s1, 4);
|
||||
EORw_REG_LSR(s4, s4, s4, 2);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
MVNw_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
@@ -2253,18 +2477,20 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
dyn->ymm_zero = dyn->insts[ninst].ymm0_in;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
dyn->ymm_zero = dyn->insts[reset_n].ymm0_out;
|
||||
#endif
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#if STEP == 0
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "New x87stack=%d\n", dyn->n.x87stack);
|
||||
if(box64_dynarec_dump && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
if(box64_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
if(box64_dynarec_dump && 0) //disable for now, need more work
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neoncache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
@@ -2272,7 +2498,7 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
@@ -2280,7 +2506,7 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
@@ -2312,3 +2538,129 @@ void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst)
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
}
|
||||
|
||||
void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1)
|
||||
{
|
||||
int s1_set = 0;
|
||||
int do_something = 0;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(mask&(1<<i)) {
|
||||
if(is_avx_zero_unset(dyn, ninst, i)) {
|
||||
if(!do_something) {
|
||||
MESSAGE(LOG_NONE, "Purge YMM mask=%04x --------\n", mask);
|
||||
do_something = 1;
|
||||
}
|
||||
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 j=0; j<32; ++j)
|
||||
if(dyn->n.neoncache[j].t==NEON_CACHE_YMMR && dyn->n.neoncache[j].n==i) {
|
||||
// just forget the reg....
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
j=32;
|
||||
} else if(dyn->n.neoncache[j].t==NEON_CACHE_YMMW && dyn->n.neoncache[j].n==i) {
|
||||
if(!do_something) {
|
||||
MESSAGE(LOG_NONE, "Purge YMM mask=%04x --------\n", mask);
|
||||
do_something = 1;
|
||||
}
|
||||
VSTR128_U12(j, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
j=32;
|
||||
}
|
||||
}
|
||||
if(do_something)
|
||||
MESSAGE(LOG_NONE, "---------- Purge YMM\n");
|
||||
}
|
||||
|
||||
// Get an YMM quad reg, while preserving up to 3 other YMM regs
|
||||
int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k2, int k3)
|
||||
{
|
||||
int i = -1;
|
||||
dyn->n.ymm_used|=(1<<ymm);
|
||||
#if STEP > 1
|
||||
// check the cached neoncache, it should be exact
|
||||
// look for it
|
||||
for(int ii=0; ii<32 && i==-1; ++ii)
|
||||
if(dyn->insts[ninst].n.neoncache[ii].n==ymm && (dyn->insts[ninst].n.neoncache[ii].t==NEON_CACHE_YMMR || dyn->insts[ninst].n.neoncache[ii].t==NEON_CACHE_YMMW))
|
||||
i = ii;
|
||||
if(i!=-1) {
|
||||
// already there!
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR) && dyn->n.neoncache[i].n==ymm) {
|
||||
if(t==NEON_CACHE_YMMW)
|
||||
dyn->n.neoncache[i].t=t;
|
||||
return i;
|
||||
}
|
||||
// check if free or should be purge before...
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
dyn->n.neoncache[i].t=t;
|
||||
dyn->n.neoncache[i].n=ymm;
|
||||
return i;
|
||||
}
|
||||
printf_log(LOG_NONE, "BOX64 Dynarec: Warning, unable to find YMM %d in neoncache at inst=%d\n", ymm, ninst);
|
||||
#else
|
||||
i = EMM0;
|
||||
// first pass see if a slot is free in EMM/x87 slots
|
||||
for(int j=0; j<8; ++j) {
|
||||
if(!dyn->n.fpuused[i+j]) {
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
if(ret>=0) return ret;
|
||||
}
|
||||
}
|
||||
// no slot in the emm space, look for scratch space in reverse
|
||||
i = SCRATCH0;
|
||||
for(int j=7; j>=dyn->n.fpu_scratch; --j) {
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
if(ret>=0) return ret;
|
||||
}
|
||||
// no free slot, needs to purge a value... First loop on the YMMR, they are easier to purge
|
||||
i = EMM0;
|
||||
for(int j=0; j<8; ++j) {
|
||||
if(!dyn->n.fpuused[i+j]) {
|
||||
// should a test be done to check if ymm is already in the purge list?
|
||||
if(!is_ymm_to_keep(dyn, i+j, k1, k2, k3) && (dyn->n.neoncache[i+j].t==NEON_CACHE_YMMR)) {
|
||||
dyn->n.neoncache[i+j].v = 0;
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
if(ret>=0) return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = SCRATCH0;
|
||||
for(int j=dyn->n.fpu_scratch; j<8; ++j) {
|
||||
if(!is_ymm_to_keep(dyn, i+j, k1, k2, k3) && (dyn->n.neoncache[i+j].t==NEON_CACHE_YMMR)) {
|
||||
dyn->n.neoncache[i+j].v = 0;
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
if(ret>=0) return ret;
|
||||
}
|
||||
}
|
||||
// make space in the scratch area
|
||||
for(int j=dyn->n.fpu_scratch; j<8; ++j) {
|
||||
// should a test be done to check if ymm is already in the purge list?
|
||||
if(!is_ymm_to_keep(dyn, i+j, k1, k2, k3)) {
|
||||
// Save the reg and recycle it
|
||||
VSTR128_U12(i+j, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i+j].n]));
|
||||
dyn->n.neoncache[i+j].v = 0;
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
if(ret>=0) return ret;
|
||||
}
|
||||
}
|
||||
// last resort, go back in the EMM area...
|
||||
i = EMM0;
|
||||
for(int j=7; j>=0; --j) {
|
||||
if(!dyn->n.fpuused[i+j]) {
|
||||
// should a test be done to check if ymm is already in the purge list?
|
||||
if((dyn->n.neoncache[i+j].t==NEON_CACHE_YMMW) && !is_ymm_to_keep(dyn, i+j, k1, k2, k3)) {
|
||||
VSTR128_U12(i+j, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i+j].n]));
|
||||
dyn->n.neoncache[i+j].v = 0;
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
if(ret>=0) return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#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;
|
||||
}
|
||||
@@ -90,6 +90,8 @@
|
||||
|
||||
// GETGD get x64 register in gd
|
||||
#define GETGD gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3)
|
||||
// GETVD get x64 register in vd
|
||||
#define GETVD vd = xRAX+vex.v
|
||||
//GETED can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETED(D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
@@ -280,6 +282,19 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
#define GETEW32(i, D) if(MODREG) { \
|
||||
wback = xRAX+(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; \
|
||||
}
|
||||
//GETEWO will use i for ed, i is also Offset, and can use r3 for wback.
|
||||
#define GETEWO(i, D) if(MODREG) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);\
|
||||
@@ -436,6 +451,172 @@
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
// Get VX as a quad (might use x1)
|
||||
#define GETVX(a, w) \
|
||||
a = sse_get_reg(dyn, ninst, x1, vex.v, w)
|
||||
|
||||
// Get an empty VX (use x1)
|
||||
#define GETVX_empty(a) \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, vex.v)
|
||||
|
||||
// Get empty VX, and non-writen EX
|
||||
#define GETVX_empty_EX(vx, ex, D) \
|
||||
GETEX_Y(ex, 0, D); \
|
||||
GETVX_empty(vx)
|
||||
|
||||
// Get VX, and EX
|
||||
#define GETVXEX(vx, w1, ex, w2, D) \
|
||||
GETEX_Y(ex, w2, D); \
|
||||
GETVX(vx, w1)
|
||||
|
||||
#define GETGY_VY(a, w1, b, w2, k1, k2) \
|
||||
if(w2) b = ymm_get_reg(dyn, ninst, x1, vex.v, w2, gd, k1, k2); \
|
||||
a = ymm_get_reg(dyn, ninst, x1, gd, w1, vex.v, k1, k2); \
|
||||
if(!w2) b = ymm_get_reg(dyn, ninst, x1, vex.v, w2, gd, k1, k2)
|
||||
|
||||
#define GETGY_empty(a, k1, k2, k3) \
|
||||
a = ymm_get_reg_empty(dyn, ninst, x1, gd, k1, k2, k3)
|
||||
|
||||
#define GETGY(a, w, k1, k2, k3) \
|
||||
a = ymm_get_reg(dyn, ninst, x1, gd, w, k1, k2, k3)
|
||||
|
||||
#define GETGY_empty_VY(a, b, w2, k1, k2) \
|
||||
b = ymm_get_reg(dyn, ninst, x1, vex.v, w2, gd, k1, k2); \
|
||||
a = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, k1, k2)
|
||||
|
||||
// Get empty GX, and non-writen VX and EX
|
||||
#define GETGX_empty_VXEX(gx, vx, ex, D) \
|
||||
GETVX(vx, 0); \
|
||||
GETEX_Y(ex, 0, D); \
|
||||
GETGX_empty(gx)
|
||||
|
||||
// Get empty GX, and non-writen EX
|
||||
#define GETGX_empty_EX(gx, ex, D) \
|
||||
GETEX_Y(ex, 0, D); \
|
||||
GETGX_empty(gx)
|
||||
|
||||
// Get empty GX, and non-writen VX
|
||||
#define GETGX_empty_VX(gx, vx) \
|
||||
GETVX(vx, 0); \
|
||||
GETGX_empty(gx)
|
||||
|
||||
// Get EX and and non-writen VX and GX
|
||||
#define GETGXVXEX(gx, vx, ex, D) \
|
||||
GETVX(vx, 0); \
|
||||
GETEX_Y(ex, 1, D); \
|
||||
GETGX(gx, 0)
|
||||
|
||||
// Get GX and and non-writen VX and EX
|
||||
#define GETGX_VXEX(gx, vx, ex, D) \
|
||||
GETVX(vx, 0); \
|
||||
GETEX_Y(ex, 0, D); \
|
||||
GETGX(gx, 1)
|
||||
|
||||
#define GETGXVXEX_empty(gx, vx, ex, D) \
|
||||
GETVX(vx, 0); \
|
||||
GETGX(gx, 0); \
|
||||
GETEX_empty_Y(ex, D);
|
||||
|
||||
// Get empty GY, and non-writen VY and EY
|
||||
#define GETGY_empty_VYEY(gy, vy, ey) \
|
||||
vy = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1); \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
gy = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1)
|
||||
|
||||
// Get EY and non-writen VY and GY
|
||||
#define GETGYVYEY(gy, vy, ey) \
|
||||
vy = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1); \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, gd, vex.v, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
gy = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1)
|
||||
|
||||
// Get GY and non-writen VY and EY
|
||||
#define GETGY_VYEY(gy, vy, ey) \
|
||||
vy = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1); \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
gy = ymm_get_reg(dyn, ninst, x1, gd, 1, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1)
|
||||
|
||||
// Get empty EY and non-writen VY and GY
|
||||
#define GETGYVYEY_empty(gy, vy, ey) \
|
||||
vy = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1); \
|
||||
gy = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1); \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3), gd, vex.v, -1)
|
||||
|
||||
// Get EY and non-writen GY
|
||||
#define GETGYEY(gy, ey) \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, gd, -1, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
gy = ymm_get_reg(dyn, ninst, x1, gd, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1, -1)
|
||||
|
||||
// Get EY
|
||||
#define GETEY(ey) \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, -1, -1, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
|
||||
// Get written EY
|
||||
#define GETEYw(ey) \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, -1, -1, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
|
||||
// Get empty EY and non-writen GY
|
||||
#define GETGYEY_empty(gy, ey) \
|
||||
gy = ymm_get_reg(dyn, ninst, x1, gd, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1, -1); \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3), gd, -1, -1)
|
||||
|
||||
// Get empty GY, and non-writen EY
|
||||
#define GETGY_empty_EY(gy, ey) \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, -1, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
gy = ymm_get_reg_empty(dyn, ninst, x1, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1, -1)
|
||||
|
||||
// Get empty VY, and non-writen EY
|
||||
#define GETVY_empty_EY(vy, ey) \
|
||||
if(MODREG) \
|
||||
ey = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, vex.v, -1, -1); \
|
||||
else \
|
||||
VLDR128_U12(ey, ed, fixedaddress+16); \
|
||||
vy = ymm_get_reg_empty(dyn, ninst, x1, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1, -1)
|
||||
|
||||
// Get EX as a quad, (x3 is used)
|
||||
#define GETEX_Y(a, w, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x3, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, D); \
|
||||
unscaled = 0; \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
// Get EX as a quad, (x3 is used)
|
||||
#define GETEX_empty_Y(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
WILLWRITE2(); \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, D); \
|
||||
unscaled = 0; \
|
||||
}
|
||||
|
||||
// Get EX as a quad, (x1 is used)
|
||||
#define GETEX(a, w, D) \
|
||||
if(MODREG) { \
|
||||
@@ -443,7 +624,7 @@
|
||||
} else { \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
VLD128(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
@@ -461,7 +642,7 @@
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
VLD64(a, ed, fixedaddress); \
|
||||
}
|
||||
@@ -475,7 +656,7 @@
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, D); \
|
||||
VLD32(a, ed, fixedaddress); \
|
||||
}
|
||||
@@ -489,7 +670,7 @@
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
|
||||
} else { \
|
||||
if(w) {WILLWRITE2();} else {SMREAD();} \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, D); \
|
||||
VLD16(a, ed, fixedaddress); \
|
||||
}
|
||||
@@ -506,7 +687,7 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
VLD64(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
@@ -517,6 +698,7 @@
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
#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)
|
||||
@@ -837,7 +1019,7 @@
|
||||
x87_do_pop(dyn, ninst, scratch)
|
||||
#endif
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->f.dfnone) {STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=1;}
|
||||
#define SET_DFNONE(S) do {dyn->f.dfnone_here=1; if(!dyn->f.dfnone) {STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=1;}} while(0);
|
||||
#define SET_DF(S, N) \
|
||||
if((N)!=d_none) { \
|
||||
MOVZw(S, (N)); \
|
||||
@@ -850,10 +1032,10 @@
|
||||
dyn->f.dfnone=0; \
|
||||
} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
#define SET_DFOK() dyn->f.dfnone = 1; dyn->f.dfnone_here=1
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS()
|
||||
#define MAYSETFLAGS() do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
@@ -986,6 +1168,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define dynarec64_66 STEPNAME(dynarec64_66)
|
||||
#define dynarec64_67 STEPNAME(dynarec64_67)
|
||||
#define dynarec64_67_32 STEPNAME(dynarec64_67_32)
|
||||
#define dynarec64_67_AVX STEPNAME(dynarec64_67_AVX)
|
||||
#define dynarec64_6764_32 STEPNAME(dynarec64_6764_32)
|
||||
#define dynarec64_D8 STEPNAME(dynarec64_D8)
|
||||
#define dynarec64_D9 STEPNAME(dynarec64_D9)
|
||||
@@ -1003,6 +1186,16 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define dynarec64_66F0 STEPNAME(dynarec64_66F0)
|
||||
#define dynarec64_F20F STEPNAME(dynarec64_F20F)
|
||||
#define dynarec64_F30F STEPNAME(dynarec64_F30F)
|
||||
#define dynarec64_AVX STEPNAME(dynarec64_AVX)
|
||||
#define dynarec64_AVX_0F STEPNAME(dynarec64_AVX_0F)
|
||||
#define dynarec64_AVX_0F38 STEPNAME(dynarec64_AVX_0F38)
|
||||
#define dynarec64_AVX_66_0F STEPNAME(dynarec64_AVX_66_0F)
|
||||
#define dynarec64_AVX_F2_0F STEPNAME(dynarec64_AVX_F2_0F)
|
||||
#define dynarec64_AVX_F3_0F STEPNAME(dynarec64_AVX_F3_0F)
|
||||
#define dynarec64_AVX_66_0F38 STEPNAME(dynarec64_AVX_66_0F38)
|
||||
#define dynarec64_AVX_66_0F3A STEPNAME(dynarec64_AVX_66_0F3A)
|
||||
#define dynarec64_AVX_F2_0F38 STEPNAME(dynarec64_AVX_F2_0F38)
|
||||
#define dynarec64_AVX_F2_0F3A STEPNAME(dynarec64_AVX_F2_0F3A)
|
||||
|
||||
#define geted STEPNAME(geted)
|
||||
#define geted32 STEPNAME(geted32)
|
||||
@@ -1136,9 +1329,13 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
#define sse_get_reg_empty STEPNAME(sse_get_reg_empty)
|
||||
#define sse_forget_reg STEPNAME(sse_forget_reg)
|
||||
#define sse_purge07cache STEPNAME(sse_purge07cache)
|
||||
#define sse_reflect_reg STEPNAME(sse_reflect_reg)
|
||||
#define sse_forget_reg STEPNAME(sse_forget_reg)
|
||||
#define sse_purge07cache STEPNAME(sse_purge07cache)
|
||||
#define sse_reflect_reg STEPNAME(sse_reflect_reg)
|
||||
#define ymm_get_reg STEPNAME(ymm_get_reg)
|
||||
#define ymm_get_reg_empty STEPNAME(ymm_get_reg_empty)
|
||||
#define ymm_mark_zero STEPNAME(ymm_mark_zero)
|
||||
#define fpu_get_reg_ymm STEPNAME(fpu_get_reg_ymm)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
@@ -1149,6 +1346,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
|
||||
#define avx_purge_ymm STEPNAME(avx_purge_ymm)
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
|
||||
@@ -1272,7 +1470,7 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s4);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid update at every call, return old internal stack counter
|
||||
@@ -1309,6 +1507,8 @@ int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// purge ymm_zero mask according to purge_ymm
|
||||
void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
@@ -1324,7 +1524,6 @@ void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
// scratch fpu regs for convertions
|
||||
#define SCRATCH 31
|
||||
|
||||
#if STEP == 0
|
||||
#define ST_IS_F(A) 0
|
||||
@@ -1361,11 +1560,11 @@ int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite);
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// forget neon register for a SSE reg, create the entry if needed
|
||||
// forget neon register for a SSE reg, YMM high part too
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// purge the XMM0..XMM7 cache (before function call)
|
||||
void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Push current value to the cache
|
||||
// Push current value to the cache (ymm too)
|
||||
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// common coproc helpers
|
||||
// reset the cache with n
|
||||
@@ -1382,6 +1581,15 @@ void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07);
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07);
|
||||
// avx helpers
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int ymm_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite, int k1, int k2, int k3);
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int k2, int k3);
|
||||
// mark an ymm upper part has zero (forgetting upper part if needed)
|
||||
void ymm_mark_zero(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get an YMM upper quad reg, while keeping up to 3 other YMM reg (-1 to no keep)
|
||||
int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k2, int k3);
|
||||
|
||||
uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
@@ -1390,6 +1598,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
@@ -1407,6 +1616,16 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_F2_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_AVX_F2_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2(A)
|
||||
@@ -1564,5 +1783,6 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} \
|
||||
}
|
||||
|
||||
#define PURGE_YMM() avx_purge_ymm(dyn, ninst, dyn->insts[ninst+1].purge_ymm, x1)
|
||||
|
||||
#endif //__DYNAREC_ARM64_HELPER_H__
|
||||
@@ -5,7 +5,7 @@
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; dyn->f.dfnone = 1;\
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x64.size>(dyn->insts[ninst].size/4))?dyn->insts[ninst].x64.size:(dyn->insts[ninst].size/4))/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do{dyn->insts[ninst].size+=4; dyn->native_size+=4;}while(0)
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>(dyn->insts[ninst-1].size/4))?dyn->insts[ninst-1].x64.size:(dyn->insts[ninst-1].size/4))/15; \
|
||||
dyn->insts[ninst].ymm0_pass2 = dyn->ymm_zero; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
#define TABLE64(A, V) {Table64(dyn, (V), 2); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
|
||||
@@ -14,8 +14,10 @@
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4);
|
||||
if(ninst) { \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4); \
|
||||
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
|
||||
}
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
|
||||
|
||||
@@ -16,7 +16,9 @@ typedef struct instsize_s instsize_t;
|
||||
#define NEON_CACHE_MM 4
|
||||
#define NEON_CACHE_XMMW 5
|
||||
#define NEON_CACHE_XMMR 6
|
||||
#define NEON_CACHE_SCR 7
|
||||
#define NEON_CACHE_YMMW 7
|
||||
#define NEON_CACHE_YMMR 8
|
||||
#define NEON_CACHE_SCR 9
|
||||
typedef union neon_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
@@ -33,7 +35,7 @@ typedef union sse_cache_s {
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
// Neon cache
|
||||
neon_cache_t neoncache[24];
|
||||
neon_cache_t neoncache[32];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
@@ -51,17 +53,21 @@ typedef struct neoncache_s {
|
||||
int16_t tags; // similar to fpu_tags
|
||||
int8_t mmxcache[8]; // cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[16]; // cache status for the 16 SSE(2) registers
|
||||
int8_t fpuused[24]; // all 0..24 double reg from fpu, used by x87, sse and mmx
|
||||
int8_t fpuused[32]; // all neon regs, used by x87, mmx, sse and avx
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch; // scratch counter
|
||||
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
uint16_t ymm_used; // mask of the ymm regs used in this opcode
|
||||
uint64_t ymm_regs; // 4bits (0-15) position of 16 ymmXX regs removed
|
||||
uint16_t ymm_write; // 1bits of ymmXX removed write
|
||||
uint16_t ymm_removed; // 1bits if ymmXX was removed
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if deferred flags is already set to df_none
|
||||
uint8_t dfnone; // if deferred flags is already set to df_none
|
||||
uint8_t dfnone_here;// defered flags is cleared in this opcode
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm64_s {
|
||||
@@ -78,7 +84,13 @@ typedef struct instruction_arm64_s {
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
uint16_t retn;
|
||||
uint16_t purge_ymm; // need to purge some ymm
|
||||
uint16_t ymm0_in; // bitmap of ymm to zero at purge
|
||||
uint16_t ymm0_add; // the ymm0 added by the opcode
|
||||
uint16_t ymm0_sub; // the ymm0 removed by the opcode
|
||||
uint16_t ymm0_out; // the ymmm0 at th end of the opcode
|
||||
uint16_t ymm0_pass2, ymm0_pass3;
|
||||
uint8_t barrier_maybe;
|
||||
uint8_t will_write;
|
||||
uint8_t last_write;
|
||||
@@ -118,6 +130,7 @@ typedef struct dynarec_arm_s {
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint16_t ymm_zero; // bitmap of ymm to zero at purge
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uint8_t smread;
|
||||
uint8_t doublepush;
|
||||
@@ -130,6 +143,7 @@ void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
void add_jump(dynarec_arm_t *dyn, int ninst);
|
||||
int get_first_jump(dynarec_arm_t *dyn, int next);
|
||||
int get_first_jump_addr(dynarec_arm_t *dyn, uintptr_t next);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
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;
|
||||
int32_t h = *p;
|
||||
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
@@ -48,7 +48,7 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
int db_size = db->x64_size;
|
||||
uintptr_t db_size = db->x64_size;
|
||||
if(db_size && my_context) {
|
||||
uint32_t n = rb_get(my_context->db_sizes, db_size);
|
||||
if(n>1)
|
||||
@@ -94,7 +94,7 @@ void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
int db_size = db->x64_size;
|
||||
uintptr_t db_size = db->x64_size;
|
||||
if(db_size && my_context) {
|
||||
uint32_t n = rb_get(my_context->db_sizes, db_size);
|
||||
if(n>1)
|
||||
|
||||
+112
-10
@@ -101,6 +101,11 @@ void add_jump(dynarec_native_t *dyn, int ninst) {
|
||||
dyn->jmps[dyn->jmp_sz++] = ninst;
|
||||
}
|
||||
int get_first_jump(dynarec_native_t *dyn, int next) {
|
||||
if(next<0 || next>dyn->size)
|
||||
return -2;
|
||||
return get_first_jump_addr(dyn, dyn->insts[next].x64.addr);
|
||||
}
|
||||
int get_first_jump_addr(dynarec_native_t *dyn, uintptr_t next) {
|
||||
for(int i=0; i<dyn->jmp_sz; ++i)
|
||||
if(dyn->insts[dyn->jmps[i]].x64.jmp == next)
|
||||
return dyn->jmps[i];
|
||||
@@ -357,7 +362,7 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
}
|
||||
}
|
||||
|
||||
// updateNeed goes backward, from last instruction to top
|
||||
// updateNeed for the current block. recursive function that goes backward
|
||||
static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
@@ -400,6 +405,83 @@ static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
return ninst;
|
||||
}
|
||||
|
||||
static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached) {
|
||||
int can_incr = ninst == max_ninst_reached; // Are we the top-level call?
|
||||
int ok = 1;
|
||||
while ((can_incr || ok) && ninst<dyn->size) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
|
||||
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
|
||||
|
||||
if (ninst && dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
|
||||
uint16_t ymm0_union = 0, ymm0_inter = (uint16_t)-1; // The union of the empty set is empty, the intersection is the universe
|
||||
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
|
||||
int pred = dyn->insts[ninst].pred[i];
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
|
||||
if (pred >= max_ninst_reached) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, " (skipped)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
int pred_out = dyn->insts[pred].x64.has_callret ? 0 : dyn->insts[pred].ymm0_out;
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
|
||||
ymm0_union |= pred_out;
|
||||
ymm0_inter &= pred_out;
|
||||
}
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
|
||||
// Notice the default values yield something coherent here (if all pred are after ninst)
|
||||
new_purge_ymm = ymm0_union & ~ymm0_inter;
|
||||
new_ymm0_in = ymm0_inter;
|
||||
new_ymm0_out = (ymm0_inter | dyn->insts[ninst].ymm0_add) & ~dyn->insts[ninst].ymm0_sub;
|
||||
|
||||
if ((dyn->insts[ninst].purge_ymm != new_purge_ymm) || (dyn->insts[ninst].ymm0_in != new_ymm0_in) || (dyn->insts[ninst].ymm0_out != new_ymm0_out)) {
|
||||
// Need to update self and next(s)
|
||||
dyn->insts[ninst].purge_ymm = new_purge_ymm;
|
||||
dyn->insts[ninst].ymm0_in = new_ymm0_in;
|
||||
dyn->insts[ninst].ymm0_out = new_ymm0_out;
|
||||
|
||||
if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We need to stop here if the opcode has no "real" next or if we reached the ninst of the toplevel
|
||||
ok = (max_ninst_reached - 1 != ninst) && dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].x64.has_callret;
|
||||
}
|
||||
|
||||
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
|
||||
if((jmp!=-1) && (jmp < max_ninst_reached)) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
// The jump goes before the last instruction reached, update the destination
|
||||
// If this is the top level call, this means the jump goes backward (jmp != ninst)
|
||||
// Otherwise, since we don't update all instructions, we may miss the update (don't use jmp < ninst)
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
|
||||
// Also update jumps to before (they are skipped otherwise)
|
||||
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
|
||||
if((jmp!=-1) && (jmp < max_ninst_reached)) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
} else if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
ok = 0;
|
||||
}
|
||||
++ninst;
|
||||
}
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
static int static_jmps[MAX_INSTS+2];
|
||||
static uintptr_t static_next[MAX_INSTS+2];
|
||||
@@ -553,17 +635,15 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1) {
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
if(!helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no need for next and jmps anymore
|
||||
// no need for next anymore
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// fill predecessors with the jump address
|
||||
int alloc_size = sizePredecessors(&helper);
|
||||
helper.predecessor = (int*)alloca(alloc_size*sizeof(int));
|
||||
@@ -576,10 +656,25 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz)
|
||||
fpu_reset_ninst(&helper, ii++);
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz) {
|
||||
fpu_reset_ninst(&helper, ii);
|
||||
helper.insts[ii].ymm0_in = helper.insts[ii].ymm0_sub = helper.insts[ii].ymm0_add = helper.insts[ii].ymm0_out = helper.insts[ii].purge_ymm = 0;
|
||||
++ii;
|
||||
}
|
||||
i = ii;
|
||||
}
|
||||
// remove trailling dead code
|
||||
while(helper.size && !helper.insts[helper.size-1].x64.alive) {
|
||||
helper.isize-=helper.insts[helper.size-1].x64.size;
|
||||
--helper.size;
|
||||
}
|
||||
if(!helper.size) {
|
||||
// NULL block after removing dead code, how is that possible?
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
updateYmm0s(&helper, 0, 0);
|
||||
|
||||
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
@@ -632,6 +727,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
int oldtable64size = helper.table64size;
|
||||
size_t oldnativesize = helper.native_size;
|
||||
size_t oldinstsize = helper.insts_size;
|
||||
int oldsize= helper.size;
|
||||
helper.native_size = 0;
|
||||
helper.table64size = 0; // reset table64 (but not the cap)
|
||||
helper.insts_size = 0; // reset
|
||||
@@ -641,6 +737,9 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// no need for jmps anymore
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
helper.table64 = NULL;
|
||||
@@ -667,14 +766,17 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
return NULL;
|
||||
}
|
||||
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8);
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu, %d) & pass3 (%zu, %d)!\n", oldnativesize+oldtable64size*8, oldsize, helper.native_size+helper.table64size*8, helper.size);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
printf_log(LOG_NONE, "%s%p:", (helper.insts[i].size2!=helper.insts[i].size)?"=====> ":"", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
printf_log(LOG_NONE, "\t%d -> %d", helper.insts[i].size2, helper.insts[i].size);
|
||||
if(helper.insts[i].ymm0_pass2 || helper.insts[i].ymm0_pass3)
|
||||
printf_log(LOG_NONE, "\t %04x -> %04x", helper.insts[i].ymm0_pass2, helper.insts[i].ymm0_pass3);
|
||||
printf_log(LOG_NONE, "\n");
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
|
||||
@@ -204,7 +204,18 @@ void native_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
LD2D(p, &emu->x87[7-i].d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void native_fsave16(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 1);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 14;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &emu->x87[7-i].d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +226,19 @@ void native_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
D2LD(&emu->x87[7-i].d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
void native_frstor16(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 1);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 14;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&emu->x87[7-i].d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
@@ -245,23 +268,23 @@ void native_fprem1(x64emu_t* emu)
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
int retval = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void native_aesimc(x64emu_t* emu, int xmm)
|
||||
@@ -275,6 +298,17 @@ void native_aesimc(x64emu_t* emu, int xmm)
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void native_aesimc_y(x64emu_t* emu, int ymm)
|
||||
{
|
||||
sse_regs_t eay1 = emu->ymm[ymm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->ymm[ymm].ub[0+j*4] = ff_mult(0x0E, eay1.ub[0+j*4]) ^ ff_mult(0x0B, eay1.ub[1+j*4]) ^ ff_mult(0x0D, eay1.ub[2+j*4]) ^ ff_mult(0x09, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[1+j*4] = ff_mult(0x09, eay1.ub[0+j*4]) ^ ff_mult(0x0E, eay1.ub[1+j*4]) ^ ff_mult(0x0B, eay1.ub[2+j*4]) ^ ff_mult(0x0D, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[2+j*4] = ff_mult(0x0D, eay1.ub[0+j*4]) ^ ff_mult(0x09, eay1.ub[1+j*4]) ^ ff_mult(0x0E, eay1.ub[2+j*4]) ^ ff_mult(0x0B, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[3+j*4] = ff_mult(0x0B, eay1.ub[0+j*4]) ^ ff_mult(0x0D, eay1.ub[1+j*4]) ^ ff_mult(0x09, eay1.ub[2+j*4]) ^ ff_mult(0x0E, eay1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void native_aesmc(x64emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
@@ -286,29 +320,40 @@ void native_aesmc(x64emu_t* emu, int xmm)
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void native_aesmc_y(x64emu_t* emu, int ymm)
|
||||
{
|
||||
sse_regs_t eay1 = emu->ymm[ymm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->ymm[ymm].ub[0+j*4] = ff_mult(0x02, eay1.ub[0+j*4]) ^ ff_mult(0x03, eay1.ub[1+j*4]) ^ eay1.ub[2+j*4] ^ eay1.ub[3+j*4] ;
|
||||
emu->ymm[ymm].ub[1+j*4] = eay1.ub[0+j*4] ^ ff_mult(0x02, eay1.ub[1+j*4]) ^ ff_mult(0x03, eay1.ub[2+j*4]) ^ eay1.ub[3+j*4] ;
|
||||
emu->ymm[ymm].ub[2+j*4] = eay1.ub[0+j*4] ^ eay1.ub[1+j*4] ^ ff_mult(0x02, eay1.ub[2+j*4]) ^ ff_mult(0x03, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[3+j*4] = ff_mult(0x03, eay1.ub[0+j*4]) ^ eay1.ub[1+j*4] ^ eay1.ub[2+j*4] ^ ff_mult(0x02, eay1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
static const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
static const uint8_t invsubbytes[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
};
|
||||
void native_aesdlast(x64emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
const uint8_t invsubbytes[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
@@ -317,6 +362,17 @@ void native_aesdlast(x64emu_t* emu, int xmm)
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
|
||||
|
||||
}
|
||||
void native_aesdlast_y(x64emu_t* emu, int ymm)
|
||||
{
|
||||
|
||||
sse_regs_t eay1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eay1.ub[i] = emu->ymm[ymm].ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->ymm[ymm].ub[i] = invsubbytes[eay1.ub[i]];
|
||||
|
||||
}
|
||||
static const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
static const uint8_t subbytes[256] = {
|
||||
@@ -348,16 +404,34 @@ void native_aeselast(x64emu_t* emu, int xmm)
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
|
||||
}
|
||||
void native_aeselast_y(x64emu_t* emu, int ymm)
|
||||
{
|
||||
sse_regs_t eay1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eay1.ub[i] = emu->ymm[ymm].ub[shiftrows[i]];
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->ymm[ymm].ub[i] = subbytes[eay1.ub[i]];
|
||||
}
|
||||
void native_aesd(x64emu_t* emu, int xmm)
|
||||
{
|
||||
native_aesdlast(emu, xmm);
|
||||
native_aesimc(emu, xmm);
|
||||
}
|
||||
void native_aesd_y(x64emu_t* emu, int ymm)
|
||||
{
|
||||
native_aesdlast_y(emu, ymm);
|
||||
native_aesimc_y(emu, ymm);
|
||||
}
|
||||
void native_aese(x64emu_t* emu, int xmm)
|
||||
{
|
||||
native_aeselast(emu, xmm);
|
||||
native_aesmc(emu, xmm);
|
||||
}
|
||||
void native_aese_y(x64emu_t* emu, int ymm)
|
||||
{
|
||||
native_aeselast_y(emu, ymm);
|
||||
native_aesmc_y(emu, ymm);
|
||||
}
|
||||
void native_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
|
||||
{
|
||||
sse_regs_t *EX = p?((sse_regs_t*)p):&emu->xmm[ex];
|
||||
@@ -393,6 +467,40 @@ void native_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
|
||||
GX->q[0] = result&0xffffffffffffffffLL;
|
||||
GX->q[1] = (result>>64)&0xffffffffffffffffLL;
|
||||
}
|
||||
void native_pclmul_x(x64emu_t* emu, int gx, int vx, void* p, uint32_t u8)
|
||||
{
|
||||
|
||||
sse_regs_t *EX = ((uintptr_t)p<16)?((sse_regs_t*)p):&emu->xmm[(uintptr_t)p];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
sse_regs_t *VX = &emu->xmm[vx];
|
||||
int g = (u8&1)?1:0;
|
||||
int e = (u8&0b10000)?1:0;
|
||||
__int128 result = 0;
|
||||
__int128 op2 = EX->q[e];
|
||||
for (int i=0; i<64; ++i)
|
||||
if(VX->q[g]&(1LL<<i))
|
||||
result ^= (op2<<i);
|
||||
|
||||
GX->q[0] = result&0xffffffffffffffffLL;
|
||||
GX->q[1] = (result>>64)&0xffffffffffffffffLL;
|
||||
}
|
||||
void native_pclmul_y(x64emu_t* emu, int gy, int vy, void* p, uint32_t u8)
|
||||
{
|
||||
|
||||
sse_regs_t *EY = ((uintptr_t)p<16)?((sse_regs_t*)p):&emu->ymm[(uintptr_t)p];
|
||||
sse_regs_t *GY = &emu->ymm[gy];
|
||||
sse_regs_t *VY = &emu->ymm[vy];
|
||||
int g = (u8&1)?1:0;
|
||||
int e = (u8&0b10000)?1:0;
|
||||
__int128 result = 0;
|
||||
__int128 op2 = EY->q[e];
|
||||
for (int i=0; i<64; ++i)
|
||||
if(VY->q[g]&(1LL<<i))
|
||||
result ^= (op2<<i);
|
||||
|
||||
GY->q[0] = result&0xffffffffffffffffLL;
|
||||
GY->q[1] = (result>>64)&0xffffffffffffffffLL;
|
||||
}
|
||||
|
||||
void native_clflush(x64emu_t* emu, void* p)
|
||||
{
|
||||
@@ -484,7 +592,7 @@ uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
}
|
||||
#undef F8
|
||||
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, uint16_t* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
|
||||
@@ -510,3 +618,31 @@ int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress,
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
|
||||
// AVX
|
||||
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->ymm_zero |= (1<<reg);
|
||||
}
|
||||
|
||||
int is_avx_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
return (dyn->ymm_zero>>reg)&1;
|
||||
}
|
||||
int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
if((dyn->ymm_zero>>reg)&1) {
|
||||
dyn->ymm_zero &= ~(1<<reg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
dyn->ymm_zero = 0;
|
||||
}
|
||||
|
||||
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->ymm_zero &= ~(1<<reg);
|
||||
}
|
||||
@@ -30,16 +30,25 @@ void native_fistp64(x64emu_t* emu, int64_t* ed);
|
||||
void native_fistt64(x64emu_t* emu, int64_t* ed);
|
||||
void native_fld(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fsave(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fsave16(x64emu_t* emu, uint8_t* ed);
|
||||
void native_frstor(x64emu_t* emu, uint8_t* ed);
|
||||
void native_frstor16(x64emu_t* emu, uint8_t* ed);
|
||||
void native_fprem1(x64emu_t* emu);
|
||||
|
||||
void native_aesd(x64emu_t* emu, int xmm);
|
||||
void native_aesd_y(x64emu_t* emu, int ymm);
|
||||
void native_aese(x64emu_t* emu, int xmm);
|
||||
void native_aese_y(x64emu_t* emu, int ymm);
|
||||
void native_aesdlast(x64emu_t* emu, int xmm);
|
||||
void native_aesdlast_y(x64emu_t* emu, int ymm);
|
||||
void native_aeselast(x64emu_t* emu, int xmm);
|
||||
void native_aeselast_y(x64emu_t* emu, int ymm);
|
||||
void native_aesimc(x64emu_t* emu, int xmm);
|
||||
void native_aesimc_y(x64emu_t* emu, int ymm);
|
||||
void native_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
void native_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8);
|
||||
void native_pclmul_x(x64emu_t* emu, int gx, int vx, void* p, uint32_t u8);
|
||||
void native_pclmul_y(x64emu_t* emu, int gy, int vy, void* p, uint32_t u8);
|
||||
|
||||
void native_clflush(x64emu_t* emu, void* p);
|
||||
|
||||
@@ -63,7 +72,14 @@ uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, uint16_t* retn);
|
||||
|
||||
// AVX utilities
|
||||
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg);
|
||||
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst);
|
||||
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
|
||||
ADDITIONNAL_DEFINITION()
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
dyn->ymm_zero = 0;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
#endif
|
||||
@@ -107,7 +108,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
|
||||
dyn->last_ip = 0; // reset IP if some jump are coming here
|
||||
#endif
|
||||
dyn->f.dfnone_here = 0;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DUMP, "New Instruction x64:%p, native:%p\n", (void*)addr, (void*)dyn->block);
|
||||
#if STEP == 0
|
||||
if(ninst && dyn->insts[ninst-1].x64.barrier_next) {
|
||||
BARRIER(dyn->insts[ninst-1].x64.barrier_next);
|
||||
@@ -117,11 +120,10 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
GOTEST(x1, x2);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
fpu_reset_scratch(dyn);
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
}
|
||||
if(box64_dynarec_test) {
|
||||
if(box64_dynarec_test && (!box64_dynarec_test_end || (ip>=box64_dynarec_test_start && ip<box64_dynarec_test_end) )) {
|
||||
MESSAGE(LOG_DUMP, "TEST STEP ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE(x64test_step, 1, x5);
|
||||
@@ -166,11 +168,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
if(dyn->abort)
|
||||
return ip;
|
||||
INST_EPILOG;
|
||||
|
||||
fpu_reset_scratch(dyn);
|
||||
int next = ninst+1;
|
||||
#if STEP > 0
|
||||
if(!dyn->insts[ninst].x64.has_next && dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts!=-1)
|
||||
next = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
@@ -189,26 +189,30 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
if(ii<dyn->size && !dyn->insts[ii].x64.alive) {
|
||||
while(ii<dyn->size && !dyn->insts[ii].x64.alive) {
|
||||
if((ninst+1)<dyn->size && !dyn->insts[ninst+1].x64.alive) {
|
||||
// reset fpu value...
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
while((ninst+1)<dyn->size && !dyn->insts[ninst+1].x64.alive) {
|
||||
// may need to skip opcodes to advance
|
||||
++ninst;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DEBUG, "Skipping unused opcode\n");
|
||||
INST_NAME("Skipped opcode");
|
||||
addr += dyn->insts[ninst].x64.size;
|
||||
INST_EPILOG;
|
||||
addr += dyn->insts[ii].x64.size;
|
||||
++ii;
|
||||
}
|
||||
}
|
||||
if((dyn->insts[ii].x64.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
if((dyn->insts[ninst+1].x64.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
reset_n = -2; // hack to say Barrier!
|
||||
else {
|
||||
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are available
|
||||
reset_n = getNominalPred(dyn, ninst+1); // may get -1 if no predecessor are available
|
||||
if(reset_n==-1) {
|
||||
reset_n = -2;
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
if(!dyn->insts[ninst].x64.has_callret) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,7 +226,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog && ok>=0) {
|
||||
// we made it!
|
||||
reset_n = get_first_jump(dyn, addr);
|
||||
reset_n = get_first_jump_addr(dyn, addr);
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p (ninst %d - %d)\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to, reset_n, ninst);
|
||||
if(dyn->insts[dyn->forward_ninst].x64.has_callret && !dyn->insts[dyn->forward_ninst].x64.has_next)
|
||||
dyn->insts[dyn->forward_ninst].x64.has_next = 1; // this block actually continue
|
||||
@@ -260,7 +264,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
}
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst+1, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
|
||||
} else if(next && (next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
} else if(next && (int)(next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
if(next<dyn->forward_to)
|
||||
@@ -304,6 +308,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
if((ok>0) && dyn->insts[ninst].x64.has_callret)
|
||||
reset_n = -2;
|
||||
if((ok>0) && reset_n==-1 && dyn->insts[ninst+1].purge_ymm)
|
||||
PURGE_YMM();
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
|
||||
@@ -167,6 +167,35 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_adc32(dyn, ninst, rex, gd, ed, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x18:
|
||||
INST_NAME("SBB Eb, Gb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EBBACK();
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
@@ -177,6 +206,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("SBB AL, Ib");
|
||||
READFLAGS(X_CF);
|
||||
@@ -321,6 +359,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETED(0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x34:
|
||||
INST_NAME("XOR AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u8 = F8;
|
||||
ANDI(x1, xRAX, 0xff);
|
||||
emit_xor8c(dyn, ninst, x1, u8, x3, x4);
|
||||
BSTRINS_D(xRAX, x1, 7, 0);
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -442,6 +488,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x66:
|
||||
addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x67:
|
||||
if (rex.is32bits) {
|
||||
DEFAULT;
|
||||
} else
|
||||
addr = dynarec64_67(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x68:
|
||||
INST_NAME("PUSH Id");
|
||||
i64 = F32S;
|
||||
@@ -477,7 +529,8 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
MUL_D(gd, ed, x4);
|
||||
SLLI_W(x3, ed, 0);
|
||||
MUL_D(gd, x3, x4);
|
||||
UFLAG_RES(gd);
|
||||
SRLI_D(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
@@ -516,7 +569,8 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
MUL_D(gd, ed, x4);
|
||||
SLLI_W(x3, ed, 0);
|
||||
MUL_D(gd, x3, x4);
|
||||
UFLAG_RES(gd);
|
||||
SRLI_D(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
@@ -587,6 +641,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK();
|
||||
break;
|
||||
case 3: // SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK();
|
||||
break;
|
||||
case 4: // AND
|
||||
INST_NAME("AND Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -772,7 +835,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
break;
|
||||
case 0x86:
|
||||
INST_NAME("(LOCK)XCHG Eb, Gb");
|
||||
INST_NAME("(LOCK) XCHG Eb, Gb");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGB(x1);
|
||||
@@ -786,9 +849,39 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
AMSWAP_DB_B(x1, gd, ed);
|
||||
else {
|
||||
SMDMB();
|
||||
LD_BU(x1, ed, 0);
|
||||
ST_B(gd, ed, 0);
|
||||
SMDMB();
|
||||
|
||||
// calculate shift amount
|
||||
ANDI(x1, ed, 0x3);
|
||||
SLLI_D(x1, x1, 3);
|
||||
|
||||
// align address to 4-bytes to use ll.w/sc.w
|
||||
ADDI_D(x4, xZR, 0xffc);
|
||||
AND(x6, ed, x4);
|
||||
|
||||
// load aligned data
|
||||
LD_WU(x5, x6, 0);
|
||||
|
||||
// insert gd byte into the aligned data
|
||||
ADDI_D(x4, xZR, 0xff);
|
||||
SLL_D(x4, x4, x1);
|
||||
NOR(x4, x4, xZR);
|
||||
AND(x4, x5, x4);
|
||||
SLL_D(x5, gd, x1);
|
||||
OR(x4, x4, x5);
|
||||
|
||||
// do aligned ll/sc sequence
|
||||
MARKLOCK;
|
||||
LL_W(x1, x6, 0);
|
||||
MV(x5, x4);
|
||||
SC_W(x5, x6, 0);
|
||||
BEQZ_MARKLOCK(x5);
|
||||
|
||||
// calculate shift amount again
|
||||
ANDI(x4, ed, 0x3);
|
||||
SLLI_D(x4, x4, 3);
|
||||
|
||||
// extract loaded byte
|
||||
SRL_D(x1, x1, x4);
|
||||
}
|
||||
BSTRINS_D(gb1, x1, gb2 + 7, gb2);
|
||||
}
|
||||
@@ -974,6 +1067,37 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LD_BU(x2, x1, 0);
|
||||
BSTRINS_D(xRAX, x2, 7, 0);
|
||||
break;
|
||||
case 0xA4:
|
||||
if (rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, 1);
|
||||
ADDI_D(xRDI, xRDI, 1);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, -1);
|
||||
ADDI_D(xRDI, xRDI, -1);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
GETDIR(x3, x1, 1);
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
ADD_D(xRSI, xRSI, x3);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA5:
|
||||
if (rep) {
|
||||
INST_NAME("REP MOVSD");
|
||||
@@ -1293,6 +1417,26 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
// flags are not affected if count is 0, we make it a nop if possible.
|
||||
if (u8) {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET_PENDING);
|
||||
GETED(1);
|
||||
F8;
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
if (MODREG && !rex.w) {
|
||||
GETED(1);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
FAKEED;
|
||||
}
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 0x3f : 0x1f);
|
||||
@@ -1416,7 +1560,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MOV32w(x3, u8);
|
||||
BSTRINS_D(eb1, x3, eb2 * 8 + 7, eb2 * 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, &lock, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, &lock, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
ADDI_D(x3, xZR, u8);
|
||||
@@ -1528,6 +1672,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xD1:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET_PENDING);
|
||||
GETED(0);
|
||||
emit_rol32c(dyn, ninst, rex, ed, 1, x3, x4);
|
||||
WBACK;
|
||||
if (!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, 1");
|
||||
@@ -2022,17 +2174,57 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("CLD");
|
||||
BSTRINS_D(xFlags, xZR, F_DF, F_DF);
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("STD");
|
||||
ORI(xFlags, xFlags, 1 << F_DF);
|
||||
break;
|
||||
case 0xFE:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("INC Eb");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1, 0);
|
||||
emit_inc8(dyn, ninst, ed, x2, x4, x5);
|
||||
EBBACK();
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Eb");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1, 0);
|
||||
emit_dec8(dyn, ninst, ed, x2, x4, x5);
|
||||
EBBACK();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
GETED(0);
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: // DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
GETED(0);
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF((box64_dynarec_safeflags > 1) || ((ninst && dyn->insts[ninst - 1].x64.set_flags) || ((ninst > 1) && dyn->insts[ninst - 2].x64.set_flags)), 1)
|
||||
{
|
||||
PASS2IF ((box64_dynarec_safeflags > 1) || ((ninst && dyn->insts[ninst - 1].x64.set_flags) || ((ninst > 1) && dyn->insts[ninst - 2].x64.set_flags)), 1) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDz(0);
|
||||
|
||||
@@ -66,17 +66,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(MODREG) {
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
nextop = F8;
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
INST_NAME("XGETBV");
|
||||
BEQZ_MARK(xRCX);
|
||||
EMIT(0); // Is there any assigned illegal instruction?
|
||||
MARK;
|
||||
MOV32w(xRAX, 0b111);
|
||||
MOV32w(xRDX, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -104,6 +99,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LOAD_XEMU_REM();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -264,6 +270,20 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("MOVNTPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
@@ -305,6 +325,74 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
break;
|
||||
case 0x38:
|
||||
// SSE3
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC8 ... 0xCD:
|
||||
u8 = nextop;
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
INST_NAME("SHA1NEXTE Gx, Ex");
|
||||
break;
|
||||
case 0xC9:
|
||||
INST_NAME("SHA1MSG1 Gx, Ex");
|
||||
break;
|
||||
case 0xCA:
|
||||
INST_NAME("SHA1MSG2 Gx, Ex");
|
||||
break;
|
||||
case 0xCB:
|
||||
INST_NAME("SHA256RNDS2 Gx, Ex");
|
||||
break;
|
||||
case 0xCC:
|
||||
INST_NAME("SHA256MSG1 Gx, Ex");
|
||||
break;
|
||||
case 0xCD:
|
||||
INST_NAME("SHA256MSG2 Gx, Ex");
|
||||
break;
|
||||
}
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x2) {
|
||||
MV(x2, ed);
|
||||
}
|
||||
}
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
sse_reflect_reg(dyn, ninst, 0);
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
CALL(sha1nexte, -1);
|
||||
break;
|
||||
case 0xC9:
|
||||
CALL(sha1msg1, -1);
|
||||
break;
|
||||
case 0xCA:
|
||||
CALL(sha1msg2, -1);
|
||||
break;
|
||||
case 0xCB:
|
||||
CALL(sha256rnds2, -1);
|
||||
break;
|
||||
case 0xCC:
|
||||
CALL(sha256msg1, -1);
|
||||
break;
|
||||
case 0xCD:
|
||||
CALL(sha256msg2, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
@@ -335,6 +423,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
#undef GO
|
||||
|
||||
case 0x50:
|
||||
INST_NAME("MOVMSPKPS Gd, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VMSKLTZ_W(q1, q0);
|
||||
MOVFR2GR_S(gd, q1);
|
||||
BSTRPICK_D(gd, gd, 31, 0);
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -350,6 +448,15 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGX_empty(q1);
|
||||
VFRSQRT_S(q1, q0);
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
// TODO: use v1.1 vfrecipe when possible
|
||||
VFRECIP_S(q1, q0);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -406,6 +513,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGX(q1, 1);
|
||||
VFCVTL_D_S(q1, q0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTDQ2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
VFFINT_S_W(q1, q0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -413,6 +527,43 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGX(v0, 1);
|
||||
VFSUB_S(v0, v0, q0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
if (!box64_dynarec_fastnan && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// always copy from v1 if any oprand is NaN
|
||||
VFCMP_S(q0, v0, v1, cUN);
|
||||
VANDN_V(v0, q0, v0);
|
||||
VAND_V(q0, q0, v1);
|
||||
VOR_V(v0, v0, q0);
|
||||
}
|
||||
VFMIN_S(v0, v0, v1);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFDIV_S(v0, v0, q0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
if (!box64_dynarec_fastnan && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// always copy from v1 if any oprand is NaN
|
||||
VFCMP_S(q0, v0, v1, cUN);
|
||||
VANDN_V(v0, q0, v0);
|
||||
VAND_V(q0, q0, v1);
|
||||
VOR_V(v0, v0, q0);
|
||||
}
|
||||
VFMAX_S(v0, v0, v1);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
@@ -515,6 +666,79 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
break;
|
||||
case 0xA4:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if (MODREG)
|
||||
switch (nextop) {
|
||||
case 0xE8:
|
||||
INST_NAME("LFENCE");
|
||||
SMDMB();
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("MFENCE");
|
||||
SMDMB();
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("SFENCE");
|
||||
SMDMB();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
else
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("FXSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SKIPTEST(x1);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL(rex.w ? ((void*)fpu_fxsave64) : ((void*)fpu_fxsave32), -1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if (box64_sse_flushto0) {
|
||||
// TODO
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("STMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
LD_WU(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
ST_W(x4, wback, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -560,7 +784,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (la64_lbt) {
|
||||
X64_MUL_W(gd, ed);
|
||||
}
|
||||
MUL_D(gd, gd, ed);
|
||||
SLLI_W(gd, gd, 0);
|
||||
SLLI_W(x3, ed, 0);
|
||||
MUL_D(gd, gd, x3);
|
||||
SRLI_D(x3, gd, 32);
|
||||
SLLI_W(gd, gd, 0);
|
||||
IFX (X_PEND) {
|
||||
@@ -780,6 +1006,23 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
u8 = F8;
|
||||
switch (u8 & 7) {
|
||||
case 0: VFCMP_S(v0, v0, v1, cEQ); break; // Equal
|
||||
case 1: VFCMP_S(v0, v0, v1, cLT); break; // Less than
|
||||
case 2: VFCMP_S(v0, v0, v1, cLE); break; // Less or equal
|
||||
case 3: VFCMP_S(v0, v0, v1, cUN); break; // NaN
|
||||
case 4: VFCMP_S(v0, v0, v1, cUNE); break; // Not Equal or unordered
|
||||
case 5: VFCMP_S(v0, v1, v0, cULE); break; // Greater or equal or unordered
|
||||
case 6: VFCMP_S(v0, v1, v0, cULT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: VFCMP_S(v0, v0, v1, cOR); break; // not NaN
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "la64_emitter.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -60,6 +61,15 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETREX();
|
||||
|
||||
switch (opcode) {
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -69,6 +79,250 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEDO(x4, 0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x64:
|
||||
addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _GS, ok, need_epilog);
|
||||
break;
|
||||
case 0x66:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, seg, ok, need_epilog);
|
||||
break;
|
||||
case 0x80:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // ADD
|
||||
INST_NAME("ADD Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK();
|
||||
break;
|
||||
case 1: // OR
|
||||
INST_NAME("OR Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK();
|
||||
break;
|
||||
case 3: // SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK();
|
||||
break;
|
||||
case 4: // AND
|
||||
INST_NAME("AND Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK();
|
||||
break;
|
||||
case 5: // SUB
|
||||
INST_NAME("SUB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK();
|
||||
break;
|
||||
case 6: // XOR
|
||||
INST_NAME("XOR Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x4);
|
||||
EBBACK();
|
||||
break;
|
||||
case 7: // CMP
|
||||
INST_NAME("CMP Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
MOV32w(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, xMASK);
|
||||
IFXA (X_CF, !la64_lbt)
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("OR Ed, Id");
|
||||
} else {
|
||||
INST_NAME("OR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 2:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("ADC Ed, Id");
|
||||
} else {
|
||||
INST_NAME("ADC Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
IFXA (X_ALL, !la64_lbt)
|
||||
ST_D(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, xMASK);
|
||||
IFXA (X_ALL, !la64_lbt) {
|
||||
LD_D(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
}
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 3:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("SBB Ed, Id");
|
||||
} else {
|
||||
INST_NAME("SBB Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, xMASK);
|
||||
IFXA (X_CF, !la64_lbt)
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 4:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("AND Ed, Id");
|
||||
} else {
|
||||
INST_NAME("AND Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 5:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("SUB Ed, Id");
|
||||
} else {
|
||||
INST_NAME("SUB Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, xMASK);
|
||||
IFXA (X_CF, !la64_lbt)
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 6:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("XOR Ed, Id");
|
||||
} else {
|
||||
INST_NAME("XOR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 7:
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("CMP Ed, Id");
|
||||
} else {
|
||||
INST_NAME("CMP Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(TO_LA64((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD_D(x4, ed, x4);
|
||||
SDxw(gd, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
@@ -83,6 +337,55 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LDxw(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
if (MODREG) { // reg <= u8
|
||||
u8 = F8;
|
||||
if (!rex.rex) {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
} else {
|
||||
eb1 = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
BSTRINS_D(eb1, x3, eb2 * 8 + 7, eb2 * 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
ADDI_D(x3, xZR, u8);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
STX_B(x3, wback, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Seg:Ed, Id");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
if (MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 4);
|
||||
i64 = F32S;
|
||||
if (i64) {
|
||||
MOV64xw(x3, i64);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
ADD_D(x4, wback, x4);
|
||||
SDxw(ed, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,15 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x0F:
|
||||
switch (rep) {
|
||||
case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
@@ -211,6 +220,36 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
case 0x64:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _FS, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, _GS, ok, need_epilog);
|
||||
break;
|
||||
case 0x66:
|
||||
addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x69:
|
||||
case 0x6B:
|
||||
if (opcode == 0x69) {
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
} else {
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode == 0x69) ? 2 : 1);
|
||||
if (opcode == 0x69)
|
||||
i32 = F16S;
|
||||
else
|
||||
i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MUL_W(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd = x2;
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
@@ -279,6 +318,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: // XOR
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("XOR Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("XOR Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
else
|
||||
i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: // CMP
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("CMP Ew, Iw");
|
||||
@@ -324,6 +379,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
if (ed != gd) {
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LD_HU(x1, ed, fixedaddress);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
@@ -342,6 +413,77 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRINS_D(gd, x2, 15, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA4:
|
||||
if (rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, 1);
|
||||
ADDI_D(xRDI, xRDI, 1);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, -1);
|
||||
ADDI_D(xRDI, xRDI, -1);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
GETDIR(x3, x1, 1);
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
ADD_D(xRSI, xRSI, x3);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA5:
|
||||
if (rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LD_H(x1, xRSI, 0);
|
||||
ST_H(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, 2);
|
||||
ADDI_D(xRDI, xRDI, 2);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LD_H(x1, xRSI, 0);
|
||||
ST_H(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, -2);
|
||||
ADDI_D(xRDI, xRDI, -2);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
GETDIR(x3, x1, 2);
|
||||
LD_H(x1, xRSI, 0);
|
||||
ST_H(x1, xRDI, 0);
|
||||
ADD_D(xRSI, xRSI, x3);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0xAB:
|
||||
if (rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
@@ -436,6 +578,20 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ew, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF { MESSAGE(LOG_DUMP, "Need Optimization for flags\n"); }
|
||||
GETSEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF { MOV32w(x2, (u8 & 15)); }
|
||||
UFLAG_OP12(ed, x2)
|
||||
SRAI_D(ed, ed, u8 & 15);
|
||||
if (MODREG) BSTRPICK_D(ed, ed, 15, 0);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -524,9 +680,38 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,34 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MAYUSE(j64);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x11:
|
||||
INST_NAME("MOVUPD Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVLPD Gx, Eq");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FLD_D(v1, wback, fixedaddress);
|
||||
VEXTRINS_D(v0, v1, 0);
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -86,6 +114,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPD Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
@@ -248,6 +291,102 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x3A: // these are some more SSSE3+ opcodes
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0x0F:
|
||||
INST_NAME("PALIGNR Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8;
|
||||
if (u8 > 31) {
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else if (u8 > 15) {
|
||||
VBSRL_V(q0, q0, u8 - 16);
|
||||
} else if (!u8) {
|
||||
VOR_V(q0, q1, q1);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VBSLL_V(q0, q0, 16 - u8);
|
||||
VBSRL_V(d0, q1, u8);
|
||||
VOR_V(q0, q0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); // p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x3) {
|
||||
MV(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_pclmul, -1);
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("AESKEYGENASSIST Gx, Ex, Ib"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); // p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x3) {
|
||||
MV(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_aeskeygenassist, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
LD_HU(x4, ed, fixedaddress); \
|
||||
ed = x4; \
|
||||
} \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 4 + 4); \
|
||||
else \
|
||||
B##NO(x1, 4 + 4); \
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
#undef GO
|
||||
|
||||
case 0x54:
|
||||
INST_NAME("ANDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -283,17 +422,56 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VXOR_V(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("ADDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
// TODO: fastnan handling
|
||||
VFADD_D(q1, q1, q0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPD2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// TODO: is there any way to support !box64_dynarec_fastround?
|
||||
// TODO: !box64_dynarec_fastround
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCVT_S_D(q0, v1, v1);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VEXTRINS_D(v0, q0, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
VFTINT_W_S(v0, v1);
|
||||
if (!box64_dynarec_fastround) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v1, cEQ);
|
||||
VLDI(q1, 0b1001110000000); // broadcast 0x80000000
|
||||
VAND_V(v0, q0, v0);
|
||||
VANDN_V(d1, q0, q1);
|
||||
VOR_V(v0, v0, d1);
|
||||
VSUBI_WU(d1, q1, 1);
|
||||
VSEQ_W(q0, v0, d1);
|
||||
VSRLI_W(q0, q0, 31);
|
||||
VADD_W(v0, v0, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
// TODO: fastnan handling
|
||||
VFSUB_D(q1, q1, q0);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -700,14 +878,32 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
|
||||
VXOR_V(v1, v1, v1);
|
||||
VEXTRINS_D(v1, v0, 0);
|
||||
if (v0 == v1) {
|
||||
// clear upper bits
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(q0, q0, q0);
|
||||
VEXTRINS_D(q0, v0, 0);
|
||||
VOR_V(v1, q0, q0);
|
||||
} else {
|
||||
VXOR_V(v1, v1, v1);
|
||||
VEXTRINS_D(v1, v0, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xD7:
|
||||
INST_NAME("PMOVMSKB Gd, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VMSKLTZ_B(v0, q0);
|
||||
MOVFR2GR_D(x1, v0);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
break;
|
||||
case 0xDB:
|
||||
INST_NAME("PAND Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -715,6 +911,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q0, 0, 0);
|
||||
VAND_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("PADDUSB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VSADD_BU(q0, q0, q1);
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("PANDN Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -729,6 +932,25 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(v1, 0, 0);
|
||||
VMUH_HU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("PMULHW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VMUH_H(v0, v0, v1);
|
||||
break;
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTDQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("POR Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -750,6 +972,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VXOR_V(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("PMULUDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VMULWEV_D_WU(v0, v0, v1);
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("PSUBB Gx,Ex");
|
||||
nextop = F8;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "la64_emitter.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_6664(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
int64_t j64;
|
||||
int v0, v1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(j64);
|
||||
|
||||
GETREX();
|
||||
|
||||
switch (opcode) {
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
if (rex.w) {
|
||||
MV(gd, ed);
|
||||
} else {
|
||||
if (ed != gd) BSTRINS_D(gd, ed, 15, 0);
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (rex.w) {
|
||||
LDX_D(gd, ed, x4);
|
||||
} else {
|
||||
LDX_HU(x1, ed, x4);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "la64_emitter.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
if(rex.is32bits) {
|
||||
// should do a different file
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
nextop = F8;
|
||||
gd = ((nextop & 0x38) >> 3) + (rex.r << 3);
|
||||
if (rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = TO_LA64(gd);
|
||||
} else {
|
||||
gb2 = ((gd & 4) << 1);
|
||||
gb1 = TO_LA64(gd & 3);
|
||||
}
|
||||
if (gb2) {
|
||||
gd = x4;
|
||||
BSTRPICK_D(gd, gb1, gb2 + 7, gb2);
|
||||
} else {
|
||||
gd = gb1; // no need to extract
|
||||
}
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (rex.rex) {
|
||||
eb1 = TO_LA64(ed);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed & 4) >> 2); // L or H
|
||||
}
|
||||
BSTRINS_D(eb1, gd, eb2 * 8 + 7, eb2 * 8);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
ST_B(gb1, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ed, Gd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(TO_LA64((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SDxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETED32(0);
|
||||
if (rex.w) {
|
||||
if (ed == xRDX)
|
||||
gd = x3;
|
||||
else
|
||||
gd = xRDX;
|
||||
MULH_DU(gd, xRAX, ed);
|
||||
MUL_D(xRAX, xRAX, ed);
|
||||
if (gd != xRDX) MV(xRDX, gd);
|
||||
} else {
|
||||
MUL_D(xRDX, xRAX, ed); // 64 <- 32x32
|
||||
AND(xRAX, xRDX, xMASK);
|
||||
SRLI_W(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w ? d_mul64 : d_mul32);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -465,7 +465,7 @@ void emit_or16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_OR_W(s1, s2);
|
||||
X64_OR_H(s1, s2);
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
@@ -509,13 +509,15 @@ void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
|
||||
OR(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if(la64_lbt) return;
|
||||
if (la64_lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
// test sign bit before zeroup.
|
||||
@@ -524,6 +526,8 @@ void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
|
||||
@@ -144,7 +144,9 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
IFX(X_PEND | X_AF | X_CF | X_OF)
|
||||
{
|
||||
MOV64xw(s2, c);
|
||||
} else if (la64_lbt) MOV64xw(s2, c);
|
||||
} else if (la64_lbt) {
|
||||
MOV64xw(s2, c);
|
||||
}
|
||||
IFX(X_PEND)
|
||||
{
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -285,7 +287,7 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
|
||||
IFX(X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s2); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX(X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
@@ -844,9 +846,9 @@ void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SBC_W(s1, s2);
|
||||
else
|
||||
X64_SBC_D(s1, s2);
|
||||
else
|
||||
X64_SBC_W(s1, s2);
|
||||
}
|
||||
MVxw(s1, s3);
|
||||
|
||||
@@ -985,7 +987,7 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
CLEAR_FLAGS(s2);
|
||||
IFX (X_CF) {
|
||||
BEQZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
@@ -1037,17 +1039,18 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
if (rex.w)
|
||||
ADC_D(s3, s1, s2);
|
||||
else
|
||||
ADC_W(s3, s1, s2);
|
||||
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ADC_D(s1, s2);
|
||||
else
|
||||
X64_ADC_W(s1, s2);
|
||||
}
|
||||
if (rex.w)
|
||||
ADC_D(s1, s1, s2);
|
||||
else
|
||||
ADC_W(s1, s1, s2);
|
||||
|
||||
MV(s1, s3);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1059,6 +1062,8 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
AND(s5, xMASK, s1);
|
||||
AND(s4, xMASK, s2);
|
||||
ADD_D(s5, s5, s4); // lo
|
||||
ANDI(s3, xFlags, 1);
|
||||
ADD_D(s5, s5, s3); // add carry
|
||||
SRLI_D(s3, s1, 0x20);
|
||||
SRLI_D(s4, s2, 0x20);
|
||||
ADD_D(s4, s4, s3);
|
||||
@@ -1069,6 +1074,8 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
AND(s3, s1, xMASK);
|
||||
AND(s4, s2, xMASK);
|
||||
ADD_D(s5, s3, s4);
|
||||
ANDI(s3, xFlags, 1);
|
||||
ADD_D(s5, s5, s3); // add carry
|
||||
SRLI_D(s6, s5, 0x20);
|
||||
}
|
||||
}
|
||||
@@ -1122,3 +1129,479 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
|
||||
// emit INC8 instruction, from s1, store result in s1 using s2, s3 and s4 as scratch
|
||||
void emit_inc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
ORI(s3, s1, 1); // s3 = op1 | op2
|
||||
ANDI(s4, s1, 1); // s5 = op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_INC_B(s1);
|
||||
}
|
||||
|
||||
ADDI_W(s1, s1, 1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
ANDI(s1, s1, 0xff);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s2, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 6);
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
ANDI(s2, s1, 0x80);
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
|
||||
// emit INC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc16);
|
||||
} else IFX (X_ZF | X_OF | X_AF | X_SF | X_PF) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
ORI(s3, s1, 1); // s3 = op1 | op2
|
||||
ANDI(s4, s1, 1); // s4 = op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_INC_H(s1);
|
||||
}
|
||||
|
||||
ADDI_D(s1, s1, 1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 14);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit INC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_inc64 : d_inc32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
ORI(s3, s1, 1); // s3 = op1 | op2
|
||||
ANDI(s5, s1, 1); // s5 = op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
if (rex.w) {
|
||||
X64_INC_D(s1);
|
||||
} else {
|
||||
X64_INC_W(s1);
|
||||
}
|
||||
}
|
||||
|
||||
ADDIxw(s1, s1, 1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s2, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, rex.w ? 62 : 30);
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
|
||||
// emit DEC8 instruction, from s1, store result in s1 using s2, s3 and s4 as scratch
|
||||
void emit_dec8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
NOR(s4, xZR, s1); // s4 = ~op1
|
||||
ORI(s3, s4, 1); // s3 = ~op1 | op2
|
||||
ANDI(s4, s4, 1); // s4 = ~op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_DEC_B(s1);
|
||||
}
|
||||
|
||||
ADDI_W(s1, s1, -1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
ANDI(s1, s1, 0xff);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
AND(s3, s1, s3); // s3 = res & (~op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (res & (~op1 | op2)) | (~op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s2, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 6);
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
ANDI(s2, s1, 0x80);
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
|
||||
// emit DEC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
NOR(s5, xZR, s1);
|
||||
ORI(s3, s5, 1); // s3 = ~op1 | op2
|
||||
ANDI(s5, s5, 1); // s5 = ~op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_DEC_H(s1);
|
||||
}
|
||||
|
||||
ADDI_W(s1, s1, -1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
AND(s3, s1, s3); // s3 = res & (~op1 | op2)
|
||||
OR(s3, s3, s5); // cc = (res & (~op1 | op2)) | (~op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s2, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 14);
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
SLLI_W(s1, s1, 16);
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
SRLI_W(s1, s1, 16);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
|
||||
// emit DEC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_dec64 : d_dec32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
NOR(s5, xZR, s1);
|
||||
ORI(s3, s5, 1); // s3 = ~op1 | op2
|
||||
ANDI(s5, s5, 1); // s5 = ~op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
if (rex.w) {
|
||||
X64_DEC_D(s1);
|
||||
} else {
|
||||
X64_DEC_W(s1);
|
||||
}
|
||||
}
|
||||
|
||||
ADDIxw(s1, s1, -1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
AND(s3, s1, s3); // s3 = res & (~op1 | op2)
|
||||
OR(s3, s3, s5); // cc = (res & (~op1 | op2)) | (~op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s2, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, rex.w ? 62 : 30);
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit NEG16 instruction, from s1, store result in s1 using s2 and s3 as scratch
|
||||
void emit_neg16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_neg16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
MV(s3, s1); // s3 = op1
|
||||
}
|
||||
|
||||
NOR(s1, s1, xZR);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
BEQZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
OR(s3, s1, s3); // s3 = res | op1
|
||||
IFX (X_AF) {
|
||||
/* af = bc & 0x8 */
|
||||
ANDI(s2, s3, 8);
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
/* of = ((bc >> (width-2)) ^ (bc >> (width-1))) & 0x1; */
|
||||
SRLI_D(s2, s3, 14);
|
||||
SRLI_D(s3, s2, 1);
|
||||
XOR(s2, s2, s3);
|
||||
ANDI(s2, s2, 1);
|
||||
BEQZ(s2, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 15 - F_SF); // put sign bit in place
|
||||
ANDI(s3, s3, 1 << F_SF); // 1<<F_SF is sign bit, so just mask
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
}
|
||||
@@ -721,6 +721,9 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ANDI(s4, s2, 0x1f);
|
||||
}
|
||||
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
BEQ_NEXT(s4, xZR);
|
||||
|
||||
SLLxw(s3, s1, s4);
|
||||
NEG_D(s4, s4);
|
||||
ADDI_D(s4, s4, rex.w ? 64 : 32);
|
||||
@@ -748,3 +751,212 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX (X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_rol64 : d_rol32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_CF | X_OF) {
|
||||
if (rex.w)
|
||||
X64_ROTLI_D(s1, c);
|
||||
else
|
||||
X64_ROTLI_W(s1, c);
|
||||
}
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
IFX (X_CF | X_OF) {
|
||||
MOV64x(s3, (1UL << F_CF | 1UL << F_OF));
|
||||
ANDN(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_CF | X_OF) {
|
||||
ANDI(s4, s1, 1 << F_CF);
|
||||
IFX (X_CF) OR(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set to the exclusive OR of the CF bit (after the rotate) and the most-significant bit of the result.
|
||||
if (c == 1) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s4);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c &= (rex.w ? 0x3f : 0x1f);
|
||||
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
} else
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shld64 : d_shld32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (c > 0) {
|
||||
SRLI_D(s3, s1, (rex.w ? 64 : 32) - c);
|
||||
ANDI(s4, s3, 1); // F_CF
|
||||
OR(xFlags, xFlags, s4);
|
||||
}
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// Store sign for later use.
|
||||
if (c == 1) SRLIxw(s4, s1, rex.w ? 63 : 31);
|
||||
}
|
||||
|
||||
SLLIxw(s3, s1, c);
|
||||
SRLIxw(s1, s2, (rex.w ? 64 : 32) - c);
|
||||
OR(s1, s1, s3);
|
||||
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set if a sign change occurred
|
||||
if (c == 1) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s4);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
ORI(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c &= (rex.w ? 0x3f : 0x1f);
|
||||
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
} else
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shrd64 : d_shrd32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
} else {
|
||||
ANDI(s3, s1, 1); // LSB == F_CF
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// Store sign for later use.
|
||||
if (c == 1) SRLIxw(s4, s1, rex.w ? 63 : 31);
|
||||
}
|
||||
|
||||
SRLIxw(s3, s1, c);
|
||||
SLLIxw(s1, s2, (rex.w ? 64 : 32) - c);
|
||||
OR(s1, s1, s3);
|
||||
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set if a sign change occurred
|
||||
if (c == 1) {
|
||||
SRLI_D(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s4);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,9 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
ANDI(x1, wback, (1 << (rex.w + 2)) - 1);
|
||||
BNEZ_MARK3(x1);
|
||||
// Aligned
|
||||
MARKLOCK;
|
||||
MV(x4, gd);
|
||||
LLxw(x1, wback, 0);
|
||||
@@ -106,6 +109,20 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
// EAX == Ed
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
B_MARK_nocond;
|
||||
MARK3;
|
||||
// Unaligned
|
||||
ADDI_D(x5, xZR, -(1 << (rex.w + 2)));
|
||||
AND(x5, x5, wback);
|
||||
MARK2;
|
||||
LDxw(x1, wback, 0);
|
||||
LLxw(x6, x5, 0);
|
||||
SUBxw(x3, x1, xRAX);
|
||||
BNEZ_MARK(x3);
|
||||
// EAX == Ed
|
||||
SCxw(x6, x5, 0);
|
||||
BEQZ_MARK2(x6);
|
||||
SDxw(gd, wback, 0);
|
||||
MARK;
|
||||
UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6); }
|
||||
MVxw(xRAX, x1);
|
||||
@@ -149,6 +166,109 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
switch (rep) {
|
||||
case 0:
|
||||
if (rex.w) {
|
||||
INST_NAME("LOCK CMPXCHG16B Gq, Eq");
|
||||
} else {
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
}
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x2, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x2);
|
||||
}
|
||||
if (rex.w) {
|
||||
if (la64_scq) {
|
||||
MARKLOCK;
|
||||
LL_D(x2, wback, 0);
|
||||
LD_D(x3, wback, 8);
|
||||
// compare RDX:RAX with x3:x2
|
||||
BNE_MARK(x2, xRAX);
|
||||
BNE_MARK(x3, xRDX);
|
||||
MV(x5, xRBX);
|
||||
SC_Q(x5, xRCX, wback);
|
||||
BEQZ_MARKLOCK(x5);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
MV(xRAX, x2);
|
||||
MV(xRDX, x3);
|
||||
MARK3;
|
||||
SMDMB();
|
||||
} else {
|
||||
// if scq extension is not available, implement it with mutex
|
||||
LD_D(x6, xEmu, offsetof(x64emu_t, context));
|
||||
ADDI_D(x6, x6, offsetof(box64context_t, mutex_16b));
|
||||
ADDI_D(x4, xZR, 1);
|
||||
MARKLOCK;
|
||||
AMSWAP_DB_W(x5, x4, x6);
|
||||
// x4 == 1 if locked
|
||||
BNEZ_MARKLOCK(x5);
|
||||
|
||||
LD_D(x2, wback, 0);
|
||||
LD_D(x3, wback, 8);
|
||||
BNE_MARK(x2, xRAX);
|
||||
BNE_MARK(x3, xRDX);
|
||||
ST_D(xRBX, wback, 0);
|
||||
ST_D(xRCX, wback, 8);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
MV(xRAX, x2);
|
||||
MV(xRDX, x3);
|
||||
MARK3;
|
||||
|
||||
// unlock
|
||||
AMSWAP_DB_W(xZR, xZR, x6);
|
||||
}
|
||||
} else {
|
||||
SMDMB();
|
||||
AND(x3, xRAX, xMASK);
|
||||
SLLI_D(x2, xRDX, 32);
|
||||
OR(x3, x3, x2);
|
||||
AND(x4, xRBX, xMASK);
|
||||
SLLI_D(x2, xRCX, 32);
|
||||
OR(x4, x4, x2);
|
||||
MARKLOCK;
|
||||
LL_D(x2, wback, 0);
|
||||
BNE_MARK(x2, x3); // EDX_EAX != Ed
|
||||
MV(x5, x4);
|
||||
SC_D(x5, wback, 0);
|
||||
BEQZ_MARKLOCK(x5);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
SLLI_D(xRDX, x2, 32);
|
||||
AND(xRAX, x2, xMASK);
|
||||
MARK3;
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -217,6 +337,44 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 1: // OR
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("LOCK OR Ed, Id");
|
||||
} else {
|
||||
INST_NAME("LOCK OR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if (MODREG) {
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81) {
|
||||
i64 = F32S;
|
||||
} else {
|
||||
i64 = F8S;
|
||||
}
|
||||
if (i64 <= -2048 || i64 > 2048) {
|
||||
MOV64xw(x3, i64);
|
||||
}
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
if (i64 >= -2048 && i64 < 2048) {
|
||||
ORI(x4, x1, i64);
|
||||
} else {
|
||||
OR(x4, x1, x3);
|
||||
}
|
||||
if (!rex.w) ZEROUP(x4);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_or32c(dyn, ninst, rex, x1, i64, x3, x4);
|
||||
}
|
||||
break;
|
||||
case 5: // SUB
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("LOCK SUB Ed, Id");
|
||||
@@ -229,7 +387,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = xRAX + (nextop & 7) + (rex.b << 3);
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
@@ -279,6 +437,50 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("LOCK INC Ed");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
ADDIxw(x4, x1, 1);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4, x5, x6);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("LOCK DEC Ed");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
ADDIxw(x4, x1, -1);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4, x5, x6);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
FTINTRZ_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (!box64_dynarec_fastround) {
|
||||
@@ -138,6 +139,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
FTINT_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!box64_dynarec_fastround) {
|
||||
@@ -152,6 +154,22 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSD(d0, 0, 0);
|
||||
FSQRT_D(d1, d0);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_D(v1, xZR);
|
||||
FCMP_D(fcc0, d0, v1, cLT);
|
||||
BCEQZ(fcc0, 4 + 4);
|
||||
FNEG_D(d1, d1);
|
||||
}
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -212,6 +230,19 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, v1, v0, cLE);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
MARK;
|
||||
VEXTRINS_D(v0, v1, 0);
|
||||
MARK2;
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -242,6 +273,21 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VEXTRINS_D(v0, v1, 0);
|
||||
MARK2;
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 1);
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
if (v0 != v1) {
|
||||
VSHUF4I_H(v0, v1, u8);
|
||||
VEXTRINS_D(v0, v1, 0x11); // v0[127:64] = v1[127:64]
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VSHUF4I_H(q0, v1, u8);
|
||||
VEXTRINS_D(v0, q0, 0x0); // v0[63:0] = q0[63:0]
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
|
||||
@@ -114,6 +114,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
FTINTRZ_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (!box64_dynarec_fastround) {
|
||||
@@ -164,6 +165,27 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
FCVT_D_S(d1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
if (!box64_dynarec_fastround) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v1, cEQ);
|
||||
VLDI(q1, 0b1001110000000); // broadcast 0x80000000
|
||||
VAND_V(v0, q0, v0);
|
||||
VANDN_V(d1, q0, q1);
|
||||
VOR_V(v0, v0, d1);
|
||||
VSUBI_WU(d1, q1, 1);
|
||||
VSEQ_W(q0, v0, d1);
|
||||
VSRLI_W(q0, q0, 31);
|
||||
VADD_W(v0, v0, q0);
|
||||
}
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -226,11 +248,18 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 1);
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
VSHUF4I_H(v0, v1, u8);
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
break;
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
VXOR_V(v0, v0, v0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
@@ -239,7 +268,17 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
}
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
GETGX_empty(v0);
|
||||
if (v0 == v1) {
|
||||
// clear upper bits..
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VXOR_V(q1, q1, q1);
|
||||
VEXTRINS_D(q1, v1, 0); // q1[63:0] = v1[63:0]
|
||||
VOR_V(v0, q1, q1);
|
||||
} else {
|
||||
VXOR_V(v0, v0, v0);
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
@@ -254,6 +293,30 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ed = x4;
|
||||
}
|
||||
RESTORE_EFLAGS(x1);
|
||||
ANDI(xFlags, xFlags, ~((1 << F_ZF) | (1 << F_CF)));
|
||||
BNE_MARK(ed, xZR);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
MOV32w(gd, rex.w ? 64 : 32);
|
||||
SPILL_EFLAGS();
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
CTZxw(gd, ed);
|
||||
BNE(gd, xZR, 4 + 4);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
|
||||
@@ -324,6 +324,150 @@ static uintptr_t geted_32(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted32(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, uint8_t scratch, int64_t* fixaddress, rex_t rex, int* l, int i12, int delta)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(delta);
|
||||
|
||||
int lock = l ? ((l == LOCK_LOCK) ? 1 : 2) : 0;
|
||||
if (lock == 2)
|
||||
*l = 0;
|
||||
uint8_t ret = x2;
|
||||
*fixaddress = 0;
|
||||
if (hint > 0) ret = hint;
|
||||
int maxval = 2047;
|
||||
if (i12 > 1)
|
||||
maxval -= i12;
|
||||
MAYUSE(scratch);
|
||||
if (!(nextop & 0xC0)) {
|
||||
if ((nextop & 7) == 4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = ((sib >> 3) & 0x7) + (rex.x << 3);
|
||||
int sib_reg2 = (sib & 0x7) + (rex.b << 3);
|
||||
if ((sib & 0x7) == 5) {
|
||||
int64_t tmp = F32S;
|
||||
if (sib_reg != 4) {
|
||||
if (tmp && ((tmp < -2048) || (tmp > maxval) || !i12)) {
|
||||
MOV64x(scratch, tmp);
|
||||
if ((sib >> 6)) {
|
||||
SLLI_D(ret, TO_LA64(sib_reg), sib >> 6);
|
||||
ADD_W(ret, ret, scratch);
|
||||
} else
|
||||
ADD_W(ret, TO_LA64(sib_reg), scratch);
|
||||
} else {
|
||||
if (sib >> 6)
|
||||
SLLI_D(ret, TO_LA64(sib_reg), (sib >> 6));
|
||||
else
|
||||
ret = TO_LA64(sib_reg);
|
||||
*fixaddress = tmp;
|
||||
}
|
||||
} else {
|
||||
switch (lock) {
|
||||
case 1: addLockAddress(tmp); break;
|
||||
case 2:
|
||||
if (isLockAddress(tmp)) *l = 1;
|
||||
break;
|
||||
}
|
||||
MOV64x(ret, tmp);
|
||||
}
|
||||
} else {
|
||||
if (sib_reg != 4) {
|
||||
if ((sib >> 6)) {
|
||||
SLLI_D(ret, TO_LA64(sib_reg), (sib >> 6));
|
||||
ADD_W(ret, ret, TO_LA64(sib_reg2));
|
||||
} else
|
||||
ADD_W(ret, TO_LA64(sib_reg2), TO_LA64(sib_reg));
|
||||
} else {
|
||||
ret = TO_LA64(sib_reg2);
|
||||
}
|
||||
}
|
||||
} else if ((nextop & 7) == 5) {
|
||||
uint32_t tmp = F32;
|
||||
MOV32w(ret, tmp);
|
||||
GETIP(addr + delta);
|
||||
ADD_W(ret, ret, xRIP);
|
||||
switch (lock) {
|
||||
case 1: addLockAddress(addr + delta + tmp); break;
|
||||
case 2:
|
||||
if (isLockAddress(addr + delta + tmp)) *l = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
if (ret == hint) {
|
||||
AND(hint, ret, xMASK); // to clear upper part
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int64_t i64;
|
||||
uint8_t sib = 0;
|
||||
int sib_reg = 0;
|
||||
if ((nextop & 7) == 4) {
|
||||
sib = F8;
|
||||
sib_reg = ((sib >> 3) & 7) + (rex.x << 3);
|
||||
}
|
||||
int sib_reg2 = (sib & 0x07) + (rex.b << 3);
|
||||
if (nextop & 0x80)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64 == 0 || ((i64 >= -2048) && (i64 <= 2047) && i12)) {
|
||||
*fixaddress = i64;
|
||||
if ((nextop & 7) == 4) {
|
||||
if (sib_reg != 4) {
|
||||
if (sib >> 6) {
|
||||
SLLI_D(ret, TO_LA64(sib_reg), (sib >> 6));
|
||||
ADD_W(ret, ret, TO_LA64(sib_reg2));
|
||||
} else
|
||||
ADD_W(ret, TO_LA64(sib_reg2), TO_LA64(sib_reg));
|
||||
} else {
|
||||
ret = TO_LA64(sib_reg2);
|
||||
}
|
||||
} else {
|
||||
ret = TO_LA64((nextop & 0x07) + (rex.b << 3));
|
||||
}
|
||||
} else {
|
||||
if (i64 >= -2048 && i64 <= 2047) {
|
||||
if ((nextop & 7) == 4) {
|
||||
if (sib_reg != 4) {
|
||||
if (sib >> 6) {
|
||||
SLLI_D(scratch, TO_LA64(sib_reg), sib >> 6);
|
||||
ADD_W(scratch, scratch, TO_LA64(sib_reg2));
|
||||
} else
|
||||
ADD_W(scratch, TO_LA64(sib_reg2), TO_LA64(sib_reg));
|
||||
} else {
|
||||
scratch = TO_LA64(sib_reg2);
|
||||
}
|
||||
} else
|
||||
scratch = TO_LA64((nextop & 0x07) + (rex.b << 3));
|
||||
ADDI_W(ret, scratch, i64);
|
||||
} else {
|
||||
MOV32w(scratch, i64);
|
||||
if ((nextop & 7) == 4) {
|
||||
if (sib_reg != 4) {
|
||||
ADD_W(scratch, scratch, TO_LA64(sib_reg2));
|
||||
if (sib >> 6) {
|
||||
SLLI_D(ret, TO_LA64(sib_reg), (sib >> 6));
|
||||
ADD_W(ret, ret, scratch);
|
||||
} else
|
||||
ADD_W(ret, scratch, TO_LA64(sib_reg));
|
||||
} else {
|
||||
PASS3(int tmp = TO_LA64(sib_reg2));
|
||||
ADD_W(ret, tmp, scratch);
|
||||
}
|
||||
} else {
|
||||
PASS3(int tmp = TO_LA64((nextop & 0x07) + (rex.b << 3)));
|
||||
ADD_W(ret, tmp, scratch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*ed = ret;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
@@ -541,9 +685,7 @@ void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int sav
|
||||
LD_D(xRIP, xEmu, offsetof(x64emu_t, ip));
|
||||
#undef GO
|
||||
}
|
||||
// regenerate mask
|
||||
ADDI_W(xMASK, xZR, -1);
|
||||
LU32I_D(xMASK, 0);
|
||||
REGENERATE_MASK();
|
||||
|
||||
fpu_popcache(dyn, ninst, reg, 0);
|
||||
if (saveflags) {
|
||||
@@ -652,6 +794,27 @@ int sse_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a)
|
||||
dyn->lsx.ssecache[a].write = 1; // it will be write...
|
||||
return dyn->lsx.ssecache[a].reg;
|
||||
}
|
||||
// forget ext register for a SSE reg, does nothing if the regs is not loaded
|
||||
void sse_forget_reg(dynarec_la64_t* dyn, int ninst, int a)
|
||||
{
|
||||
if (dyn->lsx.ssecache[a].v == -1)
|
||||
return;
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.ssecache[a].reg].t == LSX_CACHE_XMMW) {
|
||||
VST(dyn->lsx.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
|
||||
dyn->lsx.ssecache[a].v = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
void sse_reflect_reg(dynarec_la64_t* dyn, int ninst, int a)
|
||||
{
|
||||
if (dyn->lsx.ssecache[a].v == -1)
|
||||
return;
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.ssecache[a].reg].t == LSX_CACHE_XMMW) {
|
||||
VST(dyn->lsx.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
}
|
||||
}
|
||||
|
||||
// purge the SSE cache for XMM0..XMM7 (to use before function native call)
|
||||
void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
@@ -767,18 +930,18 @@ void emit_pf(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
// PF: (((emu->x64emu_parity_tab[(res&0xff) / 32] >> ((res&0xff) % 32)) & 1) == 0)
|
||||
MOV64x(s4, (uintptr_t)GetParityTab());
|
||||
SRLI_D(s3, s1, 3);
|
||||
ANDI(s3, s3, 28);
|
||||
ADD_D(s4, s4, s3);
|
||||
LD_W(s4, s4, 0);
|
||||
NOR(s4, xZR, s4);
|
||||
SRL_W(s4, s4, s1);
|
||||
ANDI(s4, s4, 1);
|
||||
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_PF);
|
||||
SRLI_D(s3, s1, 4);
|
||||
XOR(s3, s3, s1);
|
||||
|
||||
SRLI_D(s4, s3, 2);
|
||||
XOR(s4, s3, s4);
|
||||
|
||||
SRLI_D(s3, s4, 1);
|
||||
XOR(s3, s3, s4);
|
||||
|
||||
XORI(s3, s3, 1);
|
||||
BSTRINS_D(xFlags, s3, F_PF, F_PF);
|
||||
}
|
||||
|
||||
void fpu_reset_cache(dynarec_la64_t* dyn, int ninst, int reset_n)
|
||||
|
||||
@@ -111,6 +111,17 @@
|
||||
LDz(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
// GETED32 can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETED32(D) \
|
||||
if (MODREG) { \
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, D); \
|
||||
LDxw(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
// GETEDH can use hint for ed, and x1 or x2 for wback (depending on hint), might also use x3. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDH(hint, D) \
|
||||
if (MODREG) { \
|
||||
@@ -191,6 +202,13 @@
|
||||
ST_W(ed, wback, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
|
||||
#define WBACKO(O) \
|
||||
if (wback) { \
|
||||
SDXxw(ed, wback, O); \
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
// GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
|
||||
#define GETSEW(i, D) \
|
||||
if (MODREG) { \
|
||||
@@ -279,6 +297,30 @@
|
||||
gd = i; \
|
||||
BSTRPICK_D(gd, gb1, gb2 + 7, gb2);
|
||||
|
||||
// GETEBO will use i for ed, i is also Offset, and can use r3 for wback.
|
||||
#define GETEBO(i, D) \
|
||||
if (MODREG) { \
|
||||
if (rex.rex) { \
|
||||
wback = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
wb2 = 0; \
|
||||
} else { \
|
||||
wback = (nextop & 7); \
|
||||
wb2 = (wback >> 2) * 8; \
|
||||
wback = TO_LA64(wback & 3); \
|
||||
} \
|
||||
BSTRPICK_D(i, wback, wb2 + 7, wb2); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 1, D); \
|
||||
ADD_D(x3, wback, i); \
|
||||
if (wback != x3) wback = x3; \
|
||||
LD_B(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
|
||||
// Get GX as a quad (might use x1)
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop & 0x38) >> 3) + (rex.r << 3); \
|
||||
@@ -413,6 +455,10 @@
|
||||
#define BEQ_MARK3(reg1, reg2) Bxx_gen(EQ, MARK3, reg1, reg2)
|
||||
// Branch to MARKLOCK if reg1==reg2 (use j64)
|
||||
#define BEQ_MARKLOCK(reg1, reg2) Bxx_gen(EQ, MARKLOCK, reg1, reg2)
|
||||
// Branch to MARK if reg1==0 (use j64)
|
||||
#define BEQZ_MARK(reg) BxxZ_gen(EQ, MARK, reg)
|
||||
// Branch to MARK2 if reg1==0 (use j64)
|
||||
#define BEQZ_MARK2(reg) BxxZ_gen(EQ, MARK2, reg)
|
||||
// Branch to MARKLOCK if reg1==0 (use j64)
|
||||
#define BEQZ_MARKLOCK(reg) BxxZ_gen(EQ, MARKLOCK, reg)
|
||||
|
||||
@@ -450,8 +496,8 @@
|
||||
// Branch to MARK if reg1>=reg2 (use j64)
|
||||
#define BGE_MARK(reg1, reg2) Bxx_gen(GE, MARK, reg1, reg2)
|
||||
|
||||
// Branch to MARK1 instruction unconditionnal (use j64)
|
||||
#define B_MARK1_nocond Bxx_gen(__, MARK1, 0, 0)
|
||||
// Branch to MARK instruction unconditionnal (use j64)
|
||||
#define B_MARK_nocond Bxx_gen(__, MARK, 0, 0)
|
||||
// Branch to MARK2 instruction unconditionnal (use j64)
|
||||
#define B_MARK2_nocond Bxx_gen(__, MARK2, 0, 0)
|
||||
// Branch to MARK3 instruction unconditionnal (use j64)
|
||||
@@ -530,10 +576,12 @@
|
||||
LOAD_REG(R15);
|
||||
|
||||
#define SET_DFNONE() \
|
||||
do { \
|
||||
dyn->f.dfnone_here=1; \
|
||||
if (!dyn->f.dfnone) { \
|
||||
ST_W(xZR, xEmu, offsetof(x64emu_t, df)); \
|
||||
dyn->f.dfnone = 1; \
|
||||
}
|
||||
} } while(0);
|
||||
#define SET_DF(S, N) \
|
||||
if ((N) != d_none) { \
|
||||
MOV32w(S, (N)); \
|
||||
@@ -542,7 +590,7 @@
|
||||
} else \
|
||||
SET_DFNONE()
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
#define SET_DFOK() dyn->f.dfnone = 1; dyn->f.dfnone_here=1
|
||||
|
||||
#define CLEAR_FLAGS_(s) \
|
||||
MOV64x(s, (1UL << F_AF) | (1UL << F_CF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF)); ANDN(xFlags, xFlags, s);
|
||||
@@ -573,7 +621,7 @@
|
||||
ANDI(scratch1, scratch2, 0x80); \
|
||||
} else { \
|
||||
SRLI_D(scratch1, scratch2, (width)-1); \
|
||||
if (width != 64) ANDI(scratch1, scratch1, 1); \
|
||||
if ((width) != 64) ANDI(scratch1, scratch1, 1); \
|
||||
} \
|
||||
BEQZ(scratch1, 8); \
|
||||
ORI(xFlags, xFlags, 1 << F_CF); \
|
||||
@@ -591,7 +639,7 @@
|
||||
}
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS()
|
||||
#define MAYSETFLAGS() do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
@@ -723,6 +771,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define dynarec64_0F STEPNAME(dynarec64_0F)
|
||||
#define dynarec64_64 STEPNAME(dynarec64_64)
|
||||
#define dynarec64_66 STEPNAME(dynarec64_66)
|
||||
#define dynarec64_6664 STEPNAME(dynarec64_6664)
|
||||
#define dynarec64_67 STEPNAME(dynarec64_67)
|
||||
#define dynarec64_F30F STEPNAME(dynarec64_F30F)
|
||||
#define dynarec64_660F STEPNAME(dynarec64_660F)
|
||||
#define dynarec64_F0 STEPNAME(dynarec64_F0)
|
||||
@@ -763,7 +813,14 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define emit_sbb16 STEPNAME(emit_sbb16)
|
||||
#define emit_sbb32 STEPNAME(emit_sbb32)
|
||||
#define emit_neg8 STEPNAME(emit_neg8)
|
||||
#define emit_neg16 STEPNAME(emit_neg16)
|
||||
#define emit_neg32 STEPNAME(emit_neg32)
|
||||
#define emit_inc8 STEPNAME(emit_inc8)
|
||||
#define emit_inc16 STEPNAME(emit_inc16)
|
||||
#define emit_inc32 STEPNAME(emit_inc32)
|
||||
#define emit_dec8 STEPNAME(emit_dec8)
|
||||
#define emit_dec16 STEPNAME(emit_dec16)
|
||||
#define emit_dec32 STEPNAME(emit_dec32)
|
||||
#define emit_or32 STEPNAME(emit_or32)
|
||||
#define emit_or32c STEPNAME(emit_or32c)
|
||||
#define emit_or8 STEPNAME(emit_or8)
|
||||
@@ -788,8 +845,11 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar16 STEPNAME(emit_sar16)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_rol32 STEPNAME(emit_rol32)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
@@ -799,6 +859,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define sse_purge07cache STEPNAME(sse_purge07cache)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
#define sse_get_reg_empty STEPNAME(sse_get_reg_empty)
|
||||
#define sse_forget_reg STEPNAME(sse_forget_reg)
|
||||
#define sse_reflect_reg STEPNAME(sse_reflect_reg)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
@@ -852,7 +914,14 @@ void emit_sbb8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_sbb16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_neg8(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg16(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3);
|
||||
void emit_inc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_inc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_dec8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_dec16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
void emit_or8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -877,8 +946,11 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
@@ -907,6 +979,10 @@ void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1);
|
||||
int sse_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite);
|
||||
// get lsx register for an SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a);
|
||||
// forget float register for a SSE reg, create the entry if needed
|
||||
void sse_forget_reg(dynarec_la64_t* dyn, int ninst, int a);
|
||||
// Push current value to the cache
|
||||
void sse_reflect_reg(dynarec_la64_t* dyn, int ninst, int a);
|
||||
|
||||
void CacheTransform(dynarec_la64_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
@@ -924,6 +1000,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_6664(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
@@ -1063,4 +1141,12 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif //__DYNAREC_LA64_HELPER_H__
|
||||
#define REGENERATE_MASK() \
|
||||
do { \
|
||||
ADDI_W(xMASK, xZR, -1); \
|
||||
LU32I_D(xMASK, 0); \
|
||||
} while (0)
|
||||
|
||||
#define PURGE_YMM() /* TODO */
|
||||
|
||||
#endif //__DYNAREC_LA64_HELPER_H__
|
||||
@@ -4,7 +4,7 @@
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if (ninst) dyn->insts[ninst - 1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst - 1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
dyn->insts_size += 1 + ((dyn->insts[ninst].x64.size > (dyn->insts[ninst].size / 4)) ? dyn->insts[ninst].x64.size : (dyn->insts[ninst].size / 4)) / 15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) \
|
||||
do { \
|
||||
dyn->insts[ninst].size += 4; \
|
||||
@@ -15,6 +15,7 @@
|
||||
if (ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst - 1].address + dyn->insts[ninst - 1].size); \
|
||||
dyn->insts_size += 1 + ((dyn->insts[ninst - 1].x64.size > (dyn->insts[ninst - 1].size / 4)) ? dyn->insts[ninst - 1].x64.size : (dyn->insts[ninst - 1].size / 4)) / 15; \
|
||||
dyn->insts[ninst].ymm0_pass2 = dyn->ymm_zero; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#define MESSAGE(A, ...) \
|
||||
if (box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if (ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4);
|
||||
if (ninst) { \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4); \
|
||||
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
|
||||
}
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
|
||||
#define TABLE64(A, V) \
|
||||
|
||||
@@ -62,7 +62,8 @@ typedef struct lsxcache_s {
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if deferred flags is already set to df_none
|
||||
uint8_t dfnone; // if deferred flags is already set to df_none
|
||||
uint8_t dfnone_here;// defered flags is cleared in this opcode
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_la64_s {
|
||||
@@ -79,7 +80,13 @@ typedef struct instruction_la64_s {
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
uint16_t retn;
|
||||
uint16_t purge_ymm; // need to purge some ymm
|
||||
uint16_t ymm0_in; // bitmap of ymm to zero at purge
|
||||
uint16_t ymm0_add; // the ymm0 added by the opcode
|
||||
uint16_t ymm0_sub; // the ymm0 removed by the opcode
|
||||
uint16_t ymm0_out; // the ymmm0 at th end of the opcode
|
||||
uint16_t ymm0_pass2, ymm0_pass3;
|
||||
uint8_t barrier_maybe;
|
||||
uint8_t will_write;
|
||||
uint8_t last_write;
|
||||
@@ -119,6 +126,7 @@ typedef struct dynarec_la64_s {
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint16_t ymm_zero; // bitmap of ymm to zero at purge
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uint8_t always_test;
|
||||
@@ -129,6 +137,7 @@ void add_next(dynarec_la64_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_la64_t *dyn, uintptr_t addr);
|
||||
void add_jump(dynarec_la64_t *dyn, int ninst);
|
||||
int get_first_jump(dynarec_la64_t *dyn, int next);
|
||||
int get_first_jump_addr(dynarec_la64_t *dyn, uintptr_t next);
|
||||
int is_nops(dynarec_la64_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_la64_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
|
||||
@@ -253,6 +253,8 @@ f24-f31 fs0-fs7 Static registers Callee
|
||||
#define LL_D(rd, rj, imm) EMIT(type_2RI14(0b00100010, imm >> 2, rj, rd))
|
||||
#define SC_D(rd, rj, imm) EMIT(type_2RI14(0b00100011, imm >> 2, rj, rd))
|
||||
|
||||
#define SC_Q(rd, rk, rj) EMIT(type_3R(0b00111000010101110, rk, rj, rd))
|
||||
|
||||
#define LLxw(rd, rj, imm) EMIT(type_2RI14(0b00100000 | (rex.w ? 0b10 : 0b00), imm >> 2, rj, rd))
|
||||
#define SCxw(rd, rj, imm) EMIT(type_2RI14(0b00100001 | (rex.w ? 0b10 : 0b00), imm >> 2, rj, rd))
|
||||
|
||||
@@ -362,14 +364,14 @@ f24-f31 fs0-fs7 Static registers Callee
|
||||
} \
|
||||
} while (0)
|
||||
// Shift Right Logical Immediate
|
||||
#define SRLIxw(rd, rs1, imm) \
|
||||
do { \
|
||||
if (rex.w) { \
|
||||
SRLI_D(rd, rs1, imm); \
|
||||
} else { \
|
||||
SRLI_W(rd, rs1, imm); \
|
||||
if (imm == 0) ZEROUP(rd); \
|
||||
} \
|
||||
#define SRLIxw(rd, rs1, imm) \
|
||||
do { \
|
||||
if (rex.w) { \
|
||||
SRLI_D(rd, rs1, imm); \
|
||||
} else { \
|
||||
SRLI_W(rd, rs1, imm); \
|
||||
if ((imm) == 0) ZEROUP(rd); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Shift Right Arithmetic Immediate
|
||||
@@ -480,19 +482,19 @@ f24-f31 fs0-fs7 Static registers Callee
|
||||
// bstr32[msbw:lsbw] = GR[rj][msbw-lsbw:0]
|
||||
// bstr32[lsbw-1:0] = GR[rd][lsbw-1:0]
|
||||
// GR[rd] = SignExtend(bstr32[31:0], GRLEN)
|
||||
#define BSTRINS_W(rd, rj, msbw5, lsbw5) EMIT(type_2RI12(0b0000000001, 0b100000000000 | (msbw5 & 0x1F) << 6 | (lsbw5 & 0x1F), rj, rd))
|
||||
#define BSTRINS_W(rd, rj, msbw5, lsbw5) EMIT(type_2RI12(0b0000000001, 0b100000000000 | ((msbw5) & 0x1F) << 6 | ((lsbw5) & 0x1F), rj, rd))
|
||||
|
||||
// GR[rd][63:msbd+1] = GR[rd][63:msbd+1]
|
||||
// GR[rd][msbd:lsbd] = GR[rj][msbd-lsbd:0]
|
||||
// GR[rd][lsbd-1:0] = GR[rd][lsbd-1:0]
|
||||
#define BSTRINS_D(rd, rj, msbd6, lsbd6) EMIT(type_2RI12(0b0000000010, (msbd6 & 0x3F) << 6 | (lsbd6 & 0x3F), rj, rd))
|
||||
#define BSTRINS_D(rd, rj, msbd6, lsbd6) EMIT(type_2RI12(0b0000000010, ((msbd6) & 0x3F) << 6 | ((lsbd6) & 0x3F), rj, rd))
|
||||
|
||||
// bstr32[31:0] = ZeroExtend(GR[rj][msbw:lsbw], 32)
|
||||
// GR[rd] = SignExtend(bstr32[31:0], GRLEN)
|
||||
#define BSTRPICK_W(rd, rj, msbw5, lsbw5) EMIT(type_2RI12(0b0000000001, 0b100000100000 | (msbw5 & 0x1F) << 6 | (lsbw5 & 0x1F), rj, rd))
|
||||
#define BSTRPICK_W(rd, rj, msbw5, lsbw5) EMIT(type_2RI12(0b0000000001, 0b100000100000 | ((msbw5) & 0x1F) << 6 | ((lsbw5) & 0x1F), rj, rd))
|
||||
|
||||
// GR[rd] = ZeroExtend(GR[rj][msbd:lsbd], 64)
|
||||
#define BSTRPICK_D(rd, rj, msbd6, lsbd6) EMIT(type_2RI12(0b0000000011, (msbd6 & 0x3F) << 6 | (lsbd6 & 0x3F), rj, rd))
|
||||
#define BSTRPICK_D(rd, rj, msbd6, lsbd6) EMIT(type_2RI12(0b0000000011, ((msbd6) & 0x3F) << 6 | ((lsbd6) & 0x3F), rj, rd))
|
||||
|
||||
// ZERO the upper part
|
||||
#define ZEROUP(rd) BSTRINS_D(rd, xZR, 63, 32);
|
||||
@@ -526,6 +528,15 @@ f24-f31 fs0-fs7 Static registers Callee
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CTZxw(rd, rj) \
|
||||
do { \
|
||||
if (rex.w) { \
|
||||
CTZ_D(rd, rj); \
|
||||
} else { \
|
||||
CTZ_W(rd, rj); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
// GR[rd] = SignExtend(GR[rj][7:0], GRLEN)
|
||||
#define EXT_W_B(rd, rj) EMIT(type_2R(0b0000000000000000010111, rj, rd))
|
||||
@@ -917,6 +928,14 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
#define VSUB_W(vd, vj, vk) EMIT(type_3R(0b01110000000011010, vk, vj, vd))
|
||||
#define VSUB_D(vd, vj, vk) EMIT(type_3R(0b01110000000011011, vk, vj, vd))
|
||||
#define VSUB_Q(vd, vj, vk) EMIT(type_3R(0b01110001001011011, vk, vj, vd))
|
||||
#define VADDI_BU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100010100, imm5, vj, vd))
|
||||
#define VADDI_HU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100010101, imm5, vj, vd))
|
||||
#define VADDI_WU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100010110, imm5, vj, vd))
|
||||
#define VADDI_DU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100010111, imm5, vj, vd))
|
||||
#define VSUBI_BU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100011000, imm5, vj, vd))
|
||||
#define VSUBI_HU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100011001, imm5, vj, vd))
|
||||
#define VSUBI_WU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100011010, imm5, vj, vd))
|
||||
#define VSUBI_DU(vd, vj, imm5) EMIT(type_2RI5(0b01110010100011011, imm5, vj, vd))
|
||||
#define VSADD_B(vd, vj, vk) EMIT(type_3R(0b01110000010001100, vk, vj, vd))
|
||||
#define VSADD_H(vd, vj, vk) EMIT(type_3R(0b01110000010001101, vk, vj, vd))
|
||||
#define VSADD_W(vd, vj, vk) EMIT(type_3R(0b01110000010001110, vk, vj, vd))
|
||||
@@ -1137,6 +1156,12 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
#define VSIGNCOV_H(vd, vj, vk) EMIT(type_3R(0b01110001001011101, vk, vj, vd))
|
||||
#define VSIGNCOV_W(vd, vj, vk) EMIT(type_3R(0b01110001001011110, vk, vj, vd))
|
||||
#define VSIGNCOV_D(vd, vj, vk) EMIT(type_3R(0b01110001001011111, vk, vj, vd))
|
||||
#define VMSKLTZ_B(vd, vj) EMIT(type_2R(0b0111001010011100010000, vj, vd))
|
||||
#define VMSKLTZ_H(vd, vj) EMIT(type_2R(0b0111001010011100010001, vj, vd))
|
||||
#define VMSKLTZ_W(vd, vj) EMIT(type_2R(0b0111001010011100010010, vj, vd))
|
||||
#define VMSKLTZ_D(vd, vj) EMIT(type_2R(0b0111001010011100010011, vj, vd))
|
||||
#define VMSKGEZ_B(vd, vj) EMIT(type_2R(0b0111001010011100010100, vj, vd))
|
||||
#define VMSKNZ_B(vd, vj) EMIT(type_2R(0b0111001010011100011000, vj, vd))
|
||||
#define VAND_V(vd, vj, vk) EMIT(type_3R(0b01110001001001100, vk, vj, vd))
|
||||
#define VLDI(vd, imm13) EMIT(type_1RI13(0b01110011111000, imm13, vd))
|
||||
#define VOR_V(vd, vj, vk) EMIT(type_3R(0b01110001001001101, vk, vj, vd))
|
||||
@@ -1355,6 +1380,9 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
#define VLD(vd, rj, imm12) EMIT(type_2RI12(0b0010110000, imm12, rj, vd))
|
||||
#define VST(vd, rj, imm12) EMIT(type_2RI12(0b0010110001, imm12, rj, vd))
|
||||
|
||||
#define VFCMP_S(vd, vj, vk, cond) EMIT(type_4R(0b000011000101, cond, vk, vj, vd))
|
||||
#define VFCMP_D(vd, vj, vk, cond) EMIT(type_4R(0b000011000110, cond, vk, vj, vd))
|
||||
|
||||
#define XVADD_B(vd, vj, vk) EMIT(type_3R(0b01110100000010100, vk, vj, vd))
|
||||
#define XVADD_H(vd, vj, vk) EMIT(type_3R(0b01110100000010101, vk, vj, vd))
|
||||
#define XVADD_W(vd, vj, vk) EMIT(type_3R(0b01110100000010110, vk, vj, vd))
|
||||
@@ -1689,6 +1717,8 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
#define XVSLT_HU(vd, vj, vk) EMIT(type_3R(0b01110100000010001, vk, vj, vd))
|
||||
#define XVSLT_WU(vd, vj, vk) EMIT(type_3R(0b01110100000010010, vk, vj, vd))
|
||||
#define XVSLT_DU(vd, vj, vk) EMIT(type_3R(0b01110100000010011, vk, vj, vd))
|
||||
#define XVBSLL_V(vd, vj, imm5) EMIT(type_2RI5(0b01110110100011100, imm5, vj, vd))
|
||||
#define XVBSRL_V(vd, vj, imm5) EMIT(type_2RI5(0b01110110100011101, imm5, vj, vd))
|
||||
#define XVPACKEV_B(vd, vj, vk) EMIT(type_3R(0b01110101000101100, vk, vj, vd))
|
||||
#define XVPACKEV_H(vd, vj, vk) EMIT(type_3R(0b01110101000101101, vk, vj, vd))
|
||||
#define XVPACKEV_W(vd, vj, vk) EMIT(type_3R(0b01110101000101110, vk, vj, vd))
|
||||
@@ -2038,6 +2068,14 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
ST_W(rd, rj, imm12); \
|
||||
} while (0)
|
||||
|
||||
#define SDXxw(rd, rj, rk) \
|
||||
do { \
|
||||
if (rex.w) \
|
||||
STX_D(rd, rj, rk); \
|
||||
else \
|
||||
STX_W(rd, rj, rk); \
|
||||
} while (0)
|
||||
|
||||
#define SDz(rd, rj, imm12) \
|
||||
do { \
|
||||
if (rex.is32bits) \
|
||||
|
||||
@@ -191,9 +191,8 @@ la64_lock_cas_dd:
|
||||
la64_lock_cas_dq:
|
||||
ll.d $a4, $a0, 0
|
||||
bne $a4, $a2, 1f
|
||||
sc.d $a1, $a0, 0
|
||||
.word 0x38571c85 // sc.q $a1, $a3, $a0
|
||||
beqz $a1, 1f
|
||||
st.d $a3, $a0, 8
|
||||
xori $a0, $a1, 1
|
||||
ret
|
||||
1:
|
||||
|
||||
+112
-112
@@ -12,7 +12,7 @@ static const char* Vt[] = { "vra0", "vra1", "vra2", "vra3", "vra4", "vra5", "vra
|
||||
|
||||
typedef struct la64_print_s {
|
||||
int d, j, k, a;
|
||||
int i, u;
|
||||
uint64_t i, u;
|
||||
} la64_print_t;
|
||||
|
||||
int isMask(uint32_t opcode, const char* mask, la64_print_t *a)
|
||||
@@ -44,7 +44,7 @@ int isMask(uint32_t opcode, const char* mask, la64_print_t *a)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int64_t signExtend(uint32_t val, int sz)
|
||||
int64_t signExtend(uint64_t val, int sz)
|
||||
{
|
||||
int64_t ret = val;
|
||||
if((val>>(sz-1))&1)
|
||||
@@ -80,39 +80,39 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001010iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ADDI.W", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ADDI.W", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001011iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ADDI.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ADDI.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000100iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ADDU16I.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ADDU16I.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000000010iikkkkkjjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %s, %d", "ALSL.W", Xt[Rd], Xt[Rj], Xt[Rk], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %s, %lu", "ALSL.W", Xt[Rd], Xt[Rj], Xt[Rk], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000000011iikkkkkjjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %s, %d", "ALSL.WU", Xt[Rd], Xt[Rj], Xt[Rk], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %s, %lu", "ALSL.WU", Xt[Rd], Xt[Rj], Xt[Rk], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000010110iikkkkkjjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %s, %d", "ALSL.D", Xt[Rd], Xt[Rj], Xt[Rk], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %s, %lu", "ALSL.D", Xt[Rd], Xt[Rj], Xt[Rk], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0001010iiiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%x", "LU12I.W", Xt[Rd], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "LU12I.W", Xt[Rd], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0001011iiiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "LU32I.D", Xt[Rd], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "LU32I.D", Xt[Rd], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001100iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LU52I.D", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "LU52I.D", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000000100100kkkkkjjjjjddddd", &a)) {
|
||||
@@ -124,47 +124,47 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001000iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "SLTI", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "SLTI", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001001iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SLTI", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "SLTI", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0001100iiiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCADDI", Xt[Rd], signExtend(imm << 2, 22));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCADDI", Xt[Rd], (uint64_t)signExtend(imm << 2, 22));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0001101iiiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCALAU12I", Xt[Rd], signExtend(imm << 12, 32));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCALAU12I", Xt[Rd], (uint64_t)signExtend(imm << 12, 32));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0001110iiiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCADDU12I", Xt[Rd], signExtend(imm << 12, 32));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCADDU12I", Xt[Rd], (uint64_t)signExtend(imm << 12, 32));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0001111iiiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCADDU18I", Xt[Rd], signExtend(imm << 18, 38));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "PCADDU18I", Xt[Rd], (uint64_t)signExtend(imm << 18, 38));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00100000iiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LL.W", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LL.W", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00100001iiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "SC.W", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "SC.W", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00100010iiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LL.D", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LL.D", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00100011iiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "SC.D", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "SC.D", Xt[Rd], Xt[Rj], signExtend(imm << 2, 16));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00111000011100100iiiiiiiiiiiiiii", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %d", "DBAR", imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %lu", "DBAR", imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000000101001kkkkkjjjjjddddd", &a)) {
|
||||
@@ -196,15 +196,15 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001101iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "ANDI", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "ANDI", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001110iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "ORI", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "ORI", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000001111iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "XORI", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "XORI", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000000101110kkkkkjjjjjddddd", &a)) {
|
||||
@@ -240,35 +240,35 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001000001iiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SLLI.D", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "SLLI.D", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001000101iiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SRLI.D", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "SRLI.D", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001001001iiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SRAI.D", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "SRAI.D", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001001101iiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "ROTRI.D", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "ROTRI.D", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010000001iiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SLLI.W", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "SLLI.W", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010001001iiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SRLI.W", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "SRLI.W", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010010001iiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "SRAI.W", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "SRAI.W", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010011001iiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u", "ROTRI.W", Xt[Rd], Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu", "ROTRI.W", Xt[Rd], Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000000111000kkkkkjjjjjddddd", &a)) {
|
||||
@@ -336,19 +336,19 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000011uuuuu0iiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u, %u", "BSTRINS.W", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu, %lu", "BSTRINS.W", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000010uuuuuuiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u, %u", "BSTRINS.D", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu, %lu", "BSTRINS.D", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000011uuuuu1iiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u, %u", "BSTRPICK.W", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu, %lu", "BSTRPICK.W", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000011uuuuuuiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %u, %u", "BSTRPICK.D", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %lu, %lu", "BSTRPICK.D", Xt[Rd], Xt[Rj], imm_up, imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000000000000000100jjjjjddddd", &a)) {
|
||||
@@ -432,35 +432,35 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "010110iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BEQ", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "BEQ", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "010111iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BNE", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "BNE", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "011000iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BLT", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "BLT", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "011001iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BGE", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "BGE", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "011010iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BLTU", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "BLTU", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "011011iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "BGEU", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "BGEU", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "010000iiiiiiiiiiiiiiiijjjjjuuuuu", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "BEQZ", Xt[Rj], signExtend(imm + (imm_up << 16) << 2, 23));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %ld", "BEQZ", Xt[Rj], signExtend((imm + (imm_up << 16)) << 2, 23));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "010001iiiiiiiiiiiiiiiijjjjjuuuuu", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "BNEZ", Xt[Rj], signExtend(imm + (imm_up << 16) << 2, 23));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %ld", "BNEZ", Xt[Rj], signExtend((imm + (imm_up << 16)) << 2, 23));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0100110000000000000000jjjjj00000", &a)) {
|
||||
@@ -468,55 +468,55 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "010011iiiiiiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "JIRL", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "JIRL", Xt[Rd], Xt[Rj], signExtend(imm << 2, 18));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "010100iiiiiiiiiiiiiiiiiiiiiiiiii", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s 0x%x", "B", (((imm & 0x3FF) << 16) | ((uint32_t)imm >> 10)) << 6 >> 4);
|
||||
snprintf(buff, sizeof(buff), "%-15s 0x%lx", "B", (((imm & 0x3FF) << 16) | (imm >> 10)) << 6 >> 4);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100000iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.B", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.B", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100001iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.H", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.H", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100010iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.W", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.W", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100011iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101000iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.BU", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.BU", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101001iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.HU", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.HU", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101010iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "LD.WU", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "LD.WU", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100100iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ST.B", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ST.B", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100101iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ST.H", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ST.H", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100110iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ST.W", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ST.W", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010100111iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "ST.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "ST.D", Xt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00111000000000000kkkkkjjjjjddddd", &a)) {
|
||||
@@ -564,19 +564,19 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101110iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "FLD.D", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "FLD.D", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101100iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "FLD.S", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "FLD.S", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101111iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "FST.D", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "FST.D", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010101101iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "FST.S", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "FST.S", Ft[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000001000000001kkkkkjjjjjddddd", &a)) {
|
||||
@@ -2124,44 +2124,44 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100100iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VSHUF4I.B", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VSHUF4I.B", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100101iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VSHUF4I.H", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VSHUF4I.H", Vt[Rd], Vt[Rj], imm);
|
||||
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100110iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VSHUF4I.W", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VSHUF4I.W", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100111iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VSHUF4I.D", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VSHUF4I.D", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100000iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VEXTRINS.D", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VEXTRINS.D", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100001iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VEXTRINS.W", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VEXTRINS.W", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100010iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VEXTRINS.H", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VEXTRINS.H", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "01110011100011iiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%x", "VEXTRINS.B", Vt[Rd], Vt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, 0x%lx", "VEXTRINS.B", Vt[Rd], Vt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010110000iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "VLD", Vt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "VLD", Vt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0010110001iiiiiiiiiiiijjjjjddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %d", "VST", Vt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s, %ld", "VST", Vt[Rd], Xt[Rj], signExtend(imm, 12));
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000000000001000000000101000", &a)) {
|
||||
@@ -2181,7 +2181,7 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000000000001110000iii00000", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %d", "X64SETTOP", imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %lu", "X64SETTOP", imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000000000001110100000ddddd", &a)) {
|
||||
@@ -2189,15 +2189,15 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010111iiiiiiii00000ddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%x", "X64GETEFLAGS", Xt[Rd], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "X64GETEFLAGS", Xt[Rd], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010111iiiiiiii00001ddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%x", "X64SETEFLAGS", Xt[Rd], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "X64SETEFLAGS", Xt[Rd], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000011011010iiii00000ddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%x", "X64SETJ", Xt[Rd], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, 0x%lx", "X64SETJ", Xt[Rd], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000000000000100000jjjjj00000", &a)) {
|
||||
@@ -2237,31 +2237,31 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00001", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.H", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00010", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.W", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00011", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.D", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00100", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.BU", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00101", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.HU", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00110", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.WU", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111101kkkkkjjjjj00111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.B", Xt[Rj], Xt[Rk]);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %s", "X64MUL.DU", Xt[Rj], Xt[Rk]);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000001111110kkkkkjjjjj00000", &a)) {
|
||||
@@ -2505,118 +2505,118 @@ const char* la64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj00000", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SLLI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SLLI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj00100", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRLI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRLI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj01000", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRAI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRAI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj01100", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTRI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTRI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj10000", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCRI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCRI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj10100", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTLI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTLI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010100001iiijjjjj11000", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCLI.B", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCLI.B", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj00001", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SLLI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SLLI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj00101", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRLI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRLI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj01001", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRAI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRAI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj01101", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTRI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTRI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj10001", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCRI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCRI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj10101", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTLI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTLI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "000000000101010001iiiijjjjj11001", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCLI.H", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCLI.H", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj00010", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SLLI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SLLI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj00110", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRLI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRLI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj01010", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRAI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRAI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj01110", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTRI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTRI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj10010", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCRI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCRI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj10110", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTLI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTLI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "00000000010101001iiiiijjjjj11010", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCLI.W", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCLI.W", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj00011", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SLLI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SLLI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj00111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRLI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRLI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj01011", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64SRAI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64SRAI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj01111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTRI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTRI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj10011", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCRI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCRI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj10111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64ROTLI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64ROTLI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
if (isMask(opcode, "0000000001010101iiiiiijjjjj11011", &a)) {
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %d", "X64RCLI.D", Xt[Rj], imm);
|
||||
snprintf(buff, sizeof(buff), "%-15s %s, %lu", "X64RCLI.D", Xt[Rj], imm);
|
||||
return buff;
|
||||
}
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X ???", __builtin_bswap32(opcode));
|
||||
return buff;
|
||||
}
|
||||
}
|
||||
@@ -66,13 +66,8 @@
|
||||
#define native_lock_write_d(A, B) rv64_lock_cas_d(A, tmpcas, B)
|
||||
#define native_lock_read_dd(A) tmpcas=*(uint64_t*)(A)
|
||||
#define native_lock_write_dd(A, B) rv64_lock_cas_dd(A, tmpcas, B)
|
||||
// there is no atomic move on 16bytes, so faking it
|
||||
#define native_lock_read_dq(A, B, C) \
|
||||
do { \
|
||||
*A = tmpcas = ((uint64_t*)(C))[0]; \
|
||||
*B = ((uint64_t*)(C))[1]; \
|
||||
} while (0)
|
||||
#define native_lock_write_dq(A, B, C) rv64_lock_cas_dq(C, A, tmpcas, B);
|
||||
#define native_lock_read_dq(A, B, C) // never used
|
||||
#define native_lock_write_dq(A, B, C) // never used
|
||||
#define native_lock_get_b(A) rv64_lock_get_b(A)
|
||||
#define native_lock_get_d(A) rv64_lock_get_d(A)
|
||||
#define native_lock_get_dd(A) rv64_lock_get_dd(A)
|
||||
|
||||
@@ -212,7 +212,8 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
MUL(gd, ed, x4);
|
||||
SEXT_W(x3, ed);
|
||||
MUL(gd, x3, x4);
|
||||
UFLAG_RES(gd);
|
||||
SRLI(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
@@ -251,7 +252,8 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
MUL(gd, ed, x4);
|
||||
SEXT_W(x3, ed);
|
||||
MUL(gd, x3, x4);
|
||||
UFLAG_RES(gd);
|
||||
SRLI(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
|
||||
@@ -226,7 +226,7 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
break;
|
||||
case 0x86:
|
||||
INST_NAME("(LOCK)XCHG Eb, Gb");
|
||||
INST_NAME("(LOCK) XCHG Eb, Gb");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
GETGB(x1);
|
||||
@@ -240,9 +240,39 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGB(x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
LBU(x1, ed, 0);
|
||||
SB(gd, ed, 0);
|
||||
SMDMB();
|
||||
|
||||
// calculate shift amount
|
||||
ANDI(x1, ed, 0x3);
|
||||
SLLI(x1, x1, 3);
|
||||
|
||||
// align address to 4-bytes to use ll.w/sc.w
|
||||
ADDI(x4, xZR, 0xffc);
|
||||
AND(x6, ed, x4);
|
||||
|
||||
// load aligned data
|
||||
LWU(x5, x6, 0);
|
||||
|
||||
// insert gd byte into the aligned data
|
||||
ADDI(x4, xZR, 0xff);
|
||||
SLL(x4, x4, x1);
|
||||
NOT(x4, x4);
|
||||
AND(x4, x5, x4);
|
||||
SLL(x5, gd, x1);
|
||||
OR(x4, x4, x5);
|
||||
|
||||
// do aligned ll/sc sequence
|
||||
MARKLOCK;
|
||||
LR_W(x1, x6, 1, 1);
|
||||
SC_W(x5, x4, x6, 1, 1);
|
||||
BNEZ_MARKLOCK(x5);
|
||||
|
||||
// calculate shift amount again
|
||||
ANDI(x4, ed, 0x3);
|
||||
SLLI(x4, x4, 3);
|
||||
|
||||
// extract loaded byte
|
||||
SRL(x1, x1, x4);
|
||||
|
||||
gd = x1;
|
||||
GBBACK(x3);
|
||||
}
|
||||
@@ -517,7 +547,7 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x9F:
|
||||
INST_NAME("LAHF");
|
||||
READFLAGS(X_CF | X_PF | X_AF | X_ZF | X_SF);
|
||||
ANDI(x1, xFlags, 0xFF);
|
||||
ANDI(x1, xFlags, 0b11010111); // leave reserved bits out (we are using one as OF2)
|
||||
SLLI(x1, x1, 8);
|
||||
MOV64x(x2, 0xffffffffffff00ffLL);
|
||||
AND(xRAX, xRAX, x2);
|
||||
|
||||
@@ -198,6 +198,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, Ib");
|
||||
@@ -209,6 +210,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
WBACK;
|
||||
if(!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
|
||||
+1006
-71
File diff suppressed because it is too large.
Load diff
@@ -38,6 +38,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int lock;
|
||||
uintptr_t retaddr = 0;
|
||||
MAYUSE(u8);
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u64);
|
||||
@@ -125,7 +126,14 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x0F:
|
||||
switch(rep) {
|
||||
case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
case 0: {
|
||||
if (rv64_vector) {
|
||||
retaddr = dynarec64_660F_vector(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
addr = retaddr ? retaddr : dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
} else
|
||||
addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog);
|
||||
break;
|
||||
}
|
||||
case 1: addr = dynarec64_66F20F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
case 2: addr = dynarec64_66F30F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
}
|
||||
@@ -154,9 +162,9 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i16 = F16;
|
||||
u64 = F16;
|
||||
ZEXTH(x1, xRAX);
|
||||
MOV32w(x2, i16);
|
||||
MOV64x(x2, u64);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
@@ -185,8 +193,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ZEXTH(x1, xRAX);
|
||||
i16 = F16;
|
||||
MOV64xw(x2, i16);
|
||||
u64 = F16;
|
||||
MOV64x(x2, u64);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
INSH(xRAX, x1, x3, x4, 1, 0);
|
||||
break;
|
||||
@@ -455,8 +463,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -464,8 +472,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -474,8 +482,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -484,8 +492,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -493,8 +501,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -502,8 +510,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -511,8 +519,8 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -520,9 +528,9 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOV64x(x2, i16);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
if(u64) {
|
||||
MOV64x(x2, u64);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
@@ -717,7 +725,37 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SH(xRAX, x1, 0);
|
||||
SMWRITELOCK(lock);
|
||||
break;
|
||||
|
||||
case 0xA4:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1<<F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
LBU(x1, xRSI, 0);
|
||||
SB(x1, xRDI, 0);
|
||||
ADDI(xRSI, xRSI, 1);
|
||||
ADDI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LBU(x1, xRSI, 0);
|
||||
SB(x1, xRDI, 0);
|
||||
SUBI(xRSI, xRSI, 1);
|
||||
SUBI(xRDI, xRDI, 1);
|
||||
SUBI(xRCX, xRCX, 1);
|
||||
BNEZ_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
GETDIR(x3, x1, 1);
|
||||
LBU(x1, xRSI, 0);
|
||||
SB(x1, xRDI, 0);
|
||||
ADD(xRSI, xRSI, x3);
|
||||
ADD(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA5:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
|
||||
@@ -266,7 +266,6 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
sse_forget_reg(dyn, ninst, x5);
|
||||
|
||||
ADDI(x5, xEmu, offsetof(x64emu_t, scratch));
|
||||
|
||||
@@ -350,14 +349,24 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("PHADDSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
MOV64x(x5, 32767);
|
||||
MOV64x(x6, -32768);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// tmp32s = GX->sw[i*2+0]+GX->sw[i*2+1];
|
||||
// GX->sw[i] = sat(tmp32s);
|
||||
LH(x3, gback, gdoffset + 2 * (i * 2 + 0));
|
||||
LH(x4, gback, gdoffset + 2 * (i * 2 + 1));
|
||||
ADDW(x3, x3, x4);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x5);
|
||||
MAX(x3, x3, x6);
|
||||
} else {
|
||||
BLT(x3, x5, 4 + 4);
|
||||
MV(x3, x5);
|
||||
BLT(x6, x3, 4 + 4);
|
||||
MV(x3, x6);
|
||||
}
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
if (MODREG && gd == (nextop & 7) + (rex.b << 3)) {
|
||||
// GX->q[1] = GX->q[0];
|
||||
@@ -371,13 +380,21 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
LH(x3, wback, fixedaddress + 2 * (i * 2 + 0));
|
||||
LH(x4, wback, fixedaddress + 2 * (i * 2 + 1));
|
||||
ADDW(x3, x3, x4);
|
||||
SAT16(x3, x4);
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x5);
|
||||
MAX(x3, x3, x6);
|
||||
} else {
|
||||
BLT(x3, x5, 4 + 4);
|
||||
MV(x3, x5);
|
||||
BLT(x6, x3, 4 + 4);
|
||||
MV(x3, x6);
|
||||
}
|
||||
SH(x3, gback, gdoffset + 2 * (4 + i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PADDUBSW Gx, Ex");
|
||||
INST_NAME("PMADDUBSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
@@ -437,10 +454,10 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
LB(x3, gback, gdoffset + i);
|
||||
LB(x4, wback, fixedaddress + i);
|
||||
BGE(x4, xZR, 4 + 4);
|
||||
NEG(x3, x3);
|
||||
BNE(x4, xZR, 4 + 4);
|
||||
MOV_U12(x3, 0);
|
||||
SLT(x1, xZR, x4);
|
||||
SRAI(x5, x4, 63);
|
||||
OR(x1, x1, x5);
|
||||
MUL(x3, x1, x3);
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -452,10 +469,10 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LH(x3, gback, gdoffset + i * 2);
|
||||
LH(x4, wback, fixedaddress + i * 2);
|
||||
BGE(x4, xZR, 4 + 4);
|
||||
NEG(x3, x3);
|
||||
BNE(x4, xZR, 4 + 4);
|
||||
MOV_U12(x3, 0);
|
||||
SLT(x1, xZR, x4);
|
||||
SRAI(x5, x4, 63);
|
||||
OR(x1, x1, x5);
|
||||
MUL(x3, x1, x3);
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
@@ -467,10 +484,10 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LW(x3, gback, gdoffset + i * 4);
|
||||
LW(x4, wback, fixedaddress + i * 4);
|
||||
BGE(x4, xZR, 4 + 4);
|
||||
NEG(x3, x3);
|
||||
BNE(x4, xZR, 4 + 4);
|
||||
ADDI(x3, xZR, 0);
|
||||
SLT(x1, xZR, x4);
|
||||
SRAI(x5, x4, 63);
|
||||
OR(x1, x1, x5);
|
||||
MUL(x3, x1, x3);
|
||||
SW(x3, gback, gdoffset + i * 4);
|
||||
}
|
||||
break;
|
||||
@@ -494,7 +511,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
sse_forget_reg(dyn, ninst, 0); // forget xmm[0]
|
||||
sse_forget_reg(dyn, ninst, x6, 0); // forget xmm[0]
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
LB(x3, xEmu, offsetof(x64emu_t, xmm[0]) + i);
|
||||
BGE(x3, xZR, 12); // continue
|
||||
@@ -582,7 +599,6 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
MOV64x(x5, ~(1 << 31));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LW(x4, wback, fixedaddress + i * 4);
|
||||
BGE(x4, xZR, 4 + 4);
|
||||
@@ -904,11 +920,11 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
sse_reflect_reg(dyn, ninst, x6, gd);
|
||||
ADDI(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
sse_reflect_reg(dyn, ninst, x6, ed);
|
||||
ADDI(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
@@ -941,7 +957,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
SSE_LOOP_MV_Q(x3);
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesimc, -1);
|
||||
break;
|
||||
@@ -949,7 +965,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("AESENC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aese, -1);
|
||||
GETGX();
|
||||
@@ -960,7 +976,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("AESENCLAST Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aeselast, -1);
|
||||
GETGX();
|
||||
@@ -971,7 +987,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("AESDEC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesd, -1);
|
||||
GETGX();
|
||||
@@ -983,7 +999,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("AESDECLAST Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesdlast, -1);
|
||||
GETGX();
|
||||
@@ -1171,28 +1187,64 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX();
|
||||
GETEX(x2, 1);
|
||||
u8 = F8;
|
||||
sse_forget_reg(dyn, ninst, x5);
|
||||
ADDI(x5, xEmu, offsetof(x64emu_t, scratch));
|
||||
// perserve gd
|
||||
LD(x3, gback, gdoffset + 0);
|
||||
LD(x4, gback, gdoffset + 8);
|
||||
SD(x3, x5, 0);
|
||||
SD(x4, x5, 8);
|
||||
if (u8 > 31) {
|
||||
SD(xZR, gback, gdoffset + 0);
|
||||
SD(xZR, gback, gdoffset + 8);
|
||||
} else if (u8 > 23) {
|
||||
LD(x5, gback, gdoffset + 8);
|
||||
if (u8 > 24) {
|
||||
SRLI(x5, x5, 8 * (u8 - 24));
|
||||
}
|
||||
SD(x5, gback, gdoffset + 0);
|
||||
SD(xZR, gback, gdoffset + 8);
|
||||
} else if (u8 > 15) {
|
||||
if (u8 > 16) {
|
||||
LD(x5, gback, gdoffset + 8);
|
||||
LD(x4, gback, gdoffset + 0);
|
||||
SRLI(x3, x5, 8 * (u8 - 16)); // lower of higher 64 bits
|
||||
SLLI(x5, x5, 8 * (24 - u8)); // higher of lower 64 bits
|
||||
SD(x3, gback, gdoffset + 8);
|
||||
SRLI(x4, x4, 8 * (u8 - 16)); // lower of lower 64 bits
|
||||
OR(x4, x4, x5); // lower 64 bits
|
||||
SD(x4, gback, gdoffset + 0);
|
||||
}
|
||||
} else if (u8 > 7) {
|
||||
if (u8 > 8) {
|
||||
LD(x5, gback, gdoffset + 8);
|
||||
LD(x4, gback, gdoffset + 0);
|
||||
LD(x3, wback, fixedaddress + 8);
|
||||
SLLI(x5, x5, 8 * (16 - u8)); // higher of higher 64 bits
|
||||
SRLI(x1, x4, 8 * (u8 - 8)); // lower of higher 64 bits
|
||||
SLLI(x4, x4, 8 * (16 - u8)); // higher of lower 64 bits
|
||||
OR(x5, x1, x5); // higher 64 bits
|
||||
SRLI(x3, x3, 8 * (u8 - 8)); // lower of lower 64 bits
|
||||
SD(x5, gback, gdoffset + 8);
|
||||
OR(x4, x4, x3); // lower 64 bits
|
||||
SD(x4, gback, gdoffset + 0);
|
||||
} else {
|
||||
LD(x5, gback, gdoffset + 0);
|
||||
LD(x4, wback, fixedaddress + 8);
|
||||
SD(x5, gback, gdoffset + 8);
|
||||
SD(x4, gback, gdoffset + 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 16; ++i, ++u8) {
|
||||
if (u8 > 15) {
|
||||
if (u8 > 31) {
|
||||
SB(xZR, gback, gdoffset + i);
|
||||
continue;
|
||||
} else
|
||||
LBU(x3, x5, u8 - 16);
|
||||
} else {
|
||||
LBU(x3, wback, fixedaddress + u8);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
if (u8 > 0) {
|
||||
LD(x5, gback, gdoffset + 0);
|
||||
LD(x4, wback, fixedaddress + 8);
|
||||
LD(x3, wback, fixedaddress + 0);
|
||||
SLLI(x5, x5, 8 * (8 - u8)); // higher of higher 64 bits
|
||||
SRLI(x1, x4, 8 * (u8 - 0)); // lower of higher 64 bits
|
||||
SLLI(x4, x4, 8 * (8 - u8)); // higher of lower 64 bits
|
||||
OR(x5, x1, x5); // higher 64 bits
|
||||
SRLI(x3, x3, 8 * (u8 - 0)); // lower of lower 64 bits
|
||||
SD(x5, gback, gdoffset + 8);
|
||||
OR(x4, x4, x3); // lower 64 bits
|
||||
SD(x4, gback, gdoffset + 0);
|
||||
} else {
|
||||
LD(x5, wback, fixedaddress + 8);
|
||||
LD(x4, wback, fixedaddress + 0);
|
||||
SD(x5, gback, gdoffset + 8);
|
||||
SD(x4, gback, gdoffset + 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1221,7 +1273,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
SB(ed, gback, gdoffset + u8 & 0xF);
|
||||
SB(ed, gback, gdoffset + (u8 & 0xF));
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("INSERTPS GX, EX, Ib");
|
||||
@@ -1281,11 +1333,11 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
sse_forget_reg(dyn, ninst, x6, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); // p = NULL
|
||||
} else {
|
||||
@@ -1303,11 +1355,11 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("AESKEYGENASSIST Gx, Ex, Ib"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_forget_reg(dyn, ninst, x6, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
sse_forget_reg(dyn, ninst, x6, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); // p = NULL
|
||||
} else {
|
||||
@@ -1698,7 +1750,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(x1, 0);
|
||||
GETGX();
|
||||
SSE_LOOP_DS(x3, x4, SLT(x4, x4, x3); SLLI(x3, x4, 63); SRAI(x3, x3, 63));
|
||||
SSE_LOOP_DS(x3, x4, SLT(x4, x4, x3); NEG(x3, x4));
|
||||
break;
|
||||
case 0x67:
|
||||
INST_NAME("PACKUSWB Gx, Ex");
|
||||
@@ -2250,7 +2302,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shrd16c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
emit_shrd16c(dyn, ninst, rex, ed, gd, u8, x3, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAF:
|
||||
@@ -2368,8 +2420,8 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
XOR(ed, ed, x6);
|
||||
}
|
||||
EWBACK;
|
||||
MARK;
|
||||
EWBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ew, Ib");
|
||||
@@ -2381,7 +2433,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BEXTI(x3, ed, u8); // F_CF is 1
|
||||
ANDI(xFlags, xFlags, ~1);
|
||||
OR(xFlags, xFlags, x3);
|
||||
if (u8 <= 0x10) {
|
||||
if (u8 <= 10) {
|
||||
XORI(ed, ed, (1LL << u8));
|
||||
} else {
|
||||
MOV64xw(x3, (1LL << u8));
|
||||
@@ -2411,9 +2463,14 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
if (rv64_zbs)
|
||||
BEXT_(x4, ed, gd);
|
||||
else {
|
||||
if (rv64_zbs) {
|
||||
if (rex.w) {
|
||||
BEXT_(x4, ed, gd);
|
||||
} else {
|
||||
ANDI(x2, gd, 0xf);
|
||||
BEXT_(x4, ed, x2);
|
||||
}
|
||||
} else {
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0xf);
|
||||
SRL(x4, ed, x2);
|
||||
ANDI(x4, x4, 1);
|
||||
@@ -2495,11 +2552,14 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
MV(x9, ed);
|
||||
if (!(MODREG && wback == xRAX + ((nextop & 0x38) >> 3) + (rex.r << 3)))
|
||||
MV(x9, ed);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
MV(gd, x9);
|
||||
if (!(MODREG && wback == xRAX + ((nextop & 0x38) >> 3) + (rex.r << 3)))
|
||||
MV(gd, x9);
|
||||
EWBACK;
|
||||
GWBACK;
|
||||
if (!(MODREG && wback == xRAX + ((nextop & 0x38) >> 3) + (rex.r << 3)))
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
@@ -2604,13 +2664,13 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
REV8xw(gd, gd, x1, x2, x3, x4);
|
||||
} else {
|
||||
ANDI(x1, gd, 0xff);
|
||||
SLLI(x1, x1, 8);
|
||||
SRLI(x2, gd, 8);
|
||||
SLLI(x1, x1, 8);
|
||||
ANDI(x2, x2, 0xff);
|
||||
SRLI(x3, gd, 16);
|
||||
SLLI(x4, x3, 16);
|
||||
AND(x1, x4, x1);
|
||||
AND(gd, x1, x2);
|
||||
SRLI(gd, gd, 16);
|
||||
OR(x1, x1, x2);
|
||||
SLLI(gd, gd, 16);
|
||||
OR(gd, gd, x1);
|
||||
}
|
||||
break;
|
||||
case 0xD1:
|
||||
@@ -2703,12 +2763,45 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(x2, 0);
|
||||
GETGD;
|
||||
MV(gd, xZR);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
LB(x1, wback, fixedaddress + i);
|
||||
SLT(x3, x1, xZR);
|
||||
if (i > 0) SLLI(x3, x3, i);
|
||||
OR(gd, gd, x3);
|
||||
LD(x1, wback, fixedaddress + 8); // high part
|
||||
LD(x2, wback, fixedaddress + 0); // low part, also destroyed wback(x2)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (rv64_zbs) {
|
||||
if (i == 0) {
|
||||
BEXTI(gd, x1, 63);
|
||||
} else {
|
||||
BEXTI(x6, x1, 63 - i * 8);
|
||||
}
|
||||
} else {
|
||||
if (i == 0) {
|
||||
SRLI(gd, x1, 63);
|
||||
} else {
|
||||
SRLI(x6, x1, 63 - i * 8);
|
||||
ANDI(x6, x6, 1);
|
||||
}
|
||||
}
|
||||
if (i != 0) {
|
||||
if (rv64_zba) {
|
||||
SH1ADD(gd, gd, x6);
|
||||
} else {
|
||||
SLLI(gd, gd, 1);
|
||||
OR(gd, gd, x6);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (rv64_zbs) {
|
||||
BEXTI(x6, x2, 63 - i * 8);
|
||||
} else {
|
||||
SRLI(x6, x2, 63 - i * 8);
|
||||
ANDI(x6, x6, 1);
|
||||
}
|
||||
if (rv64_zba) {
|
||||
SH1ADD(gd, gd, x6);
|
||||
} else {
|
||||
SLLI(gd, gd, 1);
|
||||
OR(gd, gd, x6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -2720,9 +2813,13 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
LBU(x3, gback, gdoffset + i);
|
||||
LBU(x4, wback, fixedaddress + i);
|
||||
SUB(x3, x3, x4);
|
||||
NOT(x4, x3);
|
||||
SRAI(x4, x4, 63);
|
||||
AND(x3, x3, x4);
|
||||
if (rv64_zbb) {
|
||||
MAX(x3, x3, xZR);
|
||||
} else {
|
||||
NOT(x4, x3);
|
||||
SRAI(x4, x4, 63);
|
||||
AND(x3, x3, x4);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -2731,7 +2828,17 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
SSE_LOOP_W(x3, x4, SUB(x3, x3, x4); NOT(x4, x3); SRAI(x4, x4, 63); AND(x3, x3, x4));
|
||||
SSE_LOOP_W(x3, x4,
|
||||
SUB(x3, x3, x4);
|
||||
if (rv64_zbb) {
|
||||
MAX(x3, x3, xZR);
|
||||
} else {
|
||||
NOT(x4, x3);
|
||||
SRAI(x4, x4, 63);
|
||||
AND(x3, x3, x4);
|
||||
}
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
);
|
||||
break;
|
||||
case 0xDA:
|
||||
INST_NAME("PMINUB Gx, Ex");
|
||||
@@ -2741,8 +2848,12 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
LBU(x3, gback, gdoffset + i);
|
||||
LBU(x4, wback, fixedaddress + i);
|
||||
BLTU(x3, x4, 8);
|
||||
MV(x3, x4);
|
||||
if (rv64_zbb) {
|
||||
MINU(x3, x3, x4);
|
||||
} else {
|
||||
BLTU(x3, x4, 8);
|
||||
MV(x3, x4);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -2763,8 +2874,12 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
LBU(x3, gback, gdoffset + i);
|
||||
LBU(x4, wback, fixedaddress + i);
|
||||
ADD(x3, x3, x4);
|
||||
BLT(x3, x5, 8);
|
||||
ADDI(x3, xZR, 0xFF);
|
||||
if (rv64_zbb) {
|
||||
MINU(x3, x3, x5);
|
||||
} else {
|
||||
BLT(x3, x5, 8);
|
||||
ADDI(x3, xZR, 0xFF);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -2773,15 +2888,19 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
MOV32w(x5, 65535);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
// tmp32s = (int32_t)GX->uw[i] + EX->uw[i];
|
||||
// GX->uw[i] = (tmp32s>65535)?65535:tmp32s;
|
||||
LHU(x3, gback, gdoffset + i * 2);
|
||||
LHU(x4, wback, fixedaddress + i * 2);
|
||||
ADDW(x3, x3, x4);
|
||||
MOV32w(x4, 65536);
|
||||
BLT(x3, x4, 8);
|
||||
ADDIW(x3, x4, -1);
|
||||
if (rv64_zbb) {
|
||||
MINU(x3, x3, x5);
|
||||
} else {
|
||||
BGE(x5, x3, 8); // tmp32s <= 65535?
|
||||
MV(x3, x5);
|
||||
}
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
@@ -2793,8 +2912,12 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
LBU(x3, gback, gdoffset + i);
|
||||
LBU(x4, wback, fixedaddress + i);
|
||||
BLTU(x4, x3, 8);
|
||||
MV(x3, x4);
|
||||
if (rv64_zbb) {
|
||||
MAXU(x3, x3, x4);
|
||||
} else {
|
||||
BLTU(x4, x3, 8);
|
||||
MV(x3, x4);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -2934,22 +3057,23 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
ADDI(x5, xZR, 0x7f);
|
||||
ADDI(x6, xZR, 0xf80);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
// tmp16s = (int16_t)GX->sb[i] - EX->sb[i];
|
||||
// GX->sb[i] = (tmp16s<-128)?-128:((tmp16s>127)?127:tmp16s);
|
||||
LB(x3, gback, gdoffset + i);
|
||||
LB(x4, wback, fixedaddress + i);
|
||||
SUBW(x3, x3, x4);
|
||||
SLLIW(x3, x3, 16);
|
||||
SRAIW(x3, x3, 16);
|
||||
ADDI(x4, xZR, 0x7f);
|
||||
BLT(x3, x4, 12); // tmp16s>127?
|
||||
SB(x4, gback, gdoffset + i);
|
||||
J(24); // continue
|
||||
ADDI(x4, xZR, 0xf80);
|
||||
BLT(x4, x3, 12); // tmp16s<-128?
|
||||
SB(x4, gback, gdoffset + i);
|
||||
J(8); // continue
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x5);
|
||||
MAX(x3, x3, x6);
|
||||
} else {
|
||||
BLT(x3, x5, 4 + 4);
|
||||
MV(x3, x5);
|
||||
BLT(x6, x3, 4 + 4);
|
||||
MV(x3, x6);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -2958,14 +3082,24 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
MOV64x(x5, 32767);
|
||||
MOV64x(x6, -32768);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
// tmp32s = (int32_t)GX->sw[i] - EX->sw[i];
|
||||
// GX->sw[i] = sat16(tmp32s);
|
||||
LH(x3, gback, gdoffset + 2 * i);
|
||||
LH(x4, wback, fixedaddress + 2 * i);
|
||||
SUBW(x3, x3, x4);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x5);
|
||||
MAX(x3, x3, x6);
|
||||
} else {
|
||||
BLT(x3, x5, 4 + 4);
|
||||
MV(x3, x5);
|
||||
BLT(x6, x3, 4 + 4);
|
||||
MV(x3, x6);
|
||||
}
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
case 0xEA:
|
||||
@@ -2976,8 +3110,12 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LH(x3, gback, gdoffset + 2 * i);
|
||||
LH(x4, wback, fixedaddress + 2 * i);
|
||||
BLT(x3, x4, 8);
|
||||
MV(x3, x4);
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x4);
|
||||
} else {
|
||||
BLT(x3, x4, 8);
|
||||
MV(x3, x4);
|
||||
}
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
}
|
||||
break;
|
||||
@@ -2993,22 +3131,23 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
MOV64x(x5, 127);
|
||||
MOV64x(x6, -128);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
// tmp16s = (int16_t)GX->sb[i] + EX->sb[i];
|
||||
// GX->sb[i] = (tmp16s>127)?127:((tmp16s<-128)?-128:tmp16s);
|
||||
LB(x3, gback, gdoffset + i);
|
||||
LB(x4, wback, fixedaddress + i);
|
||||
ADDW(x3, x3, x4);
|
||||
SLLIW(x3, x3, 16);
|
||||
SRAIW(x3, x3, 16);
|
||||
ADDI(x4, xZR, 0x7f);
|
||||
BLT(x3, x4, 12); // tmp16s>127?
|
||||
SB(x4, gback, gdoffset + i);
|
||||
J(24); // continue
|
||||
ADDI(x4, xZR, 0xf80);
|
||||
BLT(x4, x3, 12); // tmp16s<-128?
|
||||
SB(x4, gback, gdoffset + i);
|
||||
J(8); // continue
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x5);
|
||||
MAX(x3, x3, x6);
|
||||
} else {
|
||||
BLT(x3, x5, 4 + 4);
|
||||
MV(x3, x5);
|
||||
BLT(x6, x3, 4 + 4);
|
||||
MV(x3, x6);
|
||||
}
|
||||
SB(x3, gback, gdoffset + i);
|
||||
}
|
||||
break;
|
||||
@@ -3017,14 +3156,24 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
MOV64x(x5, 32767);
|
||||
MOV64x(x6, -32768);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
// tmp32s = (int32_t)GX->sw[i] + EX->sw[i];
|
||||
// GX->sw[i] = sat16(tmp32s);
|
||||
LH(x3, gback, gdoffset + 2 * i);
|
||||
LH(x4, wback, fixedaddress + 2 * i);
|
||||
ADDW(x3, x3, x4);
|
||||
SAT16(x3, x4);
|
||||
SH(x3, gback, gdoffset + 2 * i);
|
||||
if (rv64_zbb) {
|
||||
MIN(x3, x3, x5);
|
||||
MAX(x3, x3, x6);
|
||||
} else {
|
||||
BLT(x3, x5, 4 + 4);
|
||||
MV(x3, x5);
|
||||
BLT(x6, x3, 4 + 4);
|
||||
MV(x3, x6);
|
||||
}
|
||||
SH(x3, gback, gdoffset + i * 2);
|
||||
}
|
||||
break;
|
||||
case 0xEE:
|
||||
@@ -3032,7 +3181,14 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0);
|
||||
SSE_LOOP_WS(x3, x4, BGE(x3, x4, 8); MV(x3, x4));
|
||||
SSE_LOOP_WS(x3, x4,
|
||||
if (rv64_zbb) {
|
||||
MAX(x3, x3, x4);
|
||||
} else {
|
||||
BGE(x3, x4, 8);
|
||||
MV(x3, x4);
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx, Ex");
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "bitutils.h"
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
uintptr_t dynarec64_660F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8, s8;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2, gback;
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1, d2;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
switch (opcode) {
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx, Ex");
|
||||
nextop = F8;
|
||||
// FIXME: we should try to minimize vsetvl usage as it may hurts performance a lot.
|
||||
vector_vsetvl_emul1(dyn, ninst, x1, VECTOR_SEW8);
|
||||
|
||||
GETG;
|
||||
if (MODREG && gd == (nextop & 7) + (rex.b << 3)) {
|
||||
// special case
|
||||
q0 = sse_get_reg_empty_vector(dyn, ninst, x1, gd);
|
||||
VXOR_VV(q0, q0, q0, VECTOR_UNMASKED);
|
||||
} else {
|
||||
q0 = sse_get_reg_vector(dyn, ninst, x1, gd, 1);
|
||||
GETEX_vector(q1, 0, 0);
|
||||
VXOR_VV(q0, q0, q1, VECTOR_UNMASKED);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// fallback to the scalar version
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -33,6 +33,7 @@ uintptr_t dynarec64_66F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
uint64_t u64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(gb1);
|
||||
@@ -127,9 +128,9 @@ uintptr_t dynarec64_66F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
MOV64x(x5, u64);
|
||||
ZEXTH(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4, x2);
|
||||
SRLI(ed, ed, 16);
|
||||
@@ -137,8 +138,8 @@ uintptr_t dynarec64_66F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
OR(ed, ed, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) u64 = F16; else u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
|
||||
ANDI(x3, wback, 0b10);
|
||||
BNEZ_MARK(x3);
|
||||
@@ -192,4 +193,4 @@ uintptr_t dynarec64_66F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ uintptr_t dynarec64_D9(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if(i2) {
|
||||
ADDI(x3, x3, i2);
|
||||
}
|
||||
MOV32w(x4, 0b100000100000000);
|
||||
MOV32w(x4, 0b100000100000000); // empty: C3,C2,C0 = 101
|
||||
BGE_MARK3(xZR, x3);
|
||||
// x5 will be the actual top
|
||||
LWU(x5, xEmu, offsetof(x64emu_t, top));
|
||||
@@ -152,11 +152,17 @@ uintptr_t dynarec64_D9(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
// load tag
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
MOV32w(x4, 0b100000100000000);
|
||||
if (i2 < 0) {
|
||||
SLLI(x3, x3, -i2 * 2);
|
||||
} else if (i2 > 0) {
|
||||
LUI(x2, 0xffff0);
|
||||
OR(x3, x3, x2);
|
||||
SRLI(x3, x3, i2 * 2);
|
||||
}
|
||||
ANDI(x2, x3, 0b11);
|
||||
BNEZ_MARK3(x2); // empty: C3,C2,C0 = 101
|
||||
// load x2 with ST0 anyway, for sign extraction
|
||||
if(rv64_zba) SH3ADD(x1, x2, xEmu); else {SLLI(x2, x2, 3); ADD(x1, xEmu, x2);}
|
||||
if(rv64_zba) SH3ADD(x1, x5, xEmu); else {SLLI(x5, x5, 3); ADD(x1, xEmu, x5);}
|
||||
LD(x2, x1, offsetof(x64emu_t, x87));
|
||||
}
|
||||
} else {
|
||||
@@ -186,7 +192,6 @@ uintptr_t dynarec64_D9(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MARK3;
|
||||
// Extract signa & Update SW
|
||||
SRLI(x1, x2, 63);
|
||||
ANDI(x4, x4, ~(1<<9));
|
||||
SLLI(x1, x1, 9);
|
||||
OR(x4, x4, x1); //C1
|
||||
LHU(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
|
||||
@@ -151,6 +151,33 @@ uintptr_t dynarec64_DF(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SH(x4, wback, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FSFLAGSI(0); // reset all bits
|
||||
}
|
||||
if (ST_IS_F(0)) {
|
||||
FCVTWS(x4, v1, RD_DYN);
|
||||
} else {
|
||||
FCVTWD(x4, v1, RD_DYN);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if(!box64_dynarec_fastround) {
|
||||
FRFLAGS(x5); // get back FPSR to check the IOC bit
|
||||
ANDI(x5, x5, 1<<FR_NV);
|
||||
BNEZ_MARK(x5);
|
||||
SLLIW(x5, x4, 16);
|
||||
SRAIW(x5, x5, 16);
|
||||
BEQ_MARK2(x5, x4);
|
||||
MARK;
|
||||
MOV32w(x4, 0x8000);
|
||||
}
|
||||
MARK2;
|
||||
SH(x4, wback, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, EXT_CACHE_ST_F);
|
||||
@@ -179,6 +206,15 @@ uintptr_t dynarec64_DF(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SH(x4, wback, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if(ed != x1) { MV(x1, ed); }
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbld, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, EXT_CACHE_ST_I64);
|
||||
|
||||
@@ -422,7 +422,7 @@ void emit_and32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
MOV64xw(s3, c);
|
||||
AND(s1, s1, s3); // res = s1 & s2
|
||||
}
|
||||
if (!rex.w && c<0 && c>=-2048) ZEROUP(s1);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
|
||||
@@ -710,14 +710,15 @@ void emit_shl32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
if (!c) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
} else SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
@@ -725,12 +726,10 @@ void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
|
||||
IFX(X_CF|X_OF) {
|
||||
if (c > 0) {
|
||||
SRLI(s3, s1, (rex.w?64:32)-c);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX(X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
SRLI(s3, s1, (rex.w?64:32)-c);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX(X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,7 +822,10 @@ void emit_shr32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
if (!c) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS();
|
||||
|
||||
@@ -837,12 +839,6 @@ void emit_shr32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI(s3, s1, c-1);
|
||||
@@ -891,7 +887,10 @@ void emit_shr32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
if (!c) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS();
|
||||
|
||||
@@ -905,12 +904,6 @@ void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI(s3, s1, c-1);
|
||||
@@ -970,7 +963,12 @@ void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
if(rv64_zbb) {
|
||||
ROLxw(s1, s1, s4);
|
||||
if (rex.w) {
|
||||
ROL(s1, s1, s4);
|
||||
} else {
|
||||
ROLW(s1, s1, s4);
|
||||
ZEROUP(s1);
|
||||
}
|
||||
} else {
|
||||
SLLxw(s3, s1, s4);
|
||||
NEG(s4, s4);
|
||||
@@ -1021,7 +1019,12 @@ void emit_ror32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
if(rv64_zbb) {
|
||||
RORxw(s1, s1, s4);
|
||||
if (rex.w) {
|
||||
ROR(s1, s1, s4);
|
||||
} else {
|
||||
RORW(s1, s1, s4);
|
||||
ZEROUP(s1);
|
||||
}
|
||||
} else {
|
||||
SRLxw(s3, s1, s4);
|
||||
NEG(s4, s4);
|
||||
@@ -1055,7 +1058,10 @@ void emit_ror32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
if (!c) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX(X_CF | X_OF) {
|
||||
ANDI(xFlags, xFlags, ~(1UL<<F_CF | 1UL<<F_OF2));
|
||||
@@ -1068,12 +1074,6 @@ void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(rv64_zbb) {
|
||||
RORIxw(s1, s1, (rex.w?64:32)-c);
|
||||
} else if (rv64_xtheadbb) {
|
||||
@@ -1107,7 +1107,10 @@ void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
if (!c) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX(X_CF | X_OF) {
|
||||
ANDI(xFlags, xFlags, ~(1UL<<F_CF | 1UL<<F_OF2));
|
||||
@@ -1120,12 +1123,6 @@ void emit_ror32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(rv64_zbb) {
|
||||
RORIxw(s1, s1, c);
|
||||
} else if (rv64_xtheadbb) {
|
||||
@@ -1175,6 +1172,7 @@ void emit_shrd32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
SET_DFNONE();
|
||||
}
|
||||
if(!c) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1227,9 +1225,9 @@ void emit_shrd32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
}
|
||||
}
|
||||
|
||||
void emit_shrd16c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4)
|
||||
void emit_shrd16c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
c&=15;
|
||||
c&=0x1f;
|
||||
CLEAR_FLAGS();
|
||||
|
||||
IFX(X_PEND) {
|
||||
@@ -1248,6 +1246,11 @@ void emit_shrd16c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// create concat first
|
||||
SLLI(s5, s2, 16);
|
||||
OR(s1, s1, s5);
|
||||
|
||||
IFX(X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI(s3, s1, c-1);
|
||||
@@ -1263,9 +1266,13 @@ void emit_shrd16c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
if (c == 1) SRLI(s4, s1, 15);
|
||||
}
|
||||
|
||||
SRLIxw(s3, s1, c);
|
||||
SLLIxw(s1, s2, 16-c);
|
||||
OR(s1, s1, s3);
|
||||
if (rv64_zbb) {
|
||||
RORIW(s1, s1, c);
|
||||
} else {
|
||||
SRLI(s5, s1, c);
|
||||
SLLI(s1, s1, 32 - c);
|
||||
OR(s1, s1, s5);
|
||||
}
|
||||
ZEXTH(s1, s1);
|
||||
|
||||
IFX(X_SF) {
|
||||
@@ -1311,6 +1318,9 @@ void emit_shld32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
}
|
||||
|
||||
if(!c) {
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1429,6 +1439,7 @@ void emit_shld32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
MOV32w(s3, (rex.w?64:32));
|
||||
SUB(s3, s3, s5);
|
||||
IFX(X_CF) {
|
||||
@@ -1475,7 +1486,7 @@ void emit_shld32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
|
||||
void emit_shld16c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
c&=15;
|
||||
c&=0x1f;
|
||||
CLEAR_FLAGS();
|
||||
IFX(X_PEND) {
|
||||
if (c) {
|
||||
@@ -1494,21 +1505,32 @@ void emit_shld16c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// create concat first
|
||||
SLLI(s5, s2, 16);
|
||||
OR(s1, s1, s5);
|
||||
|
||||
IFX(X_CF) {
|
||||
if (c > 0) {
|
||||
if (c < 16) {
|
||||
SRLI(s3, s1, 16-c);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s5);
|
||||
} else {
|
||||
SRLI(s3, s2, 32-c);
|
||||
}
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
// Store sign for later use.
|
||||
if (c == 1) SRLI(s5, s1, 15);
|
||||
}
|
||||
|
||||
SLLIxw(s3, s1, c);
|
||||
SRLIxw(s1, s2, 16-c);
|
||||
OR(s1, s1, s3);
|
||||
if (rv64_zbb) {
|
||||
RORIW(s1, s1, 32 - c);
|
||||
} else {
|
||||
SLLI(s3, s1, c);
|
||||
SRLI(s1, s1, 32 - c);
|
||||
OR(s1, s1, s3);
|
||||
}
|
||||
ZEXTH(s1, s1);
|
||||
|
||||
IFX(X_SF) {
|
||||
|
||||
@@ -230,12 +230,12 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
// Unaligned
|
||||
ANDI(x5, wback, -(1 << (rex.w + 2)));
|
||||
MARK2; // Use MARK2 as a "MARKLOCK" since we're running out of marks.
|
||||
LDxw(x6, wback, 0);
|
||||
LRxw(x1, x5, 1, 1);
|
||||
SUBxw(x3, x6, xRAX);
|
||||
LDxw(x1, wback, 0);
|
||||
LRxw(x6, x5, 1, 1);
|
||||
SUBxw(x3, x1, xRAX);
|
||||
BNEZ_MARK(x3);
|
||||
// EAX == Ed
|
||||
SCxw(x4, x1, x5, 1, 1);
|
||||
SCxw(x4, x6, x5, 1, 1);
|
||||
BNEZ_MARK2(x4);
|
||||
SDxw(gd, wback, 0);
|
||||
MARK;
|
||||
@@ -550,7 +550,7 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if (i64 < -2048 || i64 >= 2048)
|
||||
MOV64xw(x4, i64);
|
||||
MOV64xw(x9, i64);
|
||||
ANDI(x1, wback, (1 << (rex.w + 2)) - 1);
|
||||
BNEZ_MARK3(x1);
|
||||
// Aligned
|
||||
@@ -559,7 +559,7 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (i64 >= -2048 && i64 < 2048)
|
||||
ADDIxw(x4, x1, i64);
|
||||
else
|
||||
ADDxw(x4, x1, x4);
|
||||
ADDxw(x4, x1, x9);
|
||||
SCxw(x3, x4, wback, 1, 1);
|
||||
BNEZ_MARKLOCK(x3);
|
||||
B_MARK_nocond;
|
||||
@@ -572,7 +572,7 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (i64 >= -2048 && i64 < 2048)
|
||||
ADDIxw(x4, x6, i64);
|
||||
else
|
||||
ADDxw(x4, x6, x4);
|
||||
ADDxw(x4, x6, x9);
|
||||
SCxw(x3, x1, x5, 1, 1);
|
||||
BNEZ_MARK2(x3);
|
||||
SDxw(x4, wback, 0);
|
||||
@@ -596,13 +596,14 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if (i64 < -2048 || i64 >= 2048)
|
||||
MOV64xw(x9, i64);
|
||||
MARKLOCK;
|
||||
LRxw(x1, wback, 1, 1);
|
||||
if (i64>=-2048 && i64<2048) {
|
||||
if (i64 >= -2048 && i64 < 2048) {
|
||||
ORI(x4, x1, i64);
|
||||
} else {
|
||||
MOV64xw(x4, i64);
|
||||
OR(x4, x1, x4);
|
||||
OR(x4, x1, x9);
|
||||
}
|
||||
if (!rex.w) ZEROUP(x4);
|
||||
SCxw(x3, x4, wback, 1, 1);
|
||||
@@ -625,13 +626,14 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if (i64 < -2048 || i64 >= 2048)
|
||||
MOV64xw(x9, i64);
|
||||
MARKLOCK;
|
||||
LRxw(x1, wback, 1, 1);
|
||||
if (i64>=-2048 && i64<2048) {
|
||||
if (i64 >= -2048 && i64 < 2048) {
|
||||
ANDI(x4, x1, i64);
|
||||
} else {
|
||||
MOV64xw(x4, i64);
|
||||
AND(x4, x1, x4);
|
||||
AND(x4, x1, x9);
|
||||
}
|
||||
if (!rex.w) ZEROUP(x4);
|
||||
SCxw(x3, x4, wback, 1, 1);
|
||||
@@ -654,18 +656,39 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if (i64 <= -2048 || i64 > 2048)
|
||||
MOV64xw(x9, i64);
|
||||
ANDI(x1, wback, (1 << (rex.w + 2)) - 1);
|
||||
BNEZ_MARK3(x1);
|
||||
// Aligned
|
||||
MARKLOCK;
|
||||
LRxw(x1, wback, 1, 1);
|
||||
if (i64>-2048 && i64<=2048) {
|
||||
if (i64 > -2048 && i64 <= 2048) {
|
||||
ADDIxw(x4, x1, -i64);
|
||||
} else {
|
||||
MOV64xw(x4, i64);
|
||||
SUBxw(x4, x1, x4);
|
||||
SUBxw(x4, x1, x9);
|
||||
}
|
||||
SCxw(x3, x4, wback, 1, 1);
|
||||
BNEZ_MARKLOCK(x3);
|
||||
IFX(X_ALL|X_PEND)
|
||||
B_MARK_nocond;
|
||||
MARK3;
|
||||
// Unaligned
|
||||
ANDI(x5, wback, -(1 << (rex.w + 2)));
|
||||
MARK2; // Use MARK2 as a "MARKLOCK" since we're running out of marks.
|
||||
LDxw(x6, wback, 0);
|
||||
LRxw(x1, x5, 1, 1);
|
||||
if (i64 > -2048 && i64 <= 2048) {
|
||||
ADDIxw(x4, x6, -i64);
|
||||
} else {
|
||||
SUBxw(x4, x6, x9);
|
||||
}
|
||||
SCxw(x3, x1, x5, 1, 1);
|
||||
BNEZ_MARK2(x3);
|
||||
SDxw(x4, wback, 0);
|
||||
MARK;
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5, x6);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 6: // XOR
|
||||
@@ -688,13 +711,14 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64 < -2048 || i64 >= 2048)
|
||||
MOV64xw(x9, i64);
|
||||
MARKLOCK;
|
||||
LRxw(x1, wback, 1, 1);
|
||||
if (i64 >= -2048 && i64 <= 2047) {
|
||||
if (i64 >= -2048 && i64 < 2048) {
|
||||
XORI(x4, x1, i64);
|
||||
} else {
|
||||
MOV64xw(x4, i64);
|
||||
XOR(x4, x1, x4);
|
||||
XOR(x4, x1, x9);
|
||||
}
|
||||
SCxw(x3, x4, wback, 1, 1);
|
||||
BNEZ_MARKLOCK(x3);
|
||||
|
||||
Loaded 100 of 274 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user