mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-07 17:43:14 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb716a2a65 | ||
|
|
7dec0819b5 | ||
|
|
b05cb3ab54 | ||
|
|
dea645b38d | ||
|
|
707a141e0d | ||
|
|
14181b503b | ||
|
|
9a67cb9355 | ||
|
|
39d3ed2033 | ||
|
|
646fc2d3a8 | ||
|
|
0579f8b9c4 | ||
|
|
50a2603027 | ||
|
|
10224524df | ||
|
|
0886bb79c4 | ||
|
|
fa14e0ab14 | ||
|
|
ac48800fbb | ||
|
|
b197194e2d | ||
|
|
2796d6ef92 | ||
|
|
d60937b1ac | ||
|
|
d0aad67ba0 | ||
|
|
66fc843ae8 | ||
|
|
7e56375859 | ||
|
|
c13b3cc9cd | ||
|
|
ba5b9e9954 | ||
|
|
fa59e748f9 | ||
|
|
c467c05112 | ||
|
|
bb164a299f | ||
|
|
eaf2e84e19 | ||
|
|
7dcba89c71 | ||
|
|
5c5639be09 | ||
|
|
ee0c949bc2 | ||
|
|
d9402213f6 | ||
|
|
efe8bb4e6c | ||
|
|
ec278bd784 | ||
|
|
f1559b066c | ||
|
|
c9d20f60c8 | ||
|
|
512f0a6c92 | ||
|
|
1c280bd8a0 | ||
|
|
20432122de | ||
|
|
e754df0fb1 | ||
|
|
b9d565f444 | ||
|
|
58f1b5d1e3 | ||
|
|
f921c0cdbe | ||
|
|
1e749beb2e | ||
|
|
4caece4c0c | ||
|
|
d6b76922e7 | ||
|
|
69a021454a | ||
|
|
336dc5b676 | ||
|
|
450347f099 | ||
|
|
30c72e23bd | ||
|
|
ce0b4d1884 | ||
|
|
72d934b34c | ||
|
|
4e8d4a2bff | ||
|
|
c993aacd04 | ||
|
|
a7855d3bcb | ||
|
|
7b8a6aa91d | ||
|
|
c65c514882 | ||
|
|
62bc6bb1f3 | ||
|
|
0504c042f4 | ||
|
|
54c806c576 | ||
|
|
55e08ab0be | ||
|
|
e717b959c6 | ||
|
|
f97763cacd | ||
|
|
fc43e4c22b | ||
|
|
b01829b7d6 | ||
|
|
d1fcdee8a8 | ||
|
|
56b23e0668 | ||
|
|
d927dae7e7 | ||
|
|
a49c286214 | ||
|
|
80e092ae44 | ||
|
|
05017f46d2 | ||
|
|
0caa80f9f1 | ||
|
|
66a91b8580 | ||
|
|
bcd36a3152 | ||
|
|
6aba6364c4 | ||
|
|
0cf5179d7f | ||
|
|
3c9823198c | ||
|
|
664956aaa0 | ||
|
|
9811f140ce | ||
|
|
26ddd6e9ef | ||
|
|
c5bccdf300 | ||
|
|
4b20581753 | ||
|
|
a4f38779eb | ||
|
|
27c21f6979 | ||
|
|
e14d8abb61 | ||
|
|
54ed80f68a | ||
|
|
a187c7ccd3 | ||
|
|
f6a5322cf3 | ||
|
|
5da8235b18 | ||
|
|
21e9a43d21 | ||
|
|
dcc0355113 | ||
|
|
666b5a6ce6 | ||
|
|
fcbebfa8c8 | ||
|
|
9354744f68 | ||
|
|
fc0b51f3b8 | ||
|
|
cd88702516 | ||
|
|
223fa8ea17 | ||
|
|
d3d971d449 | ||
|
|
2e589f42fe | ||
|
|
96a34a2a40 | ||
|
|
69f0c979d4 | ||
|
|
ff702c0318 | ||
|
|
968fc3fcfe | ||
|
|
4abaa3d835 | ||
|
|
121c67655b | ||
|
|
9f8b96b749 | ||
|
|
a9c50ef238 | ||
|
|
984da28f40 | ||
|
|
a8babcba8d | ||
|
|
13c7029de5 | ||
|
|
148722dac4 | ||
|
|
dd5bba2aac | ||
|
|
b044c19329 | ||
|
|
fb1dbb3821 | ||
|
|
4f21d83e62 | ||
|
|
b145080d37 | ||
|
|
0829c14a73 | ||
|
|
4141748f9a | ||
|
|
25e1d8bae8 | ||
|
|
79e622a839 | ||
|
|
932045054f | ||
|
|
f5f1e1413d | ||
|
|
24f2c68805 | ||
|
|
7748d10246 | ||
|
|
22ee4685a1 | ||
|
|
35ea6fd109 | ||
|
|
3744603bcc | ||
|
|
4861b78dc4 | ||
|
|
ba017657ad | ||
|
|
811c4fccd8 | ||
|
|
3992ab5931 | ||
|
|
266392e315 | ||
|
|
83e550b122 | ||
|
|
b5f2b9c936 | ||
|
|
82f610faee | ||
|
|
ec77755952 | ||
|
|
14c9cb148d | ||
|
|
f48aeaac60 | ||
|
|
74eb4ed9d5 | ||
|
|
68503a37cf | ||
|
|
49e6609182 | ||
|
|
966bb72e9e | ||
|
|
14b978a568 | ||
|
|
8378f9b307 | ||
|
|
9dc0f8243a | ||
|
|
eaeacc6706 | ||
|
|
031dba2904 | ||
|
|
f8229ea561 | ||
|
|
e5bfe84394 | ||
|
|
5e926a266f | ||
|
|
29e97a88a2 | ||
|
|
a94e8ed659 | ||
|
|
b013c86338 | ||
|
|
29926438a8 | ||
|
|
87097f437b | ||
|
|
35f266ea94 | ||
|
|
88fd555ef0 | ||
|
|
107d792ab1 | ||
|
|
30f364f166 | ||
|
|
e259ffcf66 | ||
|
|
027605e4d5 | ||
|
|
2c58b45d8e | ||
|
|
159351fc3c | ||
|
|
d4cf4ee521 | ||
|
|
7d90fff7cd | ||
|
|
68dcf9d0bf | ||
|
|
d89c10415a | ||
|
|
99310cc9c6 | ||
|
|
57d126cddc | ||
|
|
2b35400dc5 | ||
|
|
d1d899babd | ||
|
|
fe112fece8 | ||
|
|
74a338df94 | ||
|
|
f2496984d5 | ||
|
|
3ebcc84d52 | ||
|
|
c878264ede | ||
|
|
fbf3e1b1cc | ||
|
|
e23d2167b4 | ||
|
|
3d485c6159 | ||
|
|
9af5916104 | ||
|
|
80e93dcee4 | ||
|
|
90f21fb710 | ||
|
|
41a8bc0da9 | ||
|
|
06e40a2379 | ||
|
|
78104d1b5f | ||
|
|
9626291470 | ||
|
|
6f4a8fbd5d | ||
|
|
f191228318 | ||
|
|
7c3730f4e6 | ||
|
|
772aca08b8 | ||
|
|
0f19b73dfe | ||
|
|
b7dccd065f | ||
|
|
57c1ed7118 | ||
|
|
5a348e1de9 | ||
|
|
76a5f3b7c9 | ||
|
|
c317bf94c8 | ||
|
|
cbe0ef830b | ||
|
|
5c54463c32 | ||
|
|
531ccfaf6a | ||
|
|
339af4a13e | ||
|
|
d4f7ec6ee4 | ||
|
|
2de4ce82f3 | ||
|
|
d2f033e97a | ||
|
|
c2375d030b | ||
|
|
786680a288 | ||
|
|
0883cdc9ac | ||
|
|
e35d6d22a4 | ||
|
|
14a53affc0 | ||
|
|
18e8b06dfb | ||
|
|
ac8ae8f0ec | ||
|
|
274fe75017 | ||
|
|
278d8fe8d9 | ||
|
|
dcf89339b8 | ||
|
|
1c3c3a209a | ||
|
|
d91ac13592 | ||
|
|
aafa791f4a | ||
|
|
3b08ace904 | ||
|
|
fefa13f655 | ||
|
|
949e7b7809 | ||
|
|
7fe38de5f6 | ||
|
|
9803591643 | ||
|
|
d87033837b | ||
|
|
507b68358f | ||
|
|
1b721a536e | ||
|
|
77706f8142 | ||
|
|
8a71575487 | ||
|
|
dd0a57ab30 | ||
|
|
07b0f6673a | ||
|
|
88e84a6c1c | ||
|
|
767e94aae1 | ||
|
|
0c211a0164 | ||
|
|
be6e2fe1da | ||
|
|
d94dce18c5 | ||
|
|
a0f180e86b | ||
|
|
8f2fe64afc | ||
|
|
d64248b1f8 | ||
|
|
cc67b01aa8 | ||
|
|
90a18265b9 | ||
|
|
08f8d8d721 | ||
|
|
df2504f976 | ||
|
|
117fe48b5e | ||
|
|
e02844fb93 | ||
|
|
ca1f0d0cf2 | ||
|
|
2e6bc42a49 | ||
|
|
cf2e754447 | ||
|
|
708986a3c6 | ||
|
|
e8fabe23ec | ||
|
|
fa2374a7a7 | ||
|
|
a70e5d7aa7 | ||
|
|
e87915bcfb | ||
|
|
c540942294 | ||
|
|
3869cc2bc0 | ||
|
|
f3ddb6bcf4 | ||
|
|
26f30a3c09 | ||
|
|
b831475d1b | ||
|
|
431eb604e4 | ||
|
|
0d2bf2fe30 | ||
|
|
94f9f5d0b5 | ||
|
|
8349acb93a | ||
|
|
8c00a1100f | ||
|
|
0cdd36bac6 | ||
|
|
fd3dcf3873 | ||
|
|
72d3098ba4 | ||
|
|
177abf2e44 | ||
|
|
077764251d | ||
|
|
90fbf7237f | ||
|
|
d9ec366ce4 | ||
|
|
c854b23d35 | ||
|
|
fd137915b6 | ||
|
|
dad0e5ef2f | ||
|
|
5abf1fa24e | ||
|
|
b5bc46e13a | ||
|
|
c39a8ebd51 | ||
|
|
38d35cbef0 | ||
|
|
3058fefe93 | ||
|
|
f03d09b949 | ||
|
|
2343533b41 | ||
|
|
fa2f3c0577 | ||
|
|
6c28b3584e | ||
|
|
8fa5ec74ec | ||
|
|
868ad666ed | ||
|
|
150b035a1b | ||
|
|
fdd775790a | ||
|
|
68ff10a18e | ||
|
|
3f072c8aa8 | ||
|
|
7b0c1689bb | ||
|
|
6946198045 | ||
|
|
8f76973fcf | ||
|
|
b9ded7320a | ||
|
|
fc14382a07 | ||
|
|
35cc9af4ff | ||
|
|
0c2d9acd99 | ||
|
|
9c0ecf0427 | ||
|
|
10529d007c | ||
|
|
ac356fc146 | ||
|
|
0b584bbb48 | ||
|
|
c10b105f5f | ||
|
|
236de084ea | ||
|
|
72e917bb06 | ||
|
|
0d64ab09bb | ||
|
|
ff0b7683e7 | ||
|
|
d210f12f25 | ||
|
|
87d346230c | ||
|
|
47c65e1e3a | ||
|
|
57440bd102 | ||
|
|
389c803929 | ||
|
|
08d8407056 | ||
|
|
3f12bde9ff | ||
|
|
a47a9d95d7 | ||
|
|
f2a4125ab8 | ||
|
|
2d3f244935 | ||
|
|
2a1342c5b3 | ||
|
|
82bf0a99d2 | ||
|
|
c6275bcb62 | ||
|
|
7a175a9733 | ||
|
|
75759f9ba7 | ||
|
|
6f966fe468 | ||
|
|
f716212932 | ||
|
|
4b1b214663 | ||
|
|
5e7a7db60d | ||
|
|
968da3a4d4 | ||
|
|
347c645e95 | ||
|
|
e50f152355 | ||
|
|
59f85c8fbb | ||
|
|
9fbab85232 | ||
|
|
a0a3389651 | ||
|
|
6e51e73a1e | ||
|
|
35e64fd56c | ||
|
|
402496c93e | ||
|
|
84d415c211 | ||
|
|
020b2ba8d0 | ||
|
|
2890c05fba | ||
|
|
829d39f8a3 | ||
|
|
197cdafa22 | ||
|
|
aa75d5a434 | ||
|
|
38b8d9b8a5 | ||
|
|
a1091a9a72 | ||
|
|
8d1561f6e5 | ||
|
|
375bc45b51 | ||
|
|
334b891364 | ||
|
|
a8f3d57afb | ||
|
|
3023c8262d | ||
|
|
bc166ae3b3 | ||
|
|
4e29df8a56 | ||
|
|
e24c1f048b | ||
|
|
daef5cbdc9 | ||
|
|
699af54183 | ||
|
|
731d9a249d | ||
|
|
3e67c4573b | ||
|
|
ef25a75b86 | ||
|
|
c4b182048c | ||
|
|
6079f39655 | ||
|
|
2dcd2741c7 | ||
|
|
399b2c7f8a | ||
|
|
7ae3200c6f | ||
|
|
299ddb22a5 | ||
|
|
df8930a78a | ||
|
|
a37cd0bd91 | ||
|
|
ee10226614 | ||
|
|
ad934455c1 | ||
|
|
c0e7062b03 | ||
|
|
04d03af8ac |
No files matched your search
@@ -14,7 +14,7 @@ on:
|
||||
- GENERIC_ARM
|
||||
- A64
|
||||
- GAMESHELL
|
||||
- ODROID
|
||||
- ODROIDXU4
|
||||
- PANDORA
|
||||
- PHYTIUM
|
||||
- PYRA
|
||||
@@ -23,6 +23,9 @@ on:
|
||||
- RPI4
|
||||
- RPI4ARM64
|
||||
- SD845
|
||||
- SD888
|
||||
- ADLINK
|
||||
- PHYTIUM
|
||||
build_type:
|
||||
description: 'Build type'
|
||||
required: true
|
||||
|
||||
@@ -27,23 +27,23 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM, ANDROID]
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROIDXU4, RK3399, RK3288, A64, SD845, SD888, ADLINK, PHYTIUM, ANDROID]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
- platform: TEGRAX1
|
||||
type: Trace
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
- platform: TEGRAX1ARM32
|
||||
type: Release
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
- platform: TEGRAX1ARM32
|
||||
type: Trace
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -57,10 +57,10 @@ jobs:
|
||||
if [[ ${{ matrix.platform }} != 'I386' && ${{ matrix.platform }} != 'OTHER_ARM' ]]; then
|
||||
sudo apt-get -y install git cmake make python3
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
|
||||
unzip android-ndk-r23b-linux.zip
|
||||
echo "BOX86_COMPILER=$PWD/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-DANDROID=1 -DNOLOADADDR=1" >> $GITHUB_ENV
|
||||
wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip
|
||||
unzip android-ndk-r25b-linux.zip
|
||||
echo "BOX86_COMPILER=$PWD/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=ON -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
ctest -j$(nproc)
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box86-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box86
|
||||
|
||||
+184
-35
@@ -11,19 +11,25 @@ option(GOA_CLONE "Set to ON if targeting GO Advance clones, like RG351p/v, Gamef
|
||||
option(RK3288 "Set to ON if targeting an Rockchip RK3288 based device" ${RK3288})
|
||||
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
|
||||
option(RK3588 "Set to ON if targeting an Rockchip RK3588 / RK3588S based device" ${RK3588})
|
||||
option(ODROIDN2 "Set to ON if targeting an Odroid-N2 device" ${ODROIDN2})
|
||||
option(ODROIDN2 "Set to ON if targeting an ODROID-N2 device" ${ODROIDN2})
|
||||
option(TEGRAX1 "Set to ON if targeting an Tegra X1 (ARM64) based device" ${TEGRAX1})
|
||||
option(TEGRAX1ARM32 "Set to ON if targeting an Tegra X1 (ARM32) based device" ${TEGRAX1ARM32})
|
||||
option(TEGRA_T194 "Set to ON if targeting an Tegra Xavier based device" ${TEGRA_T194})
|
||||
option(TEGRA_T234 "Set to ON if targeting an Tegra Orin based device" ${TEGRA_T234})
|
||||
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
|
||||
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
|
||||
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
|
||||
option(ODROIDXU4 "Set to ON if targeting an ODROID-XU4 device" ${ODROIDXU4})
|
||||
option(POWER9 "Set to ON if targeting a POWER9 processor" ${POWER9})
|
||||
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
|
||||
option(SD845 "Set to ON if targeting a Snapdragon 845 based device" ${SD845})
|
||||
option(SD865 "Set to ON if targeting a Snapdragon 865 based device" ${SD865})
|
||||
option(SD888 "Set to ON if targeting a Snapdragon 888 based device" ${SD888})
|
||||
option(ADLINK "Set to ON if targeting an ADLink AmpereAltra based device" ${ADLINK})
|
||||
option(A64 "Set to ON if targeting an Allwinner A64 based device" ${A64})
|
||||
option(ARM64 "Set to ON if targeting a generic ARM64 based device" ${ARM64})
|
||||
option(BAD_SIGNAL "Set to ON to activate the workaround for incoherent si_info on SIGSEGV" ${BAD_SIGNAL})
|
||||
option(LX2160A "Set to ON if targeting an LX2160A based device" ${LX2160A})
|
||||
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(TERMUX "Set to ON if targeting an Android device with Termux" ${TERMUX})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
@@ -32,7 +38,7 @@ option(NOGIT "Set to ON if not building from a git clone repo (like when buildin
|
||||
option(NO_LIB_INSTALL "Set ON to not install a few x86 libs that are used by many program" ${NO_LIB_INSTALL})
|
||||
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
|
||||
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRAX1ARM32 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64 OR LX2160A OR ARM64 OR RK3588)
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROIDXU4 OR GOA_CLONE OR RK3288 OR RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRAX1ARM32 OR TEGRA_T194 OR TEGRA_T234 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR SD865 OR SD888 OR ADLINK OR A64 OR LX2160A OR ARM64 OR RK3588)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
@@ -40,8 +46,13 @@ if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE O
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
endif()
|
||||
if(TERMUX)
|
||||
set(ANDROID ON CACHE BOOL "")
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
@@ -66,21 +77,29 @@ else()
|
||||
endif()
|
||||
|
||||
cmake_host_system_information(RESULT CMAKE_HOST_SYSTEM_PROCESSOR QUERY OS_PLATFORM)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "armhf" _armhf)
|
||||
|
||||
if(_aarch64 AND (RK3399 OR ODROIDN2 OR TEGRAX1 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64 OR LX2160A OR RK3588 OR ARM64))
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
#set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as) #will use gcc in fact
|
||||
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
|
||||
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "aarch64" AND (RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR SD888 OR ADLINK OR A64 OR LX2160A OR RK3588 OR ARM64))
|
||||
set(COMPILER_TRIPLE arm-linux-gnueabihf-gcc)
|
||||
find_program(COMPILER_FOUND ${COMPILER_TRIPLE})
|
||||
|
||||
if(COMPILER_FOUND)
|
||||
set(CMAKE_C_COMPILER ${COMPILER_FOUND})
|
||||
else()
|
||||
message(STATUS "Cross compiler ${COMPILER_TRIPLE} not found, using CC or -DCMAKE_C_COMPILER")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(box86 C ASM)
|
||||
|
||||
enable_testing()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "armhf" _armhf)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "arm" _arm)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "armv8l" _armv8l)
|
||||
|
||||
set(default_build_type "RelwithDebInfo")
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
@@ -125,10 +144,10 @@ elseif(RPI4ARM64)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ODROID)
|
||||
add_definitions(-DODROID)
|
||||
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
elseif(ODROIDXU4)
|
||||
add_definitions(-DODROIDXU4)
|
||||
add_definitions(-marm -mcpu=cortex-a15.cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a15.cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
elseif(RK3288)
|
||||
add_definitions(-DRK3288)
|
||||
add_definitions(-mcpu=cortex-a17 -mfpu=neon -mfloat-abi=hard -marm)
|
||||
@@ -137,6 +156,19 @@ elseif(SD845)
|
||||
add_definitions(-DSD845)
|
||||
add_definitions(-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(SD865)
|
||||
add_definitions(-DSD865)
|
||||
#note that cortex-a77.cortex-a55 is not supported, so fall back to a76 instead
|
||||
add_definitions(-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(SD888)
|
||||
add_definitions(-DSD888)
|
||||
add_definitions(-marm -march=armv8.4-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.4-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ADLINK)
|
||||
add_definitions(-DADLINK)
|
||||
add_definitions(-marm -mcpu=neoverse-n1 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=neoverse-n1 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(A64)
|
||||
add_definitions(-DA64)
|
||||
add_definitions(-marm -march=armv8-a+crc+simd+crypto -mcpu=cortex-a53+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
@@ -170,6 +202,14 @@ elseif(TEGRAX1ARM32)
|
||||
add_definitions(-DTEGRAX1ARM32)
|
||||
add_definitions(-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(TEGRA_T194)
|
||||
add_definitions(-DTEGRA_T194)
|
||||
add_definitions(-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a76+crypto -mtune=cortex-a76 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a76+crypto -mtune=cortex-a76 -mfloat-abi=hard")
|
||||
elseif(TEGRA_T234)
|
||||
add_definitions(-DTEGRA_T234)
|
||||
add_definitions(-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae -mfloat-abi=hard")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
@@ -178,13 +218,18 @@ elseif(LX2160A)
|
||||
add_definitions(-DLX2160A)
|
||||
add_definitions(-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
elseif(ARM_DYNAREC)
|
||||
#if DYNAREC is selected alone, without any arch
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
|
||||
if(NOT ANDROID)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
|
||||
endif()
|
||||
endif()
|
||||
if(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
endif()
|
||||
if(TERMUX)
|
||||
add_definitions(-DTERMUX)
|
||||
endif()
|
||||
|
||||
if(BAD_SIGNAL)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
endif()
|
||||
@@ -205,6 +250,12 @@ else()
|
||||
set(BOX86 box86)
|
||||
endif()
|
||||
|
||||
try_compile(HAVE_ST_INO ${CMAKE_BINARY_DIR}/compile_tests ${CMAKE_SOURCE_DIR}/tests/test_st_ino.c)
|
||||
|
||||
if(HAVE_ST_INO)
|
||||
message("stat64 has __st_info field")
|
||||
add_definitions(-DHAVE_ST_INO)
|
||||
endif()
|
||||
|
||||
set(BOX86_ELF_ADDRESS "0x62800000")
|
||||
|
||||
@@ -290,6 +341,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/tools/my_cpuid.c"
|
||||
"${BOX86_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX86_ROOT}/src/tools/rcfile.c"
|
||||
"${BOX86_ROOT}/src/tools/rbtree.c"
|
||||
"${BOX86_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfparser.c"
|
||||
@@ -299,6 +351,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/librarian/dictionnary.c"
|
||||
"${BOX86_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX86_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX86_ROOT}/src/emu/x86compstrings.c"
|
||||
"${BOX86_ROOT}/src/emu/x86emu.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x86syscall.c"
|
||||
@@ -310,6 +363,8 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign64.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalignsys64.c"
|
||||
"${BOX86_ROOT}/src/libtools/stat64_helper.c"
|
||||
"${BOX86_ROOT}/src/libtools/myfts.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
|
||||
@@ -334,6 +389,7 @@ set(INTERPRETER
|
||||
"${BOX86_ROOT}/src/emu/x86run660f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66d9.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66dd.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66f20f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run67.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6766.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rund8.c"
|
||||
@@ -354,8 +410,10 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibgl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibglx.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
@@ -413,6 +471,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedopencl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
@@ -467,6 +526,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedayatanaappindicator3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
@@ -519,6 +579,8 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibfuse.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatomic.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpcre.c"
|
||||
)
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
@@ -548,7 +610,7 @@ add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX86_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "--"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "TERMUX" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -666,7 +728,11 @@ else()
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
if(ANDROID)
|
||||
if(TERMUX)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl android-sysv-semaphore android-spawn)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl rt pthread resolv)
|
||||
endif()
|
||||
@@ -688,6 +754,11 @@ add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
if(ANDROID)
|
||||
if(TERMUX)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl android-complex-math android-sysv-semaphore android-spawn )
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl)
|
||||
endif()
|
||||
target_link_libraries(${BOX86} c m dl)
|
||||
else()
|
||||
#target_link_libraries(${BOX86} c m dl rt pthread resolv)
|
||||
@@ -701,30 +772,59 @@ endif()
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS}")
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,--image-base,${BOX86_ELF_ADDRESS}")
|
||||
else()
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS}")
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS -rdynamic)
|
||||
endif()
|
||||
else()
|
||||
target_link_options(${BOX86} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
target_link_options(${BOX86} PUBLIC -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS})
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
target_link_options(${BOX86} PUBLIC -Wl,--image-base,${BOX86_ELF_ADDRESS})
|
||||
else()
|
||||
target_link_options(${BOX86} PUBLIC -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX86}
|
||||
if(NOT TERMUX)
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION bin)
|
||||
else()
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION ${TERMUX_PATH}/usr/bin)
|
||||
endif()
|
||||
if(NOT NO_CONF_INSTALL)
|
||||
configure_file(system/box86.conf.cmake system/box86.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION /etc/)
|
||||
if(NOT TERMUX)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION /etc/)
|
||||
else()
|
||||
#install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION ${TERMUX_PATH}/usr/etc/)
|
||||
endif()
|
||||
endif()
|
||||
set(INSTALL_PATH "/usr/lib/box86-i386-linux-gnu/")
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
if(NOT TERMUX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
else()
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libunwind.so.8 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -742,7 +842,11 @@ set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Box86 - Linux Userspace x86 Emulator with a twist")
|
||||
if(TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libandroid-sysv-semaphore, libandroid-spawn")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
endif()
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
|
||||
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_MAJOR\\s*")
|
||||
string(REGEX REPLACE "BOX86_MAJOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
@@ -756,16 +860,29 @@ string(REGEX MATCH "[0-9]" BOX86_REVISION ${TEMP_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX86_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${BOX86_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${BOX86_REVISION})
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
if(_aarch64 OR _armhf)
|
||||
endif()
|
||||
if(_aarch64 OR _armhf OR _arm OR _armv8l)
|
||||
if(TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf")
|
||||
endif()
|
||||
elseif(_x86_64 OR _x86)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "i386")
|
||||
else()
|
||||
#probably wrong...
|
||||
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
endif()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
if(TERMUX)
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX "${TERMUX_PATH}/usr")
|
||||
endif()
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_${CMAKE_SYSTEM_NAME}-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
else()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_Termux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
endif()
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
@@ -872,20 +989,52 @@ add_test(NAME idiv COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
add_test(NAME multiple_dlopen COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21 -D TEST_OUTPUT=tmpfile21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME aes COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22 -D TEST_OUTPUT=tmpfile22.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
add_test(NAME sse_optimized COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17_o2 -D TEST_OUTPUT=tmpfile17_o2.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17_o2.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_optimized PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTNAN=0;BOX86_DYNAREC_FASTROUND=0")
|
||||
set_tests_properties(sse_optimized PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTNAN=0;BOX86_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23 -D TEST_OUTPUT=tmpfile23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24 -D TEST_OUTPUT=tmpfile24.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25 -D TEST_OUTPUT=tmpfile25.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fpu_rounding ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26 -D TEST_OUTPUT=tmpfile26.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTROUND=0")
|
||||
|
||||
endif(BOX86LIB)
|
||||
Vendored
+66
@@ -1,3 +1,69 @@
|
||||
box86 (0.3.8) unstable; urgency=low
|
||||
* Some optimisation of x86 P flags handling
|
||||
* Some x87 fixes and improvments
|
||||
* Added some of the tim64 wrapped functions to libc and friends
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Some fixes to internal memory tracking
|
||||
* Some more Vulkan extensions wrapped
|
||||
* Better handling of BOX86_MAXCPU
|
||||
* Some changes and improvments on Signal handling
|
||||
* More wrapped functions, and fix to some existing ones
|
||||
* A few more syscall, and fix to some existing ones
|
||||
* New build profile for SD865
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Fri, 06 Dec 2024 14:06:00 -0100
|
||||
|
||||
box86 (0.3.6) unstable; urgency=low
|
||||
* Wrapping: More libs and and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs
|
||||
* Some more profiles in box86rc
|
||||
* More SSE3+ opcodes in dynarec
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
* => should improve games stability
|
||||
* Better handling of large block in the dynarec
|
||||
* => should speedup dynarec, and allow use of BIGBLOCK 2 or 3 on more software
|
||||
* Added suport for BOX86_DYNAREC_CALLRET optimisation.
|
||||
* => backported from box64, can give 10% or more speed increase (but can also decrease speed in some cases). Still a bit crashy so use with care.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
|
||||
box86 (0.3.4) unstable; urgency=low
|
||||
|
||||
* X86Libs: Updated libstdc++ & libgcc_s
|
||||
* X86Libs: Use x86 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support for ADLink Ampere Altra
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* => Mostly a stability update with improved elfloader again, and added SSE 4.2 support (still need to work on the Dynarec part of this)
|
||||
* => Some work also to reduce the memory footprint
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
|
||||
box86 (0.3.2) unstable; urgency=low
|
||||
|
||||
* Better syscall handling
|
||||
* Fixed some wrapped functions, added some others
|
||||
* Introduced another wrapper helper
|
||||
* Added some more opcodes
|
||||
* Added a cosimulation mode (to compare the behaviour of the dynarec against the interpreter)
|
||||
* Added support of FASTNAN for some more opcodes
|
||||
* Reduced memory footprint
|
||||
* Added BOX86_NOSANDBOX (adds an argument to the command line)
|
||||
* Added an ukrainian translation
|
||||
* => Mostly a stability update with improved elfloader, fixed opcodes and refined profiles
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box86 (0.3.0) unstable; urgency=low
|
||||
|
||||
* Added rcfile handling: box86 now read "/etc/box86.box86rc" and "~/.box86rc" and apply per process parameters
|
||||
|
||||
Vendored
+6
-1
@@ -10,4 +10,9 @@ 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=libunwind.so.8
|
||||
@@ -1,3 +1,54 @@
|
||||
v0.3.8
|
||||
======
|
||||
* Some optimisation of x86 P flags handling
|
||||
* Some x87 fixes and improvments
|
||||
* Added some of the tim64 wrapped functions to libc and friends
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Some fixes to internal memory tracking
|
||||
* Some more Vulkan extensions wrapped
|
||||
* Better handling of BOX86_MAXCPU
|
||||
* Some changes and improvments on Signal handling
|
||||
* More wrapped functions, and fix to some existing ones
|
||||
* A few more syscall, and fix to some existing ones
|
||||
* New build profile for SD865
|
||||
|
||||
v0.3.6
|
||||
======
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs
|
||||
* Some more profiles in box86rc
|
||||
* More SSE3+ opcodes in dynarec
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Better handling of the Hardware Counter and TSC emulation
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* PageSize detection and handling dynamic. Larger than 4K pagesize will be handled automaticaly. Note that box64 does not emulate 4K page size, so some program might still refuse to work on larger page (like Wine for example)
|
||||
=> Linux Games can now load even on a 16K pagesize machine like a mac M1, and games (including Unity3D ones) can be played with no issues.
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
=> should improve games stability
|
||||
* Better handling of large block in the dynarec
|
||||
=> should speedup dynarec, and allow use of BIGBLOCK 2 or 3 on more software
|
||||
* Added suport for BOX86_DYNAREC_CALLRET optimisation.
|
||||
=> backported from box64, can give 10% or more speed increase (but can also decrease speed in some cases). Still a bit crashy so use with care.
|
||||
|
||||
v0.3.4
|
||||
======
|
||||
* X86Libs: Updated libstdc++ & libgcc_s
|
||||
* X86Libs: Use x86 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support for ADLink Ampere Altra
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
=> Mostly a stability update with improved elfloader again, and added SSE 4.2 support (still need to work on the Dynarec part of this)
|
||||
=> Some work also to reduce the memory footprint
|
||||
|
||||
v0.3.2
|
||||
======
|
||||
* Better syscall handling
|
||||
|
||||
+68
-17
@@ -1,18 +1,21 @@
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
#### Debian-based Linux
|
||||
You can use [@Itai-Nelken](https://github.com/Itai-Nelken)'s apt repository to install precompiled box86 debs, updated weekly.
|
||||
If you don't want to compile box86 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://itai-nelken.github.io/weekly-box86-debs/debian/box86.list -O /etc/apt/sources.list.d/box86.list
|
||||
wget -qO- https://itai-nelken.github.io/weekly-box86-debs/debian/KEY.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/box86-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box86 -y
|
||||
You can also generate your own debian package using the [instructions below](https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Important note, if you are using a 64bits OS, you need to have multi-arch enabled, with armhf support, for box86 to works. On Debian/Ubuntu/Armbian OS, you need to do:
|
||||
|
||||
```bash
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update
|
||||
sudo apt-get install libc6:armhf -y
|
||||
```
|
||||
|
||||
**Note:** On a 64bit OS, install the `box86:armhf` package.
|
||||
And of course you will need to install much more library to be able to run software and games (like X11, mesa, SDL, pulseaudio...)
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md#debian-packaging).
|
||||
## Per-platform compiling instructions
|
||||
----
|
||||
|
||||
#### for Pandora
|
||||
|
||||
@@ -60,9 +63,9 @@ sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for ODROID
|
||||
#### for ODROID-XU3/XU4/MC1/HC1/HC2
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
`mkdir build; cd build; cmake .. -DODROIDXU4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### for RK3399
|
||||
|
||||
@@ -80,11 +83,11 @@ As most RK3588 devices run an AARCH64 OS, you'll need an `armhf` multiarch envir
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for ODROID N2/N2+
|
||||
#### for ODROID-N2/N2+
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROIDN2=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most ODROID N2/N2+ devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most ODROID-N2/N2+ devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
@@ -100,11 +103,13 @@ As most Allwinner A64 devices run an AARCH64 OS, you'll need an `armhf` multiarc
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Snapdragon 845
|
||||
#### for Snapdragon
|
||||
|
||||
`mkdir build; cd build; cmake .. -DSD845=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
or
|
||||
`mkdir build; cd build; cmake .. -DSD888=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Snapdragon 845 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
Depending how old/recent you SD is. As most Snapdragon devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Phytium
|
||||
|
||||
@@ -115,6 +120,12 @@ As most Phytium (D2000 or FT2000/4) devices run an AARCH64 OS, you'll need an `a
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for ADLink AmpereAltra
|
||||
|
||||
`mkdir build; cd build; cmake .. -DADLINK=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j`
|
||||
|
||||
As ADLINK AmpereAltra computers run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Other ARM64 64bits Linux platform
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
@@ -156,6 +167,7 @@ To have a trace enabled build (***the interpreter will be slightly slower***), a
|
||||
#### to have ARM Dynarec
|
||||
|
||||
###### *Note: VFPv3 and NEON are required for Dynarec.*
|
||||
###### You might need to `sudo apt install neon-support` package for CMAKE to correctly detect them.
|
||||
|
||||
###### *Note: Compiling with `ARM_DYNAREC` without selecting a hardware profile is not advised.*
|
||||
|
||||
@@ -163,7 +175,7 @@ Dynarec is only available on the ARM architecture (for the meantime anyways). Ac
|
||||
|
||||
You will most likely need `-marm` in compilation flags (Many compilers default to the Thumb instruction set and Dynarec does not support this).
|
||||
|
||||
###### *Note: If you get error building that "target CPU does not support ARM mode", then try to pick a hardware profile (like ODROID for armv7 or PI4 for armv8).*
|
||||
###### *Note: If you get error building that "target CPU does not support ARM mode", then try to pick a hardware profile (like ODROIDXU4 for armv7 or PI4 for armv8).*
|
||||
|
||||
##### 64bit OS with Dynarec
|
||||
|
||||
@@ -176,7 +188,7 @@ If you are not building from a git clone (for example, downloading a release sou
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
## Testing
|
||||
----
|
||||
A few tests are included with box86.
|
||||
|
||||
@@ -192,7 +204,46 @@ NVIDIA doesn't provide armhf libraries for their GPU drivers at this time. There
|
||||
|
||||
----
|
||||
|
||||
Debian Packaging
|
||||
## Debian Packaging
|
||||
----
|
||||
Box86 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/box86-debs) to install precompiled box86 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
# check if .list file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box86.list ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box86.list || exit 1
|
||||
fi
|
||||
# check if .sources file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box86.sources ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box86.sources || exit 1
|
||||
fi
|
||||
# download gpg key from specified url
|
||||
if [ -f /usr/share/keyrings/box86-archive-keyring.gpg ]; then
|
||||
sudo rm -f /usr/share/keyrings/box86-archive-keyring.gpg
|
||||
fi
|
||||
sudo mkdir -p /usr/share/keyrings
|
||||
wget -qO- "https://pi-apps-coders.github.io/box86-debs/KEY.gpg" | sudo gpg --dearmor -o /usr/share/keyrings/box86-archive-keyring.gpg
|
||||
# create .sources file
|
||||
echo "Types: deb
|
||||
URIs: https://Pi-Apps-Coders.github.io/box86-debs/debian
|
||||
Suites: ./
|
||||
Signed-By: /usr/share/keyrings/box86-archive-keyring.gpg" | sudo tee /etc/apt/sources.list.d/box86.sources >/dev/null
|
||||
```
|
||||
|
||||
On a 32bit OS, run the following additional commands
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install box86-generic-arm -y
|
||||
```
|
||||
|
||||
On a 64bit OS, run the following additional commands
|
||||
```
|
||||
sudo dpkg --add-architecture armhf
|
||||
sudo apt update
|
||||
sudo apt install box86-generic-arm:armhf -y
|
||||
```
|
||||
+7
-12
@@ -28,8 +28,8 @@ Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86
|
||||
----
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
> Compilation instructions can be found [here](https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](https://github.com/ptitSeb/box86/blob/master/docs/X86WINE.md)
|
||||
|
||||
----
|
||||
|
||||
@@ -80,8 +80,8 @@ Notes about Box86 configuration
|
||||
----
|
||||
|
||||
Box86 now have configurations files. There are 2 files loaded. `/etc/box4.box86rc` and `~/.box86rc`. 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. Box86 comes with a default file that should be installed for better stability. The file in in `system/box86.box86rc` and should be installed to `/etc/box86.box86rc` If, for some reasons, you don't want to install that file here, at least copy it to `~/.box86rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.bashrc` > `/etc/box86.box86rc` > command line
|
||||
So, your settings in `~/.bashrc` may override the setting from your command line...
|
||||
Note that the priority is: `~/.box86rc` > `/etc/box86.box86rc` > command line
|
||||
So, your settings in `~/.box86rc` may override the setting from your command line...
|
||||
|
||||
----
|
||||
|
||||
@@ -104,12 +104,7 @@ Final note: the Steam BigPicture will work, but also need steamwebhelper (and so
|
||||
- If you have trouble installing Steam, you can find `install_steam.sh` in the root folder of the box86 repo. This simple script will download and install steam in your home folder, and then create a shortcut to steam in `/usr/local/bin` (and for this it will ask for sudo permission). Simply use `steam` to launch once it's installed. Note that the installation, being in the Home folder, will only work for a single user. Don't use this script if you need a multi-user installation.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables (it's automatically there if you used the `install_steam.sh` script)
|
||||
|
||||
to disable `steamwebhelper` when box64 installed and running, create (or edit) `~/.box64rc` and add:
|
||||
```
|
||||
[steamwebhelper]
|
||||
BOX64_EXIT=1
|
||||
```
|
||||
in it and it will be disable. Comment with a `#` those 2 lines to enable it again
|
||||
If you have issue with steam starting, with `steamwebhelper` not starting, you'll need to start steam with `-cef-disable-gpu` or `-cef-disable-gpu-compositor`.
|
||||
|
||||
----
|
||||
|
||||
@@ -134,8 +129,8 @@ I want to thank everyone who has contributed to box86 development.
|
||||
There are many ways to contribute: code, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, icecream95, M-HT
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For their hardware contribution: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/), [AYN](https://www.ayntec.com/)
|
||||
* For their continuous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
And I also thank the many other people who participated even once in the project.
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ Box86已经封装了Vulkan。如果设备的系统有32位的Vulkan驱动程序
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, icecream95, M-HT
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* 硬件捐赠:[ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* 为本项目持续的宣传:([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
+3
-8
@@ -2,7 +2,7 @@
|
||||
|
||||
Емулятор простіра користувача x86_64 із родзинкою
|
||||
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Українська](https://github.com/ptitSeb/box86/blob/master/docs/README_UK.md) | [Повідомити про помилку](https://github.com/ptitSeb/box86/issues/new)
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [Повідомити про помилку](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
@@ -104,12 +104,7 @@ Linux версія Steam тепер може працювати з Box86, але
|
||||
- Якщо у вас виникли проблеми зі встановленням Steam, ви можете знайти `install_steam.sh` у кореневій папці сховища box86. Цей простий скрипт завантажить і встановить Steam у вашу домашню папку, а потім створить ярлик steam у `/usr/local/bin` (для цього він запитає дозвіл sudo). Просто використовуйте `steam` для запуску після встановлення. Зауважте, що інсталяція, яка знаходиться в папці Home, працюватиме лише для одного користувача. Не використовуйте цей скрипт, якщо вам потрібна багатокористувацька інсталяція.
|
||||
- Щоб уникнути повідомлення «libc.so.6 відсутній», ви можете використовувати `STEAMOS=1` і `STEAM_RUNTIME=1` як змінні середовища (воно автоматично з’являється, якщо ви використовували сценарій `install_steam.sh`)
|
||||
|
||||
Щоб вимкнути `steamwebhelper`, коли Box64 встановлений і працює, створіть (або відредагуйте) `~/.box64rc` і додайте у ньому:
|
||||
```
|
||||
[steamwebhelper]
|
||||
BOX64_EXIT=1
|
||||
```
|
||||
І тоді `steamwebhelper` буде вимкнено. Прокоментуйте `#` ці 2 рядки, щоб увімкнути його знову.
|
||||
Якщо у вас виникла проблема із запуском Steam (не запускається `steamwebhelper`), вам потрібно запустити Steam за допомогою `-cef-disable-gpu` або `-cef-disable-gpu-compositor`.
|
||||
|
||||
----
|
||||
|
||||
@@ -135,7 +130,7 @@ Box86 вже використовує Vulkan. Якщо у вашій систе
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, icecream95, M-HT
|
||||
* За великий фінансовий внесок: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За внесок у апаратне забезпечення: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [Команда TwisterOS](https://twisteros.com/)
|
||||
* За внесок у апаратне забезпечення: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [Команда TwisterOS](https://twisteros.com/)
|
||||
* За постійну рекламу Box86: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[Команда TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у проекті.
|
||||
|
||||
+47
-15
@@ -30,7 +30,7 @@ Disables Box86 printing its version and build
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH *
|
||||
Path to look for x86 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exist.
|
||||
Also, `/usr/lib/i386-linux-gnu`, `/lib/i386-linux-gnu`, and `/usr/lib/box86-i386-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX86_PATH *
|
||||
Path to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
@@ -146,8 +146,9 @@ Define Box86's Dynarec max allowed forward value when building Block.
|
||||
#### BOX86_DYNAREC_STRONGMEM *
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
* 1 : Enable some Memory Barrier when writting to memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : All 1. plus a memory barrier on every write to memory using MOV
|
||||
* 3 : All 2. plus Memory Barrier when reading from memory and on some SSE/SSE2 opcodes too
|
||||
|
||||
#### BOX86_DYNAREC_X87DOUBLE *
|
||||
Force the use of Double for x87 emulation
|
||||
@@ -161,8 +162,8 @@ Enable/Disable generation of -NAN
|
||||
|
||||
#### BOX86_DYNAREC_FASTROUND *
|
||||
Enable/Disable generation of precise x86 rounding
|
||||
* 0 : Generate float/double -> int rounding like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion) (faster, Default)
|
||||
* 0 : Generate float/double -> int rounding and use current rounding mode for float/double compution like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion, and no set rounding mode) (faster, Default)
|
||||
|
||||
#### BOX86_DYNAREC_SAFEFLAGS *
|
||||
Handling of flags on CALL/RET opcodes
|
||||
@@ -170,15 +171,10 @@ Handling of flags on CALL/RET opcodes
|
||||
* 1 : most of RET will need flags, most of CALLS will not (Default)
|
||||
* 2 : All CALL/RET will need flags (slower, but might be needed. Automatically enabled for Vara.exe)
|
||||
|
||||
#### BOX86_DYNAREC_HOTPAGE *
|
||||
Handling of HotPage (Page beeing both executed and writen)
|
||||
* 0 : Don't track hotpage
|
||||
* 1-255 : Trak HotPage, and disable execution of a page beeing writen for N attempts (default is 16)
|
||||
|
||||
#### BOX86_DYNAREC_FASTPAGE *
|
||||
Will use a faster handling of HotPage (Page being both executed and written)
|
||||
* 0 : use regular hotpage (Default)
|
||||
* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash)
|
||||
#### BOX86_DYNAREC_CALLRET *
|
||||
Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
* 0 : Don't optimize CALL/RET, use Jump Table for boths (Default)
|
||||
* 1 : Try to optimized CALL/RET, skipping the use of the JumpTable when possible
|
||||
|
||||
#### BOX86_DYNAREC_BLEEDING_EDGE *
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
@@ -195,6 +191,11 @@ Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is n
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
#### BOX86_DYNAREC_MISSING *
|
||||
Dynarec print the missing opcodes
|
||||
* 0 : not print the missing opcode (Default, unless DYNAREC_LOG>=1 or DYNAREC_DUMP>=1 is used)
|
||||
* 1 : Will print the missing opcodes
|
||||
|
||||
#### BOX86_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
* 0 : Just track the flag (Default)
|
||||
@@ -205,11 +206,26 @@ Handling of x87 80bits long double
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
#### BOX86_MAXCPU
|
||||
Maximum CPU Core exposed
|
||||
* 0 : Don't cap the number of cpu core exposed (Default)
|
||||
* XXX : Cap the maximum CPU Core exposed to XXX (usefull with wine64 or GridAutosport for example)
|
||||
|
||||
#### BOX86_LIBCEF *
|
||||
Detect libcef and apply malloc_hack settings
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
#### BOX86_SDL2_JGUID *
|
||||
Need a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2
|
||||
* 0 : Don't use any workaround
|
||||
* 1 : Use a workaround for program that use the private SDL_GetJoystickGUIDInfo function with 1 missing argument
|
||||
|
||||
#### BOX86_MUTEX_ALIGNED *
|
||||
Will mutex are used as-is or wrapped to handle unaligned used
|
||||
* 0 : Mutex will be wrapped in case unaligned mutexes are used (Default)
|
||||
* 1 : Do no wrap mutex and use them as-is (faster, but might crash with SEGBUS error)
|
||||
|
||||
#### BOX86_LIBGL *
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
@@ -259,6 +275,16 @@ Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX86_NOCRASHHANDLER *
|
||||
Diables crashhandler.so
|
||||
* 0 : Regular process for crashhandler.so (Default)
|
||||
* 1 : Do not load crashhandler.so, even if present
|
||||
|
||||
#### BOX86_FUTEX_WAITV *
|
||||
Use of the new fuext_waitc syscall
|
||||
* 0 : Do not try to use it, return unsupported (Default for BAD_SIGNAL build)
|
||||
* 1 : let program use the syscall if the host system support it (Default for other build)
|
||||
|
||||
#### BOX86_ENV
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var.
|
||||
@@ -267,6 +293,11 @@ Disables the load of vulkan libraries.
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
#### BOX86_ARG0
|
||||
Define argv[0] of the executable.
|
||||
* yyyy
|
||||
Will rewrite argv[0] instead of using program path.
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES *
|
||||
Fix/Don't fix 64bit inodes
|
||||
* 0 : Don't fix 64bit inodes. (Default.)
|
||||
@@ -290,7 +321,7 @@ Will use yyyy as x86 bash to launch script. yyyy needs to be a full path to a va
|
||||
#### BOX86_BOX64
|
||||
Define where to find box64 binary
|
||||
* yyyy
|
||||
Will use yyyy as x86_64 interpretor, to launch x64_64 binaries
|
||||
Will use yyyy as x86_64 interpreter, to launch x64_64 binaries
|
||||
|
||||
#### BOX86_JITGDB *
|
||||
|
||||
@@ -303,6 +334,7 @@ Will use yyyy as x86_64 interpretor, to launch x64_64 binaries
|
||||
* 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/box86` 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 ` BOX86_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
* 3 : Launch `lldb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
|
||||
#### BOX86_NORCFILES
|
||||
If the env var exist, no rc files (like /etc/box86.box86rc and ~/.box86rc) will be loaded
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ if [ "$karch" = "aarch64" ] || [ "$karch" = "aarch64-linux-gnu" ] || [ "$karch"
|
||||
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
|
||||
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
|
||||
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
|
||||
libxrender1:armhf libxxf86vm1 libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
|
||||
libxrender1:armhf libxxf86vm1:armhf libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
|
||||
|
||||
+5
-3
@@ -18,11 +18,11 @@ mv ./usr/* ../
|
||||
cd ../ && rm -rf ./tmp/
|
||||
|
||||
# create run script
|
||||
echo "#!/bin/bash
|
||||
echo '#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
export DBUS_FATAL_WARNINGS=0
|
||||
~/steam/bin/steam steam://open/minigameslist $@" > steam
|
||||
~/steam/bin/steam $@' > steam
|
||||
|
||||
# make script executable and move
|
||||
chmod +x steam
|
||||
@@ -35,7 +35,9 @@ if [ ${MACHINE_TYPE} == 'aarch64' ] && [ -f '/etc/debian_version' ]; then
|
||||
sudo dpkg --add-architecture armhf # enable installation of armhf libraries
|
||||
sudo apt update # update package lists with the newly added arch
|
||||
# install the libraries that Steam requires
|
||||
sudo apt install libc6:armhf libncurses5:armhf libsdl2-2.0-0:armhf libsdl2-image-2.0-0:armhf libsdl2-mixer-2.0-0:armhf libsdl2-ttf-2.0-0:armhf libopenal1:armhf libpng16-16:armhf libfontconfig1:armhf libxcomposite1:armhf libbz2-1.0:armhf libxtst6:armhf libsm6:armhf libice6:armhf libgl1:armhf libxinerama1:armhf libxdamage1:armhf
|
||||
sudo apt install libc6:armhf libsdl2-2.0-0:armhf libsdl2-image-2.0-0:armhf libsdl2-mixer-2.0-0:armhf libsdl2-ttf-2.0-0:armhf libopenal1:armhf libpng16-16:armhf libfontconfig1:armhf libxcomposite1:armhf libbz2-1.0:armhf libxtst6:armhf libsm6:armhf libice6:armhf libgl1:armhf libxinerama1:armhf libxdamage1:armhf libibus-1.0-5
|
||||
# this one is not there all the time, so just try it...
|
||||
sudo apt install libncurses5:armhf
|
||||
|
||||
# install mesa for armhf if already installed
|
||||
if dpkg-query -W libgl1-mesa-dri 2>/dev/null; then
|
||||
|
||||
@@ -13,6 +13,7 @@ provides=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
_rkmodel=`tr -d '\0' < /proc/device-tree/compatible`
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3xxx-git}"
|
||||
@@ -22,7 +23,7 @@ pkgver() {
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}"
|
||||
# Check for RockChip version number
|
||||
if [[ ${_rkmodel} =~ "rk3288"]]; then
|
||||
if [[ ${_rkmodel} =~ "rk3288" ]]; then
|
||||
_rksuffix=3288
|
||||
elif [[ ${_rkmodel} =~ "rk3399" ]]; then
|
||||
_rksuffix=3399
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#!/bin/sh
|
||||
# Restart the systemd-binfmt service to load new binary format rules.
|
||||
# This ensures the system is immediately ready to run programs with Box86.
|
||||
if [ -d '/run/systemd/system' ]; then
|
||||
systemctl restart systemd-binfmt || :
|
||||
fi
|
||||
+2
-2
@@ -72,7 +72,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
# Get all actual instructions
|
||||
# Ignore white lines and lines beginning with either !, ; or #
|
||||
insts = list(filter(lambda l: not re.match("^\s*$", l) and not re.match("^([!;#])", l), insts.split('\n')))
|
||||
insts = list(filter(lambda l: not re.match("^\\s*$", l) and not re.match("^([!;#])", l), insts.split('\n')))
|
||||
|
||||
try:
|
||||
# Do not open with `with` to be able to open it in writing mode
|
||||
@@ -729,7 +729,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
variables["u"] = -1 # Unsigned shift
|
||||
|
||||
variables["w"] = -1 # wback (used in adressing)
|
||||
variables["w"] = -1 # wback (used in addressing)
|
||||
|
||||
variables["shift"] = False # Shift already detected?
|
||||
|
||||
|
||||
+6
-3
@@ -74,7 +74,7 @@ For each of them:
|
||||
NOTE: Those structure letters are "fake types" that are accepted in the macros.
|
||||
|
||||
`gbl` contains the first list, `redirects` the second and
|
||||
`filespec` constains file specific informations (eg, structures, typedefs required...).
|
||||
`filespec` contains file specific information (eg, structures, typedefs required...).
|
||||
|
||||
After sorting the data, it generates:
|
||||
|
||||
@@ -631,7 +631,7 @@ class Clauses:
|
||||
combinable[len(last_combined) - 1] = True
|
||||
add = (i | attempt[0], m | (i ^ attempt[0]))
|
||||
if add in combined:
|
||||
continue # Aleady added
|
||||
continue # Already added
|
||||
combined.append(add)
|
||||
last_combined.pop()
|
||||
last_combined = combined
|
||||
@@ -751,6 +751,9 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
or match("gstinterfaces010","gstaudio")\
|
||||
or match("gstreamer010","gstreamer") \
|
||||
or match("appindicator","appindicator3")\
|
||||
or match("appindicator","ayatanaappindicator3")\
|
||||
or match("appindicator3","ayatanaappindicator3")\
|
||||
or match("libgl", "libglx") \
|
||||
\
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "ldlinux") \
|
||||
@@ -1148,7 +1151,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
for fhdr in files_header:
|
||||
files_guard[fhdr] = trim(files_guard[fhdr])
|
||||
|
||||
# TODO: put the informations below in a structure (like in box64, where
|
||||
# TODO: put the information below in a structure (like in box64, where
|
||||
# typedefs & co. are stored in an ABI-specific structure)
|
||||
|
||||
return_x87: str = "DKdf"
|
||||
|
||||
+22
-7
@@ -79,13 +79,15 @@ void free_tlsdatasize(void* p)
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
if(my_context)
|
||||
pthread_setspecific(my_context->tlskey, NULL);
|
||||
}
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
void* tid = (void*)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (arm_lock_storeifref2(&A, NULL, tid)==tid); \
|
||||
@@ -140,6 +142,7 @@ static void init_mutexes(box86context_t* context)
|
||||
{
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
arm_lock_stored(&context->mutex_dyndump, 0);
|
||||
arm_lock_stored(&context->mutex_once, 0);
|
||||
arm_lock_stored(&context->mutex_once2, 0);
|
||||
@@ -147,6 +150,20 @@ static void init_mutexes(box86context_t* context)
|
||||
arm_lock_stored(&context->mutex_tls, 0);
|
||||
arm_lock_stored(&context->mutex_thread, 0);
|
||||
arm_lock_stored(&context->mutex_bridge, 0);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
pthread_mutex_init(&context->mutex_once, &attr);
|
||||
pthread_mutex_init(&context->mutex_once2, &attr);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
@@ -241,7 +258,7 @@ box86context_t *NewBox86Context(int argc)
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
|
||||
pthread_key_create(&context->tlskey, free_tlsdatasize);
|
||||
pthread_key_create(&context->tlskey, NULL/*free_tlsdatasize*/);
|
||||
|
||||
InitFTSMap(context);
|
||||
|
||||
@@ -271,6 +288,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
box86context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
//clean_current_emuthread(); // cleaning main thread seems a bad idea
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
if(ctx->maplib)
|
||||
@@ -341,7 +359,6 @@ void FreeBox86Context(box86context_t** context)
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
pthread_setspecific(ctx->tlskey, NULL);
|
||||
}
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
@@ -365,17 +382,15 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#else
|
||||
#ifndef USE_CUSTOM_MUTEX
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
|
||||
freeCycleLog(ctx);
|
||||
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 3
|
||||
#define BOX86_REVISION 2
|
||||
#define BOX86_REVISION 9
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
+230
-244
@@ -23,7 +23,7 @@
|
||||
#include <sys/mman.h>
|
||||
#include "custommem.h"
|
||||
#include "threads.h"
|
||||
//#define TRACE_MEMSTAT
|
||||
#include "rbtree.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/dynablock_private.h"
|
||||
@@ -44,6 +44,8 @@ static uintptr_t box86_jmptbl_default[1<<JMPTABL_SHIFT];
|
||||
// lock addresses
|
||||
KHASH_SET_INIT_INT(lockaddress)
|
||||
static kh_lockaddress_t *lockaddress = NULL;
|
||||
#endif
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
static uint32_t mutex_prot;
|
||||
static uint32_t mutex_blocks;
|
||||
#else
|
||||
@@ -52,22 +54,12 @@ static pthread_mutex_t mutex_blocks;
|
||||
#endif
|
||||
#define MEMPROT_SHIFT 12
|
||||
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
|
||||
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
#ifdef DYNAREC
|
||||
static uint8_t hotpages[MEMPROT_SIZE] = {0};
|
||||
#endif
|
||||
#ifdef TRACE_MEMSTAT
|
||||
static uint32_t memprot_allocated = 0, memprot_max_allocated = 0;
|
||||
#endif
|
||||
//#define TRACE_MEMSTAT
|
||||
rbtree* memprot = NULL;
|
||||
static int inited = 0;
|
||||
|
||||
|
||||
typedef struct mapmem_s {
|
||||
uintptr_t begin, end;
|
||||
struct mapmem_s *next;
|
||||
} mapmem_t;
|
||||
|
||||
static mapmem_t *mapmem = NULL;
|
||||
static rbtree* mapallmem = NULL;
|
||||
static rbtree* mmapmem = NULL;
|
||||
|
||||
typedef struct blocklist_s {
|
||||
void* block;
|
||||
@@ -76,7 +68,8 @@ typedef struct blocklist_s {
|
||||
void* first;
|
||||
} blocklist_t;
|
||||
|
||||
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
|
||||
#define MMAPSIZE (64*1024) // allocate 64kb sized blocks
|
||||
#define DYNMMAPSZ (2*1024*1024) // allocate 2Mb block for dynarec
|
||||
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static int c_blocks = 0; // capacity of blocks for custom malloc
|
||||
@@ -399,6 +392,8 @@ void* customMalloc(size_t size)
|
||||
void* ret = allocBlock(p_blocks[i].block, p, size, &p_blocks[i].first);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
mutex_unlock(&mutex_blocks);
|
||||
if(mapallmem)
|
||||
setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE);
|
||||
return ret;
|
||||
}
|
||||
void* customCalloc(size_t n, size_t size)
|
||||
@@ -536,7 +531,7 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
// check if new
|
||||
if(!list->chunks[i].size) {
|
||||
// alloc a new block, aversized or not, we are at the end of the list
|
||||
size_t allocsize = (sz>MMAPSIZE)?sz:MMAPSIZE;
|
||||
size_t allocsize = (sz>DYNMMAPSZ)?sz:DYNMMAPSZ;
|
||||
// allign sz with pagesize
|
||||
allocsize = (allocsize+(box86_pagesize-1))&~(box86_pagesize-1);
|
||||
#ifndef USE_MMAP
|
||||
@@ -548,10 +543,13 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
mprotect(p, allocsize, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#else
|
||||
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
if(p==(void*)-1) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", allocsize);
|
||||
if(p==MAP_FAILED) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes (%s)\n", allocsize, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
#ifdef MADV_HUGEPAGE
|
||||
madvise(p, allocsize, MADV_HUGEPAGE);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TRACE_MEMSTAT
|
||||
dynarec_allocated += allocsize;
|
||||
@@ -791,23 +789,33 @@ uintptr_t getJumpAddress64(uintptr_t addr)
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
|
||||
uintptr_t cur = addr&~(box86_pagesize-1);
|
||||
uintptr_t end = ALIGN(addr+size);
|
||||
|
||||
mutex_lock(&mutex_prot);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
while(cur!=end) {
|
||||
uint32_t prot = 0, oprot;
|
||||
uintptr_t bend = 0;
|
||||
rb_get_end(memprot, cur, &prot, &bend);
|
||||
if(bend>end)
|
||||
bend = end;
|
||||
oprot = prot;
|
||||
uint32_t dyn = prot&PROT_DYN;
|
||||
uint32_t mapped = prot&PROT_MMAP;
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(!(dyn&PROT_NOPROT)) {
|
||||
prot = PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
if(!(dyn&PROT_NEVERPROT)) {
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(prot&PROT_WRITE) {
|
||||
if(!dyn) mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i] = prot|mapped|PROT_DYNAREC; // need to use atomic exchange?
|
||||
} else
|
||||
memprot[i] = prot|mapped|PROT_DYNAREC_R;
|
||||
if(!dyn)
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
prot |= PROT_DYNAREC;
|
||||
} else
|
||||
prot |= PROT_DYNAREC_R;
|
||||
}
|
||||
if (prot != oprot) // If the node doesn't exist, then prot != 0
|
||||
rb_set(memprot, cur, bend, prot);
|
||||
cur = bend;
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
@@ -817,21 +825,36 @@ void protectDB(uintptr_t addr, uintptr_t size)
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size, int mark)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p (mark=%d)\n", (void*)addr, (void*)(addr+size-1), mark);
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
|
||||
uintptr_t cur = addr&~(box86_pagesize-1);
|
||||
uintptr_t end = ALIGN(addr+size);
|
||||
|
||||
mutex_lock(&mutex_prot);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
if(!(prot&PROT_NOPROT)) {
|
||||
while(cur!=end) {
|
||||
uint32_t prot = 0, oprot;
|
||||
uintptr_t bend = 0;
|
||||
if (!rb_get_end(memprot, cur, &prot, &bend)) {
|
||||
if(bend>=end) break;
|
||||
else {
|
||||
cur = bend;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
oprot = prot;
|
||||
if(bend>end)
|
||||
bend = end;
|
||||
if(!(prot&PROT_NEVERPROT)) {
|
||||
if(prot&PROT_DYNAREC) {
|
||||
prot&=~PROT_DYN;
|
||||
if(mark)
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_MMAP);
|
||||
memprot[i] = prot; // need to use atomic exchange?
|
||||
cleanDBFromAddressRange(cur, bend-cur, 0);
|
||||
mprotect((void*)cur, bend-cur, prot);
|
||||
} else if(prot&PROT_DYNAREC_R)
|
||||
memprot[i] = prot&~PROT_CUSTOM;
|
||||
prot &= ~PROT_CUSTOM;
|
||||
}
|
||||
if (prot != oprot)
|
||||
rb_set(memprot, cur, bend, prot);
|
||||
cur = bend;
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
@@ -839,135 +862,71 @@ void unprotectDB(uintptr_t addr, uintptr_t size, int mark)
|
||||
int isprotectedDB(uintptr_t addr, size_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "isprotectedDB %p -> %p => ", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
if(!(prot&PROT_DYN)) {
|
||||
uintptr_t end = ALIGN(addr+size);
|
||||
addr &=~(box86_pagesize-1);
|
||||
mutex_lock(&mutex_prot);
|
||||
while (addr < end) {
|
||||
uint32_t prot;
|
||||
uintptr_t bend;
|
||||
if (!rb_get_end(memprot, addr, &prot, &bend) || !(prot&PROT_DYN)) {
|
||||
dynarec_log(LOG_DEBUG, "0\n");
|
||||
mutex_unlock(&mutex_prot);
|
||||
return 0;
|
||||
} else {
|
||||
addr = bend;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
dynarec_log(LOG_DEBUG, "1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uintptr_t hotpage = 0;
|
||||
int hotpage_cnt = 0;
|
||||
#define HOTPAGE_MARK 64
|
||||
void SetHotPage(uintptr_t addr)
|
||||
{
|
||||
hotpage = addr&~(box86_pagesize-1);
|
||||
hotpage_cnt = HOTPAGE_MARK;
|
||||
}
|
||||
int isInHotPage(uintptr_t addr)
|
||||
{
|
||||
if(!hotpage_cnt)
|
||||
return 0;
|
||||
--hotpage_cnt;
|
||||
return (addr>=hotpage) && (addr<hotpage+box86_pagesize);
|
||||
}
|
||||
int checkInHotPage(uintptr_t addr)
|
||||
{
|
||||
return hotpage_cnt && (addr>=hotpage) && (addr<hotpage+box86_pagesize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void printMapMem()
|
||||
{
|
||||
mapmem_t* m = mapmem;
|
||||
while(m) {
|
||||
printf_log(LOG_NONE, " %p-%p\n", (void*)m->begin, (void*)m->end);
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
void addMapMem(uintptr_t begin, uintptr_t end)
|
||||
{
|
||||
if(!mapmem)
|
||||
return;
|
||||
begin &=~(box86_pagesize-1);
|
||||
end = (end&~(box86_pagesize-1))+(box86_pagesize-1); // full page
|
||||
// sanitize values
|
||||
if(end<0x10000) return;
|
||||
if(!begin) begin = 0x10000;
|
||||
// find attach point (cannot be the 1st one by construction)
|
||||
mapmem_t* m = mapmem;
|
||||
while(m->next && begin>m->next->begin) {
|
||||
m = m->next;
|
||||
}
|
||||
// attach at the end of m
|
||||
mapmem_t* newm;
|
||||
if(m->end>=begin-1) {
|
||||
if(end<=m->end)
|
||||
return; // zone completly inside current block, nothing to do
|
||||
m->end = end; // enlarge block
|
||||
newm = m;
|
||||
} else {
|
||||
// create a new block
|
||||
newm = (mapmem_t*)box_calloc(1, sizeof(mapmem_t));
|
||||
newm->next = m->next;
|
||||
newm->begin = begin;
|
||||
newm->end = end;
|
||||
m->next = newm;
|
||||
}
|
||||
while(newm && newm->next && (newm->next->begin-1)<=newm->end) {
|
||||
// fuse with next
|
||||
if(newm->next->end>newm->end)
|
||||
newm->end = newm->next->end;
|
||||
mapmem_t* tmp = newm->next;
|
||||
newm->next = tmp->next;
|
||||
box_free(tmp);
|
||||
}
|
||||
// all done!
|
||||
}
|
||||
void removeMapMem(uintptr_t begin, uintptr_t end)
|
||||
{
|
||||
if(!mapmem)
|
||||
return;
|
||||
begin &=~(box86_pagesize-1);
|
||||
end = (end&~(box86_pagesize-1))+(box86_pagesize-1); // full page
|
||||
// sanitize values
|
||||
if(end<0x10000) return;
|
||||
if(!begin) begin = 0x10000;
|
||||
mapmem_t* m = mapmem, *prev = NULL;
|
||||
while(m) {
|
||||
// check if block is beyond the zone to free
|
||||
if(m->begin > end)
|
||||
return;
|
||||
// check if the block is completly inside the zone to free
|
||||
if(m->begin>=begin && m->end<=end) {
|
||||
// just free the block
|
||||
mapmem_t *tmp = m;
|
||||
if(prev) {
|
||||
prev->next = m->next;
|
||||
m = prev;
|
||||
} else {
|
||||
mapmem = m->next; // change attach, but should never happens
|
||||
m = mapmem;
|
||||
prev = NULL;
|
||||
}
|
||||
box_free(tmp);
|
||||
} else if(begin>m->begin && end<m->end) { // the zone is totaly inside the block => split it!
|
||||
mapmem_t* newm = (mapmem_t*)box_calloc(1, sizeof(mapmem_t)); // create a new "next"
|
||||
newm->end = m->end;
|
||||
m->end = begin - 1;
|
||||
newm->begin = end + 1;
|
||||
newm->next = m->next;
|
||||
m->next = newm;
|
||||
// nothing more to free
|
||||
return;
|
||||
} else if(begin>m->begin && begin<m->end) { // free the tail of the block
|
||||
m->end = begin - 1;
|
||||
} else if(end>m->begin && end<m->end) { // free the head of the block
|
||||
m->begin = end + 1;
|
||||
}
|
||||
prev = m;
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
//dynarec_log(LOG_DEBUG, "updateProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
mutex_lock(&mutex_prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t old_prot = memprot[i];
|
||||
uint32_t dyn=(old_prot&PROT_DYN);
|
||||
uint32_t mapped=(old_prot&PROT_MMAP);
|
||||
if(!(dyn&PROT_NOPROT)) {
|
||||
uintptr_t cur = addr & ~(box86_pagesize-1);
|
||||
uintptr_t end = ALIGN(cur+size);
|
||||
rb_set(mapallmem, cur, cur+size, 1);
|
||||
while (cur < end) {
|
||||
uintptr_t bend;
|
||||
uint32_t oprot;
|
||||
rb_get_end(memprot, cur, &oprot, &bend);
|
||||
if(bend>end) bend = end;
|
||||
uint32_t dyn=(oprot&PROT_DYN);
|
||||
if(!(dyn&PROT_NEVERPROT)) {
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
} else if(dyn && !(prot&PROT_WRITE)) {
|
||||
dyn = PROT_DYNAREC_R;
|
||||
}
|
||||
}
|
||||
memprot[i] = prot|dyn|mapped;
|
||||
if ((prot|dyn) != oprot)
|
||||
rb_set(memprot, cur, bend, prot|dyn);
|
||||
cur = bend;
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
@@ -975,23 +934,44 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
//dynarec_log(LOG_DEBUG, "setProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
size = ALIGN(size);
|
||||
mutex_lock(&mutex_prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
memprot[i] = prot;
|
||||
}
|
||||
uintptr_t cur = addr & ~(box86_pagesize-1);
|
||||
uintptr_t end = ALIGN(cur+size);
|
||||
rb_set(mapallmem, cur, end, 1);
|
||||
rb_set(memprot, cur, end, prot);
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
|
||||
void setProtection_mmap(uintptr_t addr, size_t size, uint32_t prot)
|
||||
{
|
||||
if(!size)
|
||||
return;
|
||||
addr &= ~(box86_pagesize-1);
|
||||
size = ALIGN(size);
|
||||
mutex_lock(&mutex_prot);
|
||||
rb_set(mmapmem, addr, addr+size, 1);
|
||||
mutex_unlock(&mutex_prot);
|
||||
if(prot)
|
||||
setProtection(addr, size, prot|PROT_MMAP);
|
||||
setProtection(addr, size, prot);
|
||||
else {
|
||||
mutex_lock(&mutex_prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
rb_set(mapallmem, addr, addr+size, 1);
|
||||
rb_unset(memprot, addr, addr+size);
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
}
|
||||
|
||||
void setProtection_elf(uintptr_t addr, size_t size, uint32_t prot)
|
||||
{
|
||||
size = ALIGN(size);
|
||||
addr &= ~(box86_pagesize-1);
|
||||
if(prot)
|
||||
setProtection(addr, size, prot);
|
||||
else {
|
||||
mutex_lock(&mutex_prot);
|
||||
rb_set(mapallmem, addr, addr+size, 1);
|
||||
rb_unset(memprot, addr, addr+size);
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
}
|
||||
@@ -999,11 +979,11 @@ void setProtection_mmap(uintptr_t addr, size_t size, uint32_t prot)
|
||||
void refreshProtection(uintptr_t addr)
|
||||
{
|
||||
mutex_lock(&mutex_prot);
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
int prot = memprot[idx];
|
||||
if(!(prot&PROT_DYNAREC)) {
|
||||
int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box86_pagesize, prot&~PROT_CUSTOM);
|
||||
printf_log(LOG_INFO, "refreshProtection(%p): %p/0x%x (ret=%d/%s)\n", (void*)addr, (void*)(idx<<MEMPROT_SHIFT), prot, ret, ret?strerror(errno):"ok");
|
||||
uint32_t prot;
|
||||
uintptr_t bend;
|
||||
if (rb_get_end(memprot, addr, &prot, &bend)) {
|
||||
int ret = mprotect((void*)(addr&~(box86_pagesize-1)), box86_pagesize, prot&~PROT_CUSTOM);
|
||||
dynarec_log(LOG_DEBUG, "refreshProtection(%p): %p/0x%x (ret=%d/%s)\n", (void*)addr, (void*)(addr&~(box86_pagesize-1)), prot, ret, ret?strerror(errno):"ok");
|
||||
}
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
@@ -1011,47 +991,17 @@ printf_log(LOG_INFO, "refreshProtection(%p): %p/0x%x (ret=%d/%s)\n", (void*)addr
|
||||
void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
|
||||
size = ALIGN(size);
|
||||
addr &= ~(box86_pagesize-1);
|
||||
mutex_lock(&mutex_prot);
|
||||
addMapMem(addr, addr+size-1);
|
||||
rb_set(mapallmem, addr, addr+size, 1);
|
||||
mutex_unlock(&mutex_prot);
|
||||
// don't need to add precise tracking probably
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
int IsInHotPage(uintptr_t addr) {
|
||||
int idx = (addr>>MEMPROT_SHIFT);
|
||||
if(!hotpages[idx])
|
||||
return 0;
|
||||
// decrement hot
|
||||
arm_lock_decifnot0b(&hotpages[idx]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AreaInHotPage(uintptr_t start, uintptr_t end_) {
|
||||
uintptr_t idx = (start>>MEMPROT_SHIFT);
|
||||
uintptr_t end = (end_>>MEMPROT_SHIFT);
|
||||
int ret = 0;
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t hot = hotpages[i];
|
||||
if(hot) {
|
||||
// decrement hot
|
||||
arm_lock_decifnot0b(&hotpages[i]);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
if(ret && box86_dynarec_log>LOG_INFO)
|
||||
dynarec_log(LOG_DEBUG, "BOX64: AreaInHotPage %p-%p\n", (void*)start, (void*)end_);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void AddHotPage(uintptr_t addr) {
|
||||
int idx = (addr>>MEMPROT_SHIFT);
|
||||
arm_lock_storeb(&hotpages[idx], box86_dynarec_hotpage);
|
||||
}
|
||||
#endif
|
||||
|
||||
uintptr_t pbrk = 0;
|
||||
uintptr_t old_brk = 0;
|
||||
uintptr_t* cur_brk = NULL;
|
||||
void loadProtectionFromMap()
|
||||
{
|
||||
if(box86_mapclean)
|
||||
@@ -1068,80 +1018,110 @@ void loadProtectionFromMap()
|
||||
if(sscanf(buf, "%x-%x %c%c%c", &s, &e, &r, &w, &x)==5) {
|
||||
int prot = ((r=='r')?PROT_READ:0)|((w=='w')?PROT_WRITE:0)|((x=='x')?PROT_EXEC:0);
|
||||
allocProtection(s, e-s, prot);
|
||||
if(!pbrk && strstr(buf, "[heap]"))
|
||||
pbrk = s;
|
||||
}
|
||||
}
|
||||
if(!pbrk) {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, program break not found\n");
|
||||
if(cur_brk) pbrk = *cur_brk; // approximate is better than nothing
|
||||
}
|
||||
fclose(f);
|
||||
box86_mapclean = 1;
|
||||
}
|
||||
|
||||
void freeProtection(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
size = ALIGN(size);
|
||||
addr &= ~(box86_pagesize-1);
|
||||
dynarec_log(LOG_DEBUG, "freeProtection %p:%p\n", (void*)addr, (void*)(addr+size-1));
|
||||
mutex_lock(&mutex_prot);
|
||||
removeMapMem(addr, addr+size-1);
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
memprot[i] = 0;
|
||||
}
|
||||
rb_unset(mapallmem, addr, addr+size);
|
||||
rb_unset(mmapmem, addr, addr+size);
|
||||
rb_unset(memprot, addr, addr+size);
|
||||
mutex_unlock(&mutex_prot);
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
mutex_lock(&mutex_prot);
|
||||
uint32_t ret = memprot[idx];
|
||||
uint32_t ret = rb_get(memprot, addr);
|
||||
mutex_unlock(&mutex_prot);
|
||||
return ret&~PROT_MMAP;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int getMmapped(uintptr_t addr)
|
||||
{
|
||||
mutex_lock(&mutex_prot);
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uint32_t ret = memprot[idx];
|
||||
mutex_unlock(&mutex_prot);
|
||||
return (ret&PROT_MMAP)?1:0;
|
||||
return rb_get(mmapmem, addr);
|
||||
}
|
||||
|
||||
|
||||
#define LOWEST (void*)0x10000
|
||||
#define MEDIAN (void*)0x40000000
|
||||
static void* findBlockHinted(void* hint, size_t size)
|
||||
static void* findBlockHinted(void* hint, size_t size, uintptr_t mask)
|
||||
{
|
||||
mapmem_t* m = mapmem;
|
||||
uintptr_t h = (uintptr_t)hint;
|
||||
while(m) {
|
||||
// first, check if program break as changed
|
||||
if(pbrk && cur_brk && *cur_brk!=old_brk) {
|
||||
old_brk = *cur_brk;
|
||||
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
|
||||
}
|
||||
int prot;
|
||||
if(hint<LOWEST) hint = LOWEST;
|
||||
uintptr_t bend = 0;
|
||||
uintptr_t cur = (uintptr_t)hint;
|
||||
if(!mask) mask = 0xffff;
|
||||
uintptr_t end_mem = 0xffffffffLL - mask;
|
||||
while(bend<end_mem) {
|
||||
if(!rb_get_end(mapallmem, cur, &prot, &bend)) {
|
||||
if(bend-cur>=size)
|
||||
return (void*)cur;
|
||||
if(bend>=0xc0000000 && (uintptr_t)hint<0xc0000000)
|
||||
return NULL;
|
||||
}
|
||||
// granularity 0x10000
|
||||
uintptr_t addr = (m->end+1+0xffff)&~0xffff;
|
||||
uintptr_t end = (m->next)?(m->next->begin-1):0xffffffff;
|
||||
// check hint and available size
|
||||
if(addr<=h && end>=h && end-h+1>=size)
|
||||
return hint;
|
||||
if(addr>=h && end-addr+1>=size)
|
||||
return (void*)addr;
|
||||
if(end>=0xc0000000 && h<0xc0000000)
|
||||
return NULL;
|
||||
m = m->next;
|
||||
cur = (bend+mask)&~mask;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void* findBlockNearHint(void* hint, size_t size)
|
||||
{ void* ret = findBlockHinted(hint, size);
|
||||
void* findBlockNearHint(void* hint, size_t size, uintptr_t mask)
|
||||
{ void* ret = findBlockHinted(hint, size, mask);
|
||||
return ret?ret:hint;
|
||||
}
|
||||
void* find32bitBlock(size_t size)
|
||||
{
|
||||
void* ret = findBlockHinted(MEDIAN, size);
|
||||
if(!ret) ret = findBlockHinted(LOWEST, size);
|
||||
void* ret = findBlockHinted(MEDIAN, size, 0);
|
||||
if(!ret) ret = findBlockHinted(LOWEST, size, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* find32bitBlockElf(size_t size, int mainbin, uintptr_t mask)
|
||||
{
|
||||
static void* startingpoint = (void*)0x60000000;
|
||||
void* mainaddr = (void*)0x30000000;
|
||||
void* ret = findBlockHinted(mainbin?mainaddr:startingpoint, size, mask);
|
||||
if(!ret) ret = findBlockHinted(LOWEST, size, mask);
|
||||
if(!mainbin)
|
||||
startingpoint = (void*)(((uintptr_t)startingpoint+size+0x200000)&~0xfffff);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isBlockFree(void* hint, size_t size)
|
||||
{
|
||||
int prot;
|
||||
uintptr_t bend = 0;
|
||||
uintptr_t cur = (uintptr_t)hint;
|
||||
if(!rb_get_end(mapallmem, cur, &prot, &bend)) {
|
||||
if(bend-cur>=size)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unlockCustommemMutex()
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
void* tid = (void*)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (arm_lock_storeifref2(&A, NULL, (void*)tid)==tid); \
|
||||
@@ -1174,7 +1154,7 @@ void relockCustommemMutex(int locks)
|
||||
|
||||
static void init_mutexes(void)
|
||||
{
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
arm_lock_stored(&mutex_blocks, 0);
|
||||
arm_lock_stored(&mutex_prot, 0);
|
||||
#else
|
||||
@@ -1182,6 +1162,7 @@ static void init_mutexes(void)
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&mutex_blocks, &attr);
|
||||
pthread_mutex_init(&mutex_prot, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
@@ -1199,6 +1180,8 @@ void init_custommem_helper(box86context_t* ctx)
|
||||
if(inited) // already initialized
|
||||
return;
|
||||
inited = 1;
|
||||
cur_brk = dlsym(RTLD_NEXT, "__curbrk");
|
||||
memprot = init_rbtree();
|
||||
init_mutexes();
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
@@ -1212,10 +1195,10 @@ void init_custommem_helper(box86context_t* ctx)
|
||||
lockaddress = kh_init(lockaddress);
|
||||
#endif
|
||||
pthread_atfork(NULL, NULL, atfork_child_custommem);
|
||||
// init mapmem list
|
||||
mapmem = (mapmem_t*)box_calloc(1, sizeof(mapmem_t));
|
||||
mapmem->begin = 0x0;
|
||||
mapmem->end = (uintptr_t)LOWEST - 1;
|
||||
// init mapallmem list
|
||||
mapallmem = init_rbtree();
|
||||
// init mmapmem list
|
||||
mmapmem = init_rbtree();
|
||||
loadProtectionFromMap();
|
||||
}
|
||||
|
||||
@@ -1234,7 +1217,7 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
}
|
||||
if (njmps_in_cur_lv1 > njmps_in_lv1_max) njmps_in_lv1_max = njmps_in_cur_lv1;
|
||||
}
|
||||
printf_log(LOG_INFO, "Allocation:\n- dynarec: %lu kio\n- customMalloc: %zu kio\n- memprot: %lu kio (peak at %ld kio)\n- jump table: %zu kio (%zu level 1 table allocated, for %zu jumps, with at most %zu per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, memprot_allocated / 1024, memprot_max_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
printf_log(LOG_INFO, "Allocation:\n- dynarec: %lu kio\n- customMalloc: %zu kio\n- jump table: %zu kio (%zu level 1 table allocated, for %zu jumps, with at most %zu per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#endif
|
||||
if(!inited)
|
||||
return;
|
||||
@@ -1269,6 +1252,13 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
kh_destroy(lockaddress, lockaddress);
|
||||
lockaddress = NULL;
|
||||
#endif
|
||||
delete_rbtree(memprot);
|
||||
memprot = NULL;
|
||||
delete_rbtree(mmapmem);
|
||||
mmapmem = NULL;
|
||||
delete_rbtree(mapallmem);
|
||||
mapallmem = NULL;
|
||||
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
#ifdef USE_MMAP
|
||||
munmap(p_blocks[i].block, p_blocks[i].size);
|
||||
@@ -1276,14 +1266,10 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
box_free(p_blocks[i].block);
|
||||
#endif
|
||||
box_free(p_blocks);
|
||||
#ifndef DYNAREC
|
||||
#ifndef USE_CUSTOM_MUTEX
|
||||
pthread_mutex_destroy(&mutex_blocks);
|
||||
pthread_mutex_destroy(&mutex_prot);
|
||||
#endif
|
||||
while(mapmem) {
|
||||
mapmem_t *tmp = mapmem;
|
||||
mapmem = mapmem->next;
|
||||
box_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
|
||||
@@ -192,6 +192,9 @@ Op is 20-27
|
||||
// and dst, src1, #imm ror rot*2
|
||||
#define AND_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe2000000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// and.c dst, src, #(imm8)
|
||||
#define AND_IMM8_COND(cond, dst, src, imm8) \
|
||||
EMIT((cond) | 0x02000000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// and.s dst, src, #(imm8)
|
||||
#define ANDS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -222,6 +225,8 @@ Op is 20-27
|
||||
// add dst, src1, src2, lsr #imm
|
||||
#define ADD_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
#define ADD_REG_LSR_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x00800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
#define ADC_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2a00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add.s dst, src, #(imm8)
|
||||
@@ -425,6 +430,8 @@ Op is 20-27
|
||||
|
||||
// blx reg
|
||||
#define BLX(reg) EMIT(0xe12fff30 | (reg) )
|
||||
// blx cond reg
|
||||
#define BLXcond(C, reg) EMIT(C | 0x012fff30 | (reg) )
|
||||
|
||||
// b cond offset
|
||||
#define Bcond(C, O) EMIT(C | (0b101<<25) | (0<<24) | (((O)>>2)&0xffffff))
|
||||
@@ -432,6 +439,10 @@ Op is 20-27
|
||||
// bl cond offset
|
||||
#define BLcond(C, O) EMIT(C | (0b101<<25) | (1<<24) | (((O)>>2)&0xffffff))
|
||||
|
||||
// adr
|
||||
#define ADR_gen(cond, P, Rd, Imm12) (cond | (1<<25) | (((P)?0b0100:0b0010)<<21) | (0b1111<<16) | ((Rd)<<12) | (Imm12))
|
||||
#define ADR(cond, Rd, Imm) EMIT(ADR_gen(cond, (Imm>=0), Rd, ((Imm>=0)?Imm:-Imm)&0b111111111111))
|
||||
|
||||
// push reg!, {list}
|
||||
// all | const |pre-index| subs | no PSR |writeback| store | base |reg list
|
||||
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
@@ -591,8 +602,12 @@ Op is 20-27
|
||||
|
||||
// Count leading 0 bit of Rm, store result in Rd
|
||||
#define CLZ(Rd, Rm) EMIT(c__ | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
|
||||
// Count leading 0 bit of Rm, store result in Rd with cond
|
||||
#define CLZ_COND(cond, Rd, Rm) EMIT(cond | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
|
||||
// Reverse bits of Rm, store result in Rd
|
||||
#define RBIT(Rd, Rm) EMIT(c__ | 0b01101111<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0011<<4 | (Rm))
|
||||
// Reverse bits of Rm, store result in Rd with cond
|
||||
#define RBIT_COND(cond, Rd, Rm) EMIT(cond | 0b01101111<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0011<<4 | (Rm))
|
||||
|
||||
#define PLD_gen(U, R, Rn, Imm5, type, Rm) (0b1111<<28 | 0b0111<<24 | (U)<<23 | (R)<<22 | 0b01<<20 | (Rn)<<16 | 0b1111<<12 | (Imm5)<<7 | (type)<<5 | (Rm))
|
||||
// Preload Cache Rn+Rm
|
||||
@@ -602,7 +617,21 @@ Op is 20-27
|
||||
|
||||
#define DMB_gen(opt) (0b1111<<28 | 0b01010111<<20 | 0b1111<<16 | 0b1111<<12 | 0b0000<<8 | 0b0101<<4 | (opt))
|
||||
// Data memory barrier Inner Sharable
|
||||
#ifdef PANDORA
|
||||
// The Pandora is single core and ordered, DMB is not usefull here so just emit nothing
|
||||
#define DMB_ISH()
|
||||
#else
|
||||
#define DMB_ISH() EMIT(DMB_gen(0b1011))
|
||||
#endif
|
||||
|
||||
#define DSB_gen(opt) (0b1111<<28 | 0b01010111<<20 | 0b1111<<16 | 0b1111<<12 | 0b0000<<8 | 0b0100<<4 | (opt))
|
||||
// Data memory barrier Inner Sharable
|
||||
#ifdef PANDORA
|
||||
// The Pandora is single core and ordered, DSB is not usefull here so just emit nothing
|
||||
#define DSB_ISH()
|
||||
#else
|
||||
#define DSB_ISH() EMIT(DSB_gen(0b1011))
|
||||
#endif
|
||||
|
||||
#define SWP_gen(cond, B, Rn, Rt, Rt2) (cond | 0b0001<<24 | (B)<<22 | (Rn)<<16 | (Rt)<<12 | 0b1001<<4 | (Rt2))
|
||||
// SWAP (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2
|
||||
@@ -628,11 +657,15 @@ Op is 20-27
|
||||
#define VMRS(Rt) EMIT(c__ | (0b1110<<24) | (0b1111<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
// Move to FPSCR from Arm register
|
||||
#define VMSR(Rt) EMIT(c__ | (0b1110<<24) | (0b1110<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
// Move to FPSCR from Arm register with cond
|
||||
#define VMSR_cond(cond, Rt) EMIT(cond | (0b1110<<24) | (0b1110<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
// Move to FPSCR from Arm flags APSR
|
||||
#define VMRS_APSR() VMRS(15)
|
||||
|
||||
// Move between Rt to Sm
|
||||
#define VMOVtoV(Sm, Rt) EMIT(c__ | (0b1110<<24) | (0b000<<21) | (0<<20) | ((((Sm)&0b11110)>>1)<<16) | ((Rt)<<12) | (0b1010<<8) | (((Sm)&1)<<7) |(0b00<<6) | (1<<4))
|
||||
// Move between Rt to Sm with condition
|
||||
#define VMOVtoVcond(cond, Sm, Rt) EMIT(cond | (0b1110<<24) | (0b000<<21) | (0<<20) | ((((Sm)&0b11110)>>1)<<16) | ((Rt)<<12) | (0b1010<<8) | (((Sm)&1)<<7) |(0b00<<6) | (1<<4))
|
||||
// Move between Sm to Rt
|
||||
#define VMOVfrV(Rt, Sm) EMIT(c__ | (0b1110<<24) | (0b000<<21) | (1<<20) | ((((Sm)&0b11110)>>1)<<16) | ((Rt)<<12) | (0b1010<<8) | (((Sm)&1)<<7) |(0b00<<6) | (1<<4))
|
||||
|
||||
@@ -885,6 +918,8 @@ Op is 20-27
|
||||
#define VMOV_igen(i, D, imm3, Vd, cmode, Q, op, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | (op)<<5 | 1<<4 | (imm4))
|
||||
#define VMOV_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 0, (imm)&15))
|
||||
#define VMOVQ_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 1, 0, (imm)&15))
|
||||
// Dd <= imm8 6bits duplicated 1bit -> 1byte
|
||||
#define VMOV_D64(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 1, (imm)&15))
|
||||
// Dd <= imm8 in high bits
|
||||
#define VMOV_H32(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b0110, 0, 0, (imm8)&15))
|
||||
// Dd <= imm8 in high bits
|
||||
@@ -1095,6 +1130,7 @@ Op is 20-27
|
||||
#define VMULL_U32_U16(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 1, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_S64_S32(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_U64_U32(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_P64(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 1, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMUL_NEON_gen(op, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (op)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1001<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VMULQ_32(Dd, Dn, Dm) EMIT(VMUL_NEON_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -1392,4 +1428,17 @@ Op is 20-27
|
||||
#define VABSQ_S8(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABSQ_F(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
// AES
|
||||
#define AESD_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0110<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
#define AESD(Dd, Dm) EMIT(AESD_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define AESE_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0110<<7 | 0<<6 | (M)<<5 | (Vm))
|
||||
#define AESE(Dd, Dm) EMIT(AESE_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define AESIMC_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0111<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
#define AESIMC(Dd, Dm) EMIT(AESIMC_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define AESMC_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0111<<7 | 0<<6 | (M)<<5 | (Vm))
|
||||
#define AESMC(Dd, Dm) EMIT(AESMC_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#endif //__ARM_EMITTER_H__
|
||||
@@ -9,8 +9,11 @@
|
||||
.global arm_epilog
|
||||
arm_epilog:
|
||||
//update register -> emu
|
||||
//pop {r0}
|
||||
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (so r14 must be Flags now)
|
||||
// restore stack pointer
|
||||
ldr sp, [r0, #(8*4+2*4)]
|
||||
pop {r4, r5}
|
||||
str r4, [r0, #(8*4+2*4)] // put back old value
|
||||
//restore all used register
|
||||
vpop {d8-d15}
|
||||
pop {r4-r12, pc}
|
||||
@@ -20,6 +23,10 @@ arm_epilog:
|
||||
|
||||
.global arm_epilog_fast
|
||||
arm_epilog_fast:
|
||||
// restore stack pointer
|
||||
ldr sp, [r0, #(8*4+2*4)]
|
||||
pop {r4, r5}
|
||||
str r4, [r0, #(8*4+2*4)] // put back old value
|
||||
//restore all used register
|
||||
vpop {d8-d15}
|
||||
pop {r4-r12, pc}
|
||||
|
||||
@@ -471,8 +471,10 @@ ARM_ cond 0 0 0 1 1 1 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXH<c> <Rd>, <Rt>,
|
||||
ARM_ cond 0 0 0 1 1 1 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXH<c> <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 1 0 0 0 0 S Rn Rd imm12 AND{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 0 1 S Rn Rd imm12 EOR{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #-<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 S Rn Rd imm12 SUB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 1 S Rn Rd imm12 RSB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 S Rn Rd imm12 ADD{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 1 S Rn Rd imm12 ADC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 1 0 S Rn Rd imm12 SBC{S}<c> <Rd>, <Rn>, #<const>
|
||||
|
||||
@@ -101,6 +101,7 @@ arm_lock_storeifnull:
|
||||
beq arm_lock_storeifnull
|
||||
arm_lock_storeifnull_exit:
|
||||
mov r0, r2
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifref2:
|
||||
@@ -116,6 +117,7 @@ arm_lock_storeifref2_loop:
|
||||
beq arm_lock_storeifref_loop
|
||||
mov r0, r2
|
||||
arm_lock_storeifref2_exit:
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifref:
|
||||
@@ -131,6 +133,7 @@ arm_lock_storeifref_loop:
|
||||
beq arm_lock_storeifref_loop
|
||||
mov r0, r1
|
||||
arm_lock_storeifref_exit:
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_decifnot0b:
|
||||
|
||||
@@ -4197,6 +4197,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "EOR%s%s %s, %s, #0x%x", (s ? "S" : ""), cond, regname[rd], regname[rn], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FFF0000) == 0x024F0000) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "ADR%s %s, #-0x%x", cond, regname[rd], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FE00000) == 0x02400000) {
|
||||
int s = (opcode >> 20) & 1;
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
@@ -4213,6 +4219,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "RSB%s%s %s, %s, #0x%x", (s ? "S" : ""), cond, regname[rd], regname[rn], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FFF0000) == 0x028F0000) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "ADR%s %s, #0x%x", cond, regname[rd], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FE00000) == 0x02800000) {
|
||||
int s = (opcode >> 20) & 1;
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
|
||||
@@ -11,9 +11,12 @@ arm_prolog:
|
||||
//save all used register
|
||||
push {r4-r12, lr}
|
||||
vpush {d8-d15}
|
||||
// save Sp and setup stack for optionnal callret
|
||||
ldr r4, [r0, #(8*4+2*4)] // grab old value of xSPSave
|
||||
mov r5, #0
|
||||
push {r4-r5}
|
||||
str sp, [r0, #(8*4+2*4)]
|
||||
//setup emu -> register
|
||||
//push {r0}
|
||||
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
|
||||
//TODO
|
||||
//jump to function
|
||||
bx r1
|
||||
+17
-23
@@ -177,11 +177,21 @@ dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
}
|
||||
|
||||
//TODO: move this to dynrec_arm.c and track allocated structure to avoid memory leak
|
||||
static __thread struct __jmp_buf_tag dynarec_jmpbuf;
|
||||
#ifdef ANDROID
|
||||
#define JUMPBUFF sigjmp_buf
|
||||
#else
|
||||
#define JUMPBUFF struct __jmp_buf_tag
|
||||
#endif
|
||||
static __thread JUMPBUFF dynarec_jmpbuf;
|
||||
#ifdef ANDROID
|
||||
#define DYN_JMPBUF dynarec_jmpbuf
|
||||
#else
|
||||
#define DYN_JMPBUF &dynarec_jmpbuf
|
||||
#endif
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
longjmp(&dynarec_jmpbuf, 1);
|
||||
longjmp(DYN_JMPBUF, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -214,7 +224,7 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
if(sigsetjmp(DYN_JMPBUF, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
FreeDynablock(block, 0);
|
||||
if(need_lock)
|
||||
@@ -252,33 +262,17 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
|
||||
{
|
||||
if(isInHotPage(addr))
|
||||
return NULL;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
if(AreaInHotPage((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr + db->x86_size - 1)) {
|
||||
emu->test.test = 0;
|
||||
if(box86_dynarec_fastpage) {
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(hash==db->hash) { // seems ok, run it without reprotecting it
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
return db;
|
||||
}
|
||||
db->done = 0; // invalidating the block, it's already not good
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 1);
|
||||
return NULL; // not building a new one, it's still a hotpage
|
||||
} else {
|
||||
dynarec_log(LOG_INFO, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, db->always_test, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
@@ -290,7 +284,7 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, db->always_test, (void*)addr);
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) {
|
||||
|
||||
+87
-143
@@ -20,6 +20,7 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "custommem.h"
|
||||
void x86test_check(x86emu_t* ref, uintptr_t ip);
|
||||
#endif
|
||||
|
||||
@@ -59,9 +60,13 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
// no block, let link table as is...
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=box86_dynarec_log) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p(elf=%s))\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
|
||||
if(checkInHotPage(addr)) {
|
||||
dynarec_log(LOG_INFO, "Not trying to run a block from a Hotpage at %p\n", (void*)addr);
|
||||
} else {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2-4);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p(elf=%s))\n", (void*)addr, x2-4, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
@@ -81,125 +86,77 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#define JUMPBUFF sigjmp_buf
|
||||
#else
|
||||
#define JUMPBUFF struct __jmp_buf_tag
|
||||
#endif
|
||||
|
||||
void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
int jmpbuf_reset = 0;
|
||||
int skip = 0;
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if((skip=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", skip, ejb->emu->segs[_FS]);
|
||||
addr = R_EIP; // not sure if it should still be inside DynaCall!
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
x86test_check(emu, R_EIP);
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
if(skip!=2)
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
uint32_t old_esp = R_ESP;
|
||||
uint32_t old_ebx = R_EBX;
|
||||
uint32_t old_edi = R_EDI;
|
||||
uint32_t old_esi = R_ESI;
|
||||
uint32_t old_ebp = R_EBP;
|
||||
uint32_t old_eip = R_EIP;
|
||||
// save defered flags
|
||||
defered_flags_t old_df = emu->df;
|
||||
uint32_t old_op1 = emu->op1;
|
||||
uint32_t old_op2 = emu->op2;
|
||||
uint32_t old_res = emu->res;
|
||||
// uc_link
|
||||
i386_ucontext_t* old_uc_link = emu->uc_link;
|
||||
emu->uc_link = NULL;
|
||||
|
||||
PushExit(emu);
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
DynaRun(emu);
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
emu->uc_link = old_uc_link;
|
||||
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
|
||||
if(emu->flags.quitonlongjmp==1)
|
||||
emu->flags.longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
// restore defered flags
|
||||
emu->df = old_df;
|
||||
emu->op1 = old_op1;
|
||||
emu->op2 = old_op2;
|
||||
emu->res = old_res;
|
||||
// and the old registers
|
||||
R_EBX = old_ebx;
|
||||
R_EDI = old_edi;
|
||||
R_ESI = old_esi;
|
||||
R_EBP = old_ebp;
|
||||
R_ESP = old_esp;
|
||||
R_EIP = old_eip; // and set back instruction pointer
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
#endif
|
||||
EmuCall(emu, addr);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
uint32_t old_esp = R_ESP;
|
||||
uint32_t old_ebx = R_EBX;
|
||||
uint32_t old_edi = R_EDI;
|
||||
uint32_t old_esi = R_ESI;
|
||||
uint32_t old_ebp = R_EBP;
|
||||
uint32_t old_eip = R_EIP;
|
||||
PushExit(emu);
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1);
|
||||
current = block;
|
||||
if(!block || !block->block || !block->done) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
if(box86_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_EIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
if(emu->quitonlongjmp && emu->longjmp) {
|
||||
emu->longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
R_EBX = old_ebx;
|
||||
R_EDI = old_edi;
|
||||
R_ESI = old_esi;
|
||||
R_EBP = old_ebp;
|
||||
R_ESP = old_esp;
|
||||
R_EIP = old_eip; // and set back instruction pointer
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
}
|
||||
|
||||
int my_setcontext(x86emu_t* emu, void* ucp);
|
||||
int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
JUMPBUFF jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
#ifdef DYNAREC
|
||||
int jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
int a;
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if((skip=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", skip, ejb->emu->segs[_FS]);
|
||||
JUMPBUFF *old_jmpbuf = emu->jmpbuf;
|
||||
uintptr_t old_savesp = emu->xSPSave;
|
||||
emu->flags.jmpbuf_ready = 0;
|
||||
|
||||
while(!(emu->quit)) {
|
||||
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
|
||||
emu->jmpbuf = jmpbuf;
|
||||
emu->old_savedsp = emu->xSPSave;
|
||||
emu->flags.jmpbuf_ready = 1;
|
||||
#ifdef ANDROID
|
||||
if((skip=sigsetjmp(*(JUMPBUFF*)emu->jmpbuf, 1)))
|
||||
#else
|
||||
if((skip=sigsetjmp(emu->jmpbuf, 1)))
|
||||
#endif
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun\n");
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
@@ -207,60 +164,47 @@ int DynaRun(x86emu_t* emu)
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
if(skip!=2)
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
#endif
|
||||
return Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1);
|
||||
current = block;
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->flags.need_jmpbuf = 0;
|
||||
|
||||
#ifndef DYNAREC
|
||||
Run(emu, 0);
|
||||
#else
|
||||
if(!box86_dynarec)
|
||||
Run(emu, 0);
|
||||
else {
|
||||
dynablock_t* block = (skip || ACCESS_FLAG(F_TF))?NULL:DBGetBlock(emu, R_EIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
if(box86_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (hash=0x%x) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->hash, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
else if(emu->quit && emu->uc_link) {
|
||||
if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->quit = 0;
|
||||
}
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
return 0;
|
||||
#endif
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
emu->xSPSave = old_savesp;
|
||||
}
|
||||
+142
-57
@@ -73,8 +73,7 @@ void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
}
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 64;
|
||||
dyn->next = (uintptr_t*)dynaRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
printf_log(LOG_NONE, "Warning, overallocating next\n");
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -95,6 +94,20 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
}
|
||||
return best;
|
||||
}
|
||||
void add_jump(dynarec_arm_t *dyn, int ninst) {
|
||||
// add slots
|
||||
if(dyn->jmp_sz == dyn->jmp_cap) {
|
||||
printf_log(LOG_NONE, "Warning, overallocating jmps\n");
|
||||
}
|
||||
dyn->jmps[dyn->jmp_sz++] = ninst;
|
||||
}
|
||||
int get_first_jump(dynarec_arm_t *dyn, int next) {
|
||||
for(int i=0; i<dyn->jmp_sz; ++i)
|
||||
if(dyn->insts[dyn->jmps[i]].x86.jmp == next)
|
||||
return dyn->jmps[i];
|
||||
return -2;
|
||||
}
|
||||
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
@@ -267,33 +280,47 @@ void addInst(instsize_t* insts, size_t* size, int x86_size, int native_size)
|
||||
}
|
||||
}
|
||||
|
||||
static void recurse_mark_alive(dynarec_arm_t* dyn, int i)
|
||||
{
|
||||
if(dyn->insts[i].x86.alive)
|
||||
return;
|
||||
dyn->insts[i].x86.alive = 1;
|
||||
if(dyn->insts[i].x86.jmp && dyn->insts[i].x86.jmp_insts!=-1)
|
||||
recurse_mark_alive(dyn, dyn->insts[i].x86.jmp_insts);
|
||||
if(i<dyn->size-1 && dyn->insts[i].x86.has_next)
|
||||
recurse_mark_alive(dyn, i+1);
|
||||
}
|
||||
|
||||
static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
static int sizePredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to alocate the array
|
||||
// compute total size of predecessor to allocate the array
|
||||
// mark alive...
|
||||
recurse_mark_alive(dyn, 0);
|
||||
// first compute the jumps
|
||||
int jmpto;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x86.jmp && dyn->insts[i].x86.jmp_insts!=-1) {
|
||||
++pred_sz;
|
||||
++dyn->insts[dyn->insts[i].x86.jmp_insts].pred_sz;
|
||||
if(dyn->insts[i].x86.alive && dyn->insts[i].x86.jmp && ((jmpto=dyn->insts[i].x86.jmp_insts)!=-1)) {
|
||||
pred_sz++;
|
||||
dyn->insts[jmpto].pred_sz++;
|
||||
}
|
||||
}
|
||||
// remove "has_next" from orphean branch
|
||||
// remove "has_next" from orphan branch
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(!dyn->insts[i].x86.has_next) {
|
||||
if(dyn->insts[i+1].x86.has_next && !dyn->insts[i+1].pred_sz)
|
||||
dyn->insts[i+1].x86.has_next = 0;
|
||||
}
|
||||
if(dyn->insts[i].x86.has_next && !dyn->insts[i+1].x86.alive)
|
||||
dyn->insts[i].x86.has_next = 0;
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x86.has_next) {
|
||||
++pred_sz;
|
||||
++dyn->insts[i+1].pred_sz;
|
||||
pred_sz++;
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)dynaMalloc(pred_sz*sizeof(int));
|
||||
return pred_sz;
|
||||
}
|
||||
static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
@@ -302,7 +329,7 @@ static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
for(int i=0; i<dyn->size; ++i) if(dyn->insts[i].x86.alive) {
|
||||
if((i!=dyn->size-1) && dyn->insts[i].x86.has_next)
|
||||
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
|
||||
if(dyn->insts[i].x86.jmp && (dyn->insts[i].x86.jmp_insts!=-1)) {
|
||||
@@ -317,14 +344,10 @@ static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x86.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags==SF_SUBSET)) {
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags==SF_SUBSET || dyn->insts[ninst].x86.state_flags==SF_SET || dyn->insts[ninst].x86.state_flags==SF_SET_NODF)) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
}
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags==SF_SET)) {
|
||||
need &=~X_PEND;
|
||||
need |= dyn->insts[ninst].x86.set_flags; // SF_SET will compute all flags, it's not SUBSET!
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x86.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x86.set_flags);
|
||||
}
|
||||
@@ -333,11 +356,11 @@ static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
dyn->insts[ninst].x86.gen_flags |= X_PEND;
|
||||
dyn->insts[ninst].x86.need_after = need;
|
||||
need = dyn->insts[ninst].x86.need_after&~dyn->insts[ninst].x86.gen_flags;
|
||||
|
||||
if(dyn->insts[ninst].x86.may_set)
|
||||
need |= dyn->insts[ninst].x86.gen_flags; // forward the flags
|
||||
// Consume X_PEND if relevant
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.set_flags&SF_PENDING))
|
||||
need &=~X_PEND;
|
||||
else if((need&X_PEND) && (dyn->insts[ninst].x86.set_flags&SF_PENDING))
|
||||
need &=~X_PEND; // Consume X_PEND if relevant
|
||||
need |= dyn->insts[ninst].x86.use_flags;
|
||||
if(dyn->insts[ninst].x86.need_before == need)
|
||||
return ninst - 1;
|
||||
@@ -360,22 +383,23 @@ static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
static int static_jmps[MAX_INSTS+2];
|
||||
static uintptr_t static_next[MAX_INSTS+2];
|
||||
static instruction_arm_t static_insts[MAX_INSTS+2] = {0};
|
||||
// TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory
|
||||
|
||||
void CancelBlock(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(helper) {
|
||||
dynaFree(helper->next);
|
||||
dynaFree(helper->insts);
|
||||
dynaFree(helper->predecessor);
|
||||
if(helper->dynablock && helper->dynablock->actual_block) {
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
helper->dynablock->actual_block = NULL;
|
||||
}
|
||||
}
|
||||
current_helper = NULL;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
@@ -424,10 +448,6 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
|
||||
*/
|
||||
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
@@ -444,14 +464,19 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)dynaCalloc(helper.cap, sizeof(instruction_arm_t));
|
||||
helper.cap = MAX_INSTS;
|
||||
helper.insts = static_insts;
|
||||
helper.jmps = static_jmps;
|
||||
helper.jmp_cap = MAX_INSTS;
|
||||
helper.next = static_next;
|
||||
helper.next_cap = MAX_INSTS;
|
||||
// pass 0, addresses, x86 jump addresses, overall size of the block
|
||||
uintptr_t end = arm_pass0(&helper, addr);
|
||||
// no need for next anymore
|
||||
dynaFree(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
@@ -460,7 +485,6 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
AddHotPage(addr);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -470,38 +494,89 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// calculate barriers
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.jmp) {
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
if(j<start || j>=end || j==helper.insts[i].x86.addr) {
|
||||
if(j==helper.insts[i].x86.addr) // if there is a loop on some opcode, make the block "always to tested"
|
||||
helper.always_test = 1;
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
helper.insts[i].x86.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x86.addr==j)
|
||||
k=i2;
|
||||
for(int ii=0; ii<helper.jmp_sz; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
if(j<start || j>=end || j==helper.insts[i].x86.addr) {
|
||||
if(j==helper.insts[i].x86.addr) // if there is a loop on some opcode, make the block "always to tested"
|
||||
helper.always_test = 1;
|
||||
helper.insts[i].x86.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
int search = ((j>=helper.insts[0].x86.addr) && j<helper.insts[0].x86.addr+helper.isize)?1:0;
|
||||
int imin = 0;
|
||||
int imax = helper.size-1;
|
||||
int i2 = helper.size/2;
|
||||
// dichotomy search
|
||||
while(search) {
|
||||
if(helper.insts[i2].x86.addr == j) {
|
||||
k = i2;
|
||||
search = 0;
|
||||
} else if(helper.insts[i2].x86.addr>j) {
|
||||
imax = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
} else {
|
||||
imin = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
}
|
||||
if(search && (imax-imin)<2) {
|
||||
search = 0;
|
||||
if(helper.insts[imin].x86.addr==j)
|
||||
k = imin;
|
||||
else if(helper.insts[imax].x86.addr==j)
|
||||
k = imax;
|
||||
}
|
||||
}
|
||||
/*for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x86.addr==j)
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1) {
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x86.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x86.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no need for next and jmps 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));
|
||||
fillPredecessors(&helper);
|
||||
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
// remove fpu stuff on non-executed code
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz)
|
||||
fpu_reset_ninst(&helper, ii++);
|
||||
i = ii;
|
||||
}
|
||||
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
arm_pass1(&helper, addr);
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
@@ -535,13 +610,16 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
helper.arm_size = 0;
|
||||
helper.insts_size = 0; // reset
|
||||
arm_pass3(&helper, addr);
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
helper.instsize = NULL;
|
||||
dynaFree(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
@@ -560,7 +638,6 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
// Check if something changed, to abbort if it as
|
||||
if((block->hash != hash)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%zu)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
AddHotPage(addr);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -578,15 +655,23 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// ok, free the helper now
|
||||
helper.insts = NULL;
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX86: Warning, ists_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%zu, marking as need_test\n", block->x86_addr, block->x86_size);
|
||||
AddHotPage(addr);
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
block->dirty = 1;
|
||||
block->always_test = 1;
|
||||
}
|
||||
if(block->always_test) {
|
||||
dynarec_log(LOG_DEBUG, "Note: block marked as always dirty %p:%ld\n", block->x86_addr, block->x86_size);
|
||||
}
|
||||
current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
|
||||
+366
-220
File diff suppressed because it is too large.
Load diff
+161
-72
@@ -28,7 +28,7 @@
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
#define GETEX(a, w) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7, w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -40,7 +40,7 @@
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
#define GETEM(a) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -86,11 +86,70 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
nextop = F8;
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("FAKE xgetbv");
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
//CALL(arm_ud, -1, 0);
|
||||
SKIPTEST(x1, x14);
|
||||
UDF(0);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("SMSW Ed");
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, (1<<0) | (1<<4)); // only PE and ET set...
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("SGDT Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
MOVW(x1, 0x7f);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
MOVW(x1, 0x000c);
|
||||
STRH_IMM8(x1, wback, 2);
|
||||
MOVW(x1, 0xd000);
|
||||
STRH_IMM8(x1, wback, 4);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("SIDT Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
MOVW(x1, 0xfff);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
MOVW(x1, 0);
|
||||
STR_IMM9(x1, wback, 2);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("SMSW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
// dummy for now... Do I need to track CR0 state?
|
||||
MOVW(x1, (1<<0) | (1<<4)); // only PE and ET set...
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0B:
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
//CALL(arm_ud, -1, 0);
|
||||
SKIPTEST(x14);
|
||||
SKIPTEST(x1, x14);
|
||||
UDF(0);
|
||||
break;
|
||||
|
||||
@@ -111,7 +170,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
@@ -133,7 +192,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -150,7 +209,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
INST_NAME("MOVHLPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
@@ -169,7 +228,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
INST_NAME("MOVLPS Ex,Gx");
|
||||
GETGX(v0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
VMOVD(v1, v0);
|
||||
} else {
|
||||
@@ -192,7 +251,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, q0);
|
||||
} else q1 = q0;
|
||||
@@ -203,7 +262,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, q0);
|
||||
} else q1 = q0;
|
||||
@@ -212,7 +271,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
INST_NAME("MOVLHPS Gx,Ex");
|
||||
GETGX(v0, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
@@ -229,7 +288,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
INST_NAME("MOVHPS Ex,Gx");
|
||||
GETGX(v0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
VMOVD(v1, v0+1);
|
||||
} else {
|
||||
@@ -249,7 +308,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x18:
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
INST_NAME("NOP (multibyte)");
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -282,7 +341,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVAPS Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
@@ -298,7 +357,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -312,7 +371,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -327,7 +386,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -340,7 +399,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -355,7 +414,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -385,10 +444,10 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v1<16)
|
||||
d0 = v1;
|
||||
@@ -422,7 +481,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SKIPTEST(x14);
|
||||
SKIPTEST(x1, x14);
|
||||
CALL(ReadTSC, xEAX, 0); // will return the u64 in x1:xEAX
|
||||
MOV_REG(xEDX, x1);
|
||||
break;
|
||||
@@ -466,7 +525,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVBE Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
REV(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
@@ -479,12 +538,12 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVBE Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
REV(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
REV(x1, gd);
|
||||
STR_IMM9(gd, ed, fixedaddress);
|
||||
STR_IMM9(x1, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -523,7 +582,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
MOV_REG_COND(YES, gd, ed); \
|
||||
} else { \
|
||||
@@ -625,7 +684,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
XOR_REG_LSL_IMM5(gd, gd, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
// EX is an xmm reg
|
||||
GETEX(q0, 0);
|
||||
VMOVfrV_D(x1, x2, q0);
|
||||
@@ -658,11 +717,13 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTPS Gx, Ex");
|
||||
SKIPTEST(x1);
|
||||
SKIPTEST(x1, x14);
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
#if 0
|
||||
// the approximate is not precise enough and and some incorrect behavior
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
// Newton-Raphson: Xn+1 = Xn*(3-d*Xn²)/2 converge to 1/sqrt(d) with X0 = result of VSQRTE
|
||||
@@ -695,10 +756,37 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMULQ_F32(v0, v2, q0); // v0 = X2*d ~ SQRT(d)
|
||||
}
|
||||
#else
|
||||
if((q0<15) && (v0<15)) {
|
||||
d0 = q0;
|
||||
d1 = v0;
|
||||
} else {
|
||||
s0 = fpu_get_scratch_quad(dyn);
|
||||
// source ok or not
|
||||
if(q0<15) {
|
||||
d0 = q0;
|
||||
} else {
|
||||
VMOVQ(s0, q0);
|
||||
d0 = s0;
|
||||
}
|
||||
if(v0<15)
|
||||
d1 = v0;
|
||||
else
|
||||
d1 = s0;
|
||||
}
|
||||
for(int i=0; i<4; ++i) {
|
||||
VSQRT_F32(d1*2+i, d0*2+i);
|
||||
}
|
||||
if(v0<15) {
|
||||
//done
|
||||
} else {
|
||||
VMOVQ(v0, d1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
SKIPTEST(x1);
|
||||
SKIPTEST(x1, x14);
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
@@ -721,7 +809,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
SKIPTEST(x1);
|
||||
SKIPTEST(x1, x14);
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
@@ -880,7 +968,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(v0, d1);
|
||||
} else v0 = d1;
|
||||
@@ -891,7 +979,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(v0, d1);
|
||||
} else v0 = d1;
|
||||
@@ -902,7 +990,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(v0, d1);
|
||||
} else v0 = d1;
|
||||
@@ -944,7 +1032,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOVD(q0+1, d1);
|
||||
} else {
|
||||
@@ -959,7 +1047,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(v0, d1);
|
||||
} else v0 = d1;
|
||||
@@ -971,7 +1059,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(v0, d1);
|
||||
} else v0 = d1;
|
||||
@@ -983,7 +1071,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(v0, d1);
|
||||
} else v0 = d1;
|
||||
@@ -1018,7 +1106,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVQ Gm, Em");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
VMOVD(v0, v1);
|
||||
@@ -1034,7 +1122,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
gd = (nextop&0x38)>>3;
|
||||
i32 = -1;
|
||||
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
u8 = F8;
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
// use stack as temporary storage
|
||||
@@ -1079,7 +1167,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLW Em, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1102,7 +1190,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAW Em, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1121,7 +1209,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLW Em, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1249,7 +1337,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVD Ed, Gm");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX + (nextop&7);
|
||||
VMOVfrDx_32(ed, v0, 0);
|
||||
} else {
|
||||
@@ -1263,7 +1351,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVQ Em, Gm");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
VMOVD(v1, v0);
|
||||
} else {
|
||||
@@ -1402,7 +1490,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop=F8; \
|
||||
MOVW_COND(NO, x3, 0); \
|
||||
MOVW_COND(YES, x3, 1); \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
ed = (nextop&7); \
|
||||
eb1 = xEAX+(ed&3); \
|
||||
eb2 = ((ed&4)>>2); \
|
||||
@@ -1529,7 +1617,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1556,7 +1644,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETED;
|
||||
GETGD;
|
||||
@@ -1585,7 +1673,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1614,7 +1702,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED;
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
@@ -1624,7 +1712,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETED;
|
||||
GETGD;
|
||||
@@ -1652,7 +1740,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// A purge is probably not needed, just a full refresh
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
@@ -1664,7 +1752,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
@@ -1685,7 +1773,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("STMXCSR Md");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
LDR_IMM9(ed, xEmu, offsetof(x86emu_t, mxcsr));
|
||||
} else {
|
||||
@@ -1697,7 +1785,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed (not implemented");
|
||||
FAKEED;
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
STM(xEmu, (1<<xEAX)|(1<<xECX)|(1<<xEDX)|(1<<xEBX)|(1<<xESP)|(1<<xEBP)|(1<<xESI)|(1<<xEDI)|(1<<xFlags));
|
||||
STR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
CALL(arm_ud, -1, 0);
|
||||
@@ -1781,7 +1869,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1813,7 +1901,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
@@ -1828,7 +1916,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVZX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
UXTH(gd, ed, 0);
|
||||
} else {
|
||||
@@ -1846,7 +1934,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
gd = x2;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1866,7 +1954,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1898,7 +1986,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1930,7 +2018,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1970,7 +2058,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -2042,7 +2130,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
@@ -2057,7 +2145,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVSX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
SXTH(gd, ed, 0);
|
||||
} else {
|
||||
@@ -2082,11 +2170,12 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED;
|
||||
MOV_REG(x1, gd);
|
||||
if(gd!=ed) {
|
||||
MOV_REG(gd, ed);
|
||||
XOR_REG_LSL_IMM5(gd, gd, ed, 0); // swap gd, ed
|
||||
XOR_REG_LSL_IMM5(ed, gd, ed, 0);
|
||||
XOR_REG_LSL_IMM5(gd, gd, ed, 0);
|
||||
}
|
||||
emit_add32(dyn, ninst, ed, x1, x3, x14);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
@@ -2125,7 +2214,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// ignoring "NTI"
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd); // doesn't exist
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
@@ -2136,7 +2225,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("PINSRW Gm,Ed,Ib");
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
u8 = (F8)&3;
|
||||
ed = xEAX+(nextop&7);
|
||||
VMOVtoDx_16(d0, u8, ed);
|
||||
@@ -2151,7 +2240,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("PEXTRW Gd,Em,Ib");
|
||||
nextop = F8;
|
||||
gd = xEAX+((nextop&0x38)>>3);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETEM(d0);
|
||||
u8 = (F8)&3;
|
||||
VMOVfrDx_U16(gd, d0, u8);
|
||||
@@ -2414,7 +2503,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xD7:
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
INST_NAME("PMOVMSKB Gd, Em");
|
||||
GETEM(d0);
|
||||
gd = xEAX+((nextop&0x38)>>3);
|
||||
@@ -2558,7 +2647,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOVNTQ Em, Gm");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
@@ -29,7 +30,8 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, u8;
|
||||
uint8_t wback, u8, wb1, wb2;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
@@ -46,6 +48,17 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
GETEBO(x14);
|
||||
emit_and8(dyn, ninst, x1, x2, x14, x2);
|
||||
EBBACK;
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -86,6 +99,13 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarecFS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarecGS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x67:
|
||||
// reduced EA size...
|
||||
opcode = F8;
|
||||
@@ -95,7 +115,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
@@ -112,7 +132,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
@@ -125,7 +145,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
@@ -165,7 +185,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
@@ -182,13 +202,36 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
gb2 = ((gd&4)>>2);
|
||||
gb1 = xEAX+(gd&3);
|
||||
if(gb2) {
|
||||
gd = x3;
|
||||
UXTB(gd, gb1, gb2);
|
||||
} else {
|
||||
gd = gb1; // no need to extract
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed&4)<<1); // L or H
|
||||
BFI(eb1, gd, eb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
STRB_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ed, Gd");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
@@ -202,7 +245,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
@@ -215,7 +258,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xEAX+(nextop&7));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
@@ -224,6 +267,9 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA0:
|
||||
INST_NAME("MOV AL, FS:Id");
|
||||
@@ -288,7 +334,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
if(MODREG) { // reg <= i32
|
||||
i32 = F32S;
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
@@ -319,24 +365,45 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); //Hack to put flag in "don't care" state
|
||||
}
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
MOV_REG(xEIP, xEAX+(nextop&7));
|
||||
} else { // mem
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
|
||||
}
|
||||
BARRIER(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
if(box86_dynarec_callret && box86_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
MOV32(x2, addr);
|
||||
if(box86_dynarec_callret) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)-8):0;
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j32>>2);
|
||||
ADR(c__, x3, j32);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j32 = getJumpTableAddress(addr);
|
||||
MOV32(x3, j32);
|
||||
LDR_IMM9(x3, x3, 0);
|
||||
}
|
||||
PUSH(xSP, (1<<x2)|(1<<x3));
|
||||
}
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
break;
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
|
||||
@@ -172,6 +172,13 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarecFS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarecGS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, GS:Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -369,7 +376,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
@@ -383,7 +390,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
@@ -396,7 +403,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1((xEAX+(nextop&7)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
@@ -405,6 +412,9 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, GS:Id");
|
||||
@@ -444,7 +454,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV GS:Eb, Ib");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= u8
|
||||
if(MODREG) { // reg <= u8
|
||||
u8 = F8;
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
@@ -463,7 +473,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
if(MODREG) { // reg <= i32
|
||||
i32 = F32S;
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
@@ -498,7 +508,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
GETEDO2(x14);
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
@@ -509,7 +519,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RCR Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcr32, ed, (1<<x2));
|
||||
@@ -591,7 +601,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcl32, ed, (1<<x2));
|
||||
@@ -601,7 +611,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
@@ -650,7 +660,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH GS:Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
|
||||
+216
-119
@@ -18,6 +18,7 @@
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
@@ -172,9 +173,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i16 = F16;
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
|
||||
emit_sbb16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x1E:
|
||||
@@ -388,13 +389,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETEW(x1);
|
||||
i16 = F16S;
|
||||
MOVW(x2, i16);
|
||||
SMULBB(x2, ed, x2);
|
||||
UFLAG_RES(x2);
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
@@ -406,13 +407,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETEW(x1);
|
||||
i16 = F8S;
|
||||
MOVW(x2, i16);
|
||||
SMULBB(x2, ed, x2);
|
||||
UFLAG_RES(x2);
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
@@ -507,7 +508,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x87:
|
||||
INST_NAME("(LOCK) XCHG Ew, Gw");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETGD;
|
||||
UXTH(x14, gd, 0);
|
||||
ed = xEAX + (nextop&7);
|
||||
@@ -541,7 +542,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
@@ -556,7 +557,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(gd, ed, 0, 16);
|
||||
@@ -573,7 +574,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
LDRH_REG(x1, xEmu, x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
BFI(ed, x1, 0, 16);
|
||||
} else {
|
||||
@@ -586,7 +587,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg,Ew");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
STRH_REG(ed, xEmu, x2);
|
||||
@@ -636,7 +637,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF (16b)");
|
||||
SETFLAGS(X_ALL, SF_SET); // lower 16bits is all flags handled in dynarec
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // lower 16bits is all flags handled in dynarec
|
||||
LDRHA_IMM8(x2, xESP, 2);
|
||||
MOV32(x1, 0x7FD7);
|
||||
AND_REG_LSL_IMM5(x2, x2, x1, 0);
|
||||
@@ -649,7 +650,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV, AX, Od");
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
SMREAD();
|
||||
if(isLockAddress(u32)) lock=1; else lock = 0;
|
||||
SMREADLOCK(lock);
|
||||
LDRH_IMM8(x2, x2, 0);
|
||||
BFI(xEAX, x2, 0, 16);
|
||||
break;
|
||||
@@ -657,8 +659,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV Od, AX");
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
if(isLockAddress(u32)) lock=1; else lock = 0;
|
||||
STRH_IMM8(xEAX, x2, 0);
|
||||
SMWRITE();
|
||||
SMWRITELOCK(lock);
|
||||
break;
|
||||
case 0xA5:
|
||||
INST_NAME("MOVSW");
|
||||
@@ -723,26 +726,34 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
CALL_(rol16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_rol16c(dyn, ninst, x1, u8&15, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
CALL_(ror16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_ror16c(dyn, ninst, x1, u8&15, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
@@ -752,7 +763,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
@@ -762,39 +773,42 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
MOV_REG_LSL_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_shl16c(dyn, ninst, x1, u8&31, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
MOV_REG_LSR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_shr16c(dyn, ninst, x1, u8&31, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
MOV_REG_ASR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1);
|
||||
u8 = F8;
|
||||
emit_sar16c(dyn, ninst, x1, u8&31, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -802,7 +816,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u16 = F16;
|
||||
MOVW(x1, u16);
|
||||
@@ -816,101 +830,178 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOVW(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
INST_NAME("ROL Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
CALL_(rol16, x1, (1<<x3));
|
||||
emit_rol16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROR Ew, 1");
|
||||
MOVW(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
INST_NAME("ROR Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
CALL_(ror16, x1, (1<<x3));
|
||||
emit_ror16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD1) {INST_NAME("RCL Ew, 1"); } else { INST_NAME("RCL Ew, CL");}
|
||||
INST_NAME("RCL Ew, 1");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
GETEW(x1);
|
||||
CALL_(rcl16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD1) {INST_NAME("RCR Ew, 1");} else {INST_NAME("RCR Ew, CL");}
|
||||
INST_NAME("RCR Ew, 1");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
GETEW(x1);
|
||||
CALL_(rcr16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
INST_NAME("SHL Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_LSL_REG(ed, ed, x14);
|
||||
emit_shl16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
INST_NAME("SHR Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_LSR_REG(ed, ed, x14);
|
||||
emit_shr16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
INST_NAME("SAR Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETSEW(x1);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_ASR_REG(ed, ed, x14);
|
||||
emit_sar16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
TSTS_IMM8(xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
AND_IMM8(x2, xECX, 0x0f);
|
||||
RSB_IMM8(x2, x2, 16);
|
||||
GETEW(x1);
|
||||
ORR_REG_LSL_IMM5(ed, ed, ed, 16);
|
||||
MOV_REG_LSR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x2, 15);
|
||||
ADD_REG_LSR_IMM5_COND(cEQ, x3, ed, ed, 15);
|
||||
BFI_COND(cEQ, xFlags, x3, F_OF, 1);
|
||||
BFI(xFlags, ed, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
TSTS_IMM8(xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
AND_IMM8(x2, xECX, 0x0f);
|
||||
GETEW(x1);
|
||||
ORR_REG_LSL_IMM5(ed, ed, ed, 16);
|
||||
MOV_REG_LSR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x2, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, x2, ed, 14); // x2 = d>>14
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, x2, x2, x2, 1); // x2 = ((d>>14) ^ ((d>>14)>>1))
|
||||
BFI_COND(cEQ, xFlags, x2, F_OF, 1);
|
||||
MOV_REG_LSR_IMM5(x2, ed, 15);
|
||||
BFI(xFlags, x2, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, CL");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
GETEW(x1);
|
||||
CALL_(rcl16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, CL");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
GETEW(x1);
|
||||
CALL_(rcr16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDS_IMM8(x2, xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
GETEW(x1);
|
||||
emit_shl16(dyn, ninst, x1, x2, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDS_IMM8(x2, xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
GETEW(x1);
|
||||
emit_shr16(dyn, ninst, x1, x2, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDS_IMM8(x2, xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
GETSEW(x1);
|
||||
emit_sar16(dyn, ninst, x1, x2, x2, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1058,19 +1149,20 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETEW(x1);
|
||||
SMULBB(x2, xEAX, ed);
|
||||
UFLAG_RES(x2);
|
||||
BFI(xEAX, x2, 0, 16);
|
||||
MOV_REG_LSR_IMM5(x2, x2, 16);
|
||||
BFI(xEDX, x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
if(arm_div) {
|
||||
GETEW(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE(x2);
|
||||
UXTH(x2, xEAX, 0);
|
||||
ORR_REG_LSL_IMM5(x2, x2, xEDX, 16);
|
||||
UDIV(x3, x2, ed);
|
||||
@@ -1079,7 +1171,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BFI(xEDX, x14, 0, 16);
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
|
||||
CALL(div16, -1, 0);
|
||||
@@ -1089,7 +1181,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
|
||||
CALL(idiv16, -1, 0);
|
||||
@@ -1128,6 +1220,11 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_dec16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PUSH Ew");
|
||||
GETEW(x1);
|
||||
PUSH16(x1, xESP);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
+453
-59
@@ -21,10 +21,11 @@
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "emu/x86compstrings.h"
|
||||
|
||||
// Get EX as a quad
|
||||
#define GETEX(a, w) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7, w); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -35,12 +36,18 @@
|
||||
#define GETGX(a, w) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
#define GETGX_empty(a) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETG gd = (nextop&0x38)>>3
|
||||
|
||||
uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t eb1, eb2;
|
||||
@@ -66,7 +73,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVUPD Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
@@ -87,7 +94,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -105,7 +112,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVLPD Gx, Eq");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -126,7 +133,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVLPD Eq, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -147,7 +154,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("UNPCKLPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0+1, v1);
|
||||
} else {
|
||||
@@ -161,7 +168,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
VMOVD(v0, v0+1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0+1, v1+1);
|
||||
} else {
|
||||
@@ -174,7 +181,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVHPD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -195,7 +202,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVHPD Ed, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -223,7 +230,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVAPD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
@@ -239,7 +246,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -255,7 +262,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -269,7 +276,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
@@ -286,7 +293,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -460,6 +467,198 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VABSQ_S32(q0, q1);
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("PACKUSDW Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VEORQ(v0, v0, v0);
|
||||
VMAXQ_S32(v1, v0, q0); // values < 0 => 0
|
||||
VQMOVN_U32(q0, v1);
|
||||
if(q0==q1) {
|
||||
VMOV_64(q0+1, q0);
|
||||
} else {
|
||||
VMAXQ_S32(v0, v0, q1);
|
||||
VQMOVN_U32(q0+1, v0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38:
|
||||
INST_NAME("PMINSB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMINQ_S8(q0, q0, q1);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("PMINSD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMINQ_S32(q0, q0, q1);
|
||||
break;
|
||||
case 0x3A:
|
||||
INST_NAME("PMINUW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMINQ_U16(q0, q0, q1);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("PMINUD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMINQ_U32(q0, q0, q1);
|
||||
break;
|
||||
case 0x3C:
|
||||
INST_NAME("PMAXSB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMAXQ_S8(q0, q0, q1);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("PMAXSD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMAXQ_S32(q0, q0, q1);
|
||||
break;
|
||||
case 0x3E:
|
||||
INST_NAME("PMAXUW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMAXQ_U16(q0, q0, q1);
|
||||
break;
|
||||
case 0x3F:
|
||||
INST_NAME("PMAXUD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMINQ_U32(q0, q0, q1);
|
||||
break;
|
||||
case 0x40:
|
||||
INST_NAME("PMULLD Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0);
|
||||
GETGX(q0, 1);
|
||||
VMULQ_32(q0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0xDB:
|
||||
INST_NAME("AESIMC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm_aes) {
|
||||
GETEX(q1, 0);
|
||||
GETGX_empty(q0);
|
||||
AESIMC(q0, q1);
|
||||
} else {
|
||||
GETEX(q1, 0);
|
||||
GETGX_empty(q0);
|
||||
if(q0!=q1) {
|
||||
VMOVQ(q0, q1);
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
MOV32(x1, gd);
|
||||
CALL(arm_aesimc, -1, 0);
|
||||
}
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("AESENC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm_aes) {
|
||||
GETEX(q1, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch_quad(dyn); // 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;
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
MOV32(x1, gd);
|
||||
CALL(arm_aese, -1, 0);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0xDD:
|
||||
INST_NAME("AESENCLAST Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm_aes) {
|
||||
GETEX(q1, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch_quad(dyn); // ARM64 internal operation differs a bit from x86_64
|
||||
VEORQ(v0, q0, q1);
|
||||
AESE(v0, q1);
|
||||
VEORQ(q0, v0, q1);
|
||||
} else {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
MOV32(x1, gd);
|
||||
CALL(arm_aeselast, -1, 0);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0xDE:
|
||||
INST_NAME("AESDEC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm_aes) {
|
||||
GETEX(q1, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch_quad(dyn); // 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;
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
MOV32(x1, gd);
|
||||
CALL(arm_aesd, -1, 0);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("AESDECLAST Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm_aes) {
|
||||
GETEX(q1, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch_quad(dyn); // ARM64 internal operation differs a bit from x86_64
|
||||
VEORQ(v0, q0, q1);
|
||||
AESD(v0, q1);
|
||||
VEORQ(q0, v0, q1);
|
||||
} else {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
MOV32(x1, gd);
|
||||
CALL(arm_aesdlast, -1, 0);
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -468,6 +667,34 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0x3A: // these are some more SSSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0E:
|
||||
INST_NAME("PBLENDW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
u8 = F8;
|
||||
i32 = 0;
|
||||
for(int i=0; i<4; ++i)
|
||||
if((u8&(1<<i)))
|
||||
i32|=(0b11<<(i*2));
|
||||
if(i32 && (q0!=q1)) {
|
||||
VMOV_D64(v0, i32);
|
||||
VBICD(q0, q0, v0);
|
||||
VANDD(v0, q1, v0);
|
||||
VORRD(q0, q0, v0);
|
||||
}
|
||||
i32 = 0;
|
||||
for(int i=0; i<4; ++i)
|
||||
if((u8&(1<<(i+4))))
|
||||
i32|=(0b11<<(i*2));
|
||||
if(i32 && (q0!=q1)) {
|
||||
VMOV_D64(v0, i32);
|
||||
VBICD(q0+1, q0+1, v0);
|
||||
VANDD(v0, q1+1, v0);
|
||||
VORRD(q0+1, q0+1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x0F:
|
||||
INST_NAME("PALIGNR Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -484,6 +711,163 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VEXTQ_8(q0, q1, q0, u8);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("PEXTRD Ed, Gx, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
VMOVfrDx_32(ed, q0+((u8&2)>>1), u8&1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
VST1LANE_32(q0+((u8&2)>>1), wback, u8&1);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("PINSRB Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
VMOVtoDx_8(q0+((u8&8)>>3), u8&7, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
VLD1LANE_8(q0+((u8&8)>>3), wback, u8&7);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x22:
|
||||
INST_NAME("PINSRD Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
VMOVtoDx_32(q0+((u8&2)>>1), u8&1, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
VLD1LANE_32(q0+((u8&2)>>1), wback, u8&1);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm_pmull) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
u8 = F8;
|
||||
switch (u8&0b00010001) {
|
||||
case 0b00000000:
|
||||
VMULL_P64(q0, q0, q1);
|
||||
break;
|
||||
case 0b00010001:
|
||||
VMULL_P64(q0, q0+1, q1+1);
|
||||
break;
|
||||
case 0b00000001:
|
||||
VMULL_P64(q0, q0+1, q1);
|
||||
break;
|
||||
case 0b00010000:
|
||||
VMULL_P64(q0, q0, q1+1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
if(MODREG) {
|
||||
ed = nextop&7;
|
||||
sse_forget_reg(dyn, ninst, ed, x1);
|
||||
MOV32(x2, ed);
|
||||
} else {
|
||||
MOV32(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x2) {
|
||||
MOV_REG(x2, ed);
|
||||
}
|
||||
}
|
||||
MOV32(x1, gd); // gx
|
||||
u8 = F8;
|
||||
MOV32(x3, u8);
|
||||
CALL(arm_pclmul, -1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x63:
|
||||
INST_NAME("PCMPISTRI Gx, Ex, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(!sse_reflect_reg(dyn, ninst, gd, x2)) {
|
||||
u32 = offsetof(x86emu_t, xmm[gd]);
|
||||
if(!(u32&3) && (u32>>2)<256) {
|
||||
ADD_IMM8_ROR(x2, xEmu, u32>>2, 15);
|
||||
} else {
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x2, xEmu, x2, 0);
|
||||
}
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
if(!sse_reflect_reg(dyn, ninst, ed, x1)) {
|
||||
u32 = offsetof(x86emu_t, xmm[ed]);
|
||||
if(!(u32&3) && (u32>>2)<256) {
|
||||
ADD_IMM8_ROR(x1, xEmu, u32>>2, 15);
|
||||
} else {
|
||||
MOV32(x1, u32);
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x1, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32(x3, u8);
|
||||
CALL(sse42_compare_string_implicit_len, x1, 0);
|
||||
CMPS_IMM8(x1, 0);
|
||||
MOVW_COND(cEQ, xECX, (u8&1)?8:16);
|
||||
if(u8&0b1000000) {
|
||||
CLZ_COND(cNE, xECX, x1);
|
||||
RSB_COND_IMM8(cNE, xECX, xECX, 31);
|
||||
} else {
|
||||
RBIT_COND(cNE, xECX, x1);
|
||||
CLZ_COND(cNE, xECX, xECX);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDF:
|
||||
INST_NAME("AESKEYGENASSIST Gx, Ex, Ib"); // AES-NI
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd, x1);
|
||||
MOV32(x1, gd); // gx
|
||||
if(MODREG) {
|
||||
ed = nextop&7;
|
||||
sse_forget_reg(dyn, ninst, ed, x2);
|
||||
MOV32(x2, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x2) {
|
||||
MOV_REG(x2, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32(x3, u8);
|
||||
CALL(arm_aeskeygenassist, -1, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -494,7 +878,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -602,7 +986,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = xEAX+((nextop&0x38)>>3);
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
q1 = q0;
|
||||
@@ -727,11 +1111,21 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
q1 = v1;
|
||||
// need rounding!
|
||||
//VCVTQ_S32_F32(v0, v1);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
VCVTR_S32_F32(q0*2+0, q1*2+0);
|
||||
VCVTR_S32_F32(q0*2+1, q1*2+1);
|
||||
VCVTR_S32_F32(q0*2+2, q1*2+2);
|
||||
VCVTR_S32_F32(q0*2+3, q1*2+3);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = sse_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
else
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
for(int i=0; i<4; ++i) {
|
||||
VCVTR_S32_F32(q0*2+i, q1*2+i);
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU exception (IO only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, x1, 0b10, 1); // 0x80000000
|
||||
VMOVtoVcond(cNE, q0*2+i, x1);
|
||||
BIC_IMM8_COND(cNE, x3, x3, 1, 0); // reset FPU
|
||||
VMSR_cond(cNE, x3);
|
||||
}
|
||||
}
|
||||
if(q0!=v0) {
|
||||
VMOVQ(v0, q0);
|
||||
}
|
||||
@@ -936,7 +1330,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0+1, v1);
|
||||
} else {
|
||||
@@ -950,7 +1344,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
VMOVD(q0, q0+1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(q0+1, q1+1);
|
||||
} else {
|
||||
@@ -972,7 +1366,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDQA Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
@@ -988,7 +1382,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
i32 = -1;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
u8 = F8;
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
@@ -1119,7 +1513,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLW Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1142,7 +1536,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAW Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1161,7 +1555,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLW Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1192,7 +1586,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLD Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1215,7 +1609,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAD Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1234,7 +1628,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLD Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1264,7 +1658,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLQ Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1287,7 +1681,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("PSRLDQ Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1312,7 +1706,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLQ Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1335,7 +1729,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("PSLLDQ Ex, Ib");
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1389,7 +1783,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX + (nextop&7);
|
||||
VMOVfrDx_32(ed, v0, 0);
|
||||
} else {
|
||||
@@ -1403,7 +1797,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDQA Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -1419,7 +1813,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, so 32bits is the same (no need for GETGW)
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7); // no need for extract
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1442,7 +1836,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEWW(x14, x1);
|
||||
GETGW(x2);
|
||||
if(opcode==0xA4) {
|
||||
@@ -1461,7 +1855,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0; // no need for extract
|
||||
} else {
|
||||
@@ -1494,7 +1888,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEWW(x14, x1);
|
||||
GETGW(x2);
|
||||
if(opcode==0xAC) {
|
||||
@@ -1511,8 +1905,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
@@ -1523,6 +1916,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SMULBB(x2, gd, ed);
|
||||
UFLAG_RES(x2);
|
||||
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
@@ -1531,7 +1925,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0; // no need for extract
|
||||
} else {
|
||||
@@ -1560,7 +1954,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVZX Gw, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
@@ -1576,7 +1970,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVZX Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX + (nextop&7);
|
||||
UXTH(x1, ed, 0);
|
||||
} else {
|
||||
@@ -1594,7 +1988,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("BT Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1614,7 +2008,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("BTS Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1645,7 +2039,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("BTR Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1676,7 +2070,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("BTC Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -1712,7 +2106,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0; // no need for extract
|
||||
} else {
|
||||
@@ -1771,7 +2165,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
@@ -1844,7 +2238,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("PINSRW Gx,Ed,Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
u8 = (F8)&7;
|
||||
ed = xEAX+(nextop&7);
|
||||
VMOVtoDx_16(v0+(u8/4), u8&3, ed);
|
||||
@@ -1859,7 +2253,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("PEXTRW Gd,Ex,Ib");
|
||||
nextop = F8;
|
||||
gd = xEAX+((nextop&0x38)>>3);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETEX(v0, 0);
|
||||
u8 = (F8)&7;
|
||||
VMOVfrDx_U16(gd, v0+(u8/4), (u8&3));
|
||||
@@ -1973,7 +2367,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVQ Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVD(q1, q0);
|
||||
VEOR(q1+1, q1+1, q1+1);
|
||||
@@ -1994,7 +2388,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 0xD7:
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
INST_NAME("PMOVMSKB Gd, Ex");
|
||||
GETEX(q0, 0);
|
||||
gd = xEAX+((nextop&0x38)>>3);
|
||||
@@ -2165,7 +2559,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -2280,7 +2674,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q0, v0);
|
||||
VTRN_32(q0, q0+1); // transpose GX
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else {
|
||||
@@ -2317,7 +2711,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETEX(q1, 0);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_8(v0, xEDI); // hopefully it's always aligned?
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
v1 = fpu_get_scratch_quad(dyn); // need to preserve the register
|
||||
else
|
||||
v1 = q1;
|
||||
|
||||
@@ -41,7 +41,6 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
@@ -50,8 +49,7 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("LOCK ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add16c(dyn, ninst, ed, i16, x3, x14);
|
||||
@@ -69,9 +67,9 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
SMDMB();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
@@ -84,8 +82,8 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -101,7 +99,7 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0: // INC Ew
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
@@ -118,9 +116,9 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
SMDMB();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
@@ -133,13 +131,14 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETEW(x1);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
@@ -156,9 +155,9 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
SMDMB();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
@@ -171,6 +170,7 @@ uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -50,7 +50,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
@@ -67,7 +67,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(gd, ed, 0, 16);
|
||||
@@ -83,7 +83,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
@@ -123,7 +123,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
|
||||
@@ -33,6 +33,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
@@ -52,11 +53,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, v2);
|
||||
} else {
|
||||
VADD_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -69,11 +74,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, v2);
|
||||
} else {
|
||||
VMUL_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -110,7 +119,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -123,11 +132,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -140,11 +153,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -157,11 +174,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -174,11 +195,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -196,12 +221,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VADD_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
@@ -216,12 +245,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VMUL_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
@@ -264,7 +297,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, d1);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
@@ -279,12 +312,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
@@ -299,12 +336,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, s0, v1);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, d1, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
@@ -319,12 +360,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
@@ -339,12 +384,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, s0, v1);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
+142
-68
@@ -67,7 +67,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v2 = x87_do_push(dyn, ninst, x3, X87_ST(nextop&7));
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x3, X87_ST(nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_32(v2, v1);
|
||||
@@ -134,25 +134,49 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
|
||||
// value put in x14
|
||||
if(i1==-1) {
|
||||
// not in cache, so check Empty status and load it
|
||||
// x14 will be the actual top
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
i2 = -dyn->n.x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
} else {
|
||||
ADD_IMM8(x14, x14, i2);
|
||||
if(fpu_is_st_freed(dyn, ninst, 0)) {
|
||||
MOV32(x14, 0b100000100000000);
|
||||
B_MARK3(c__);
|
||||
} else { // not in cache, so check Empty status and load it
|
||||
// load tag
|
||||
LDRH_IMM8(x3, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
MOV_REG_LSL_IMM5(x3, x3, -i2*2);
|
||||
} else {
|
||||
MOV32(x14, 0xffff);
|
||||
ORR_REG_LSL_IMM5(x3, x3, x14, 16);
|
||||
MOV_REG_LSR_IMM5(x3, x3, i2*2);
|
||||
}
|
||||
}
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
TSTS_IMM8(x3, 0b11);
|
||||
MOVW(x14, 0b100000100000000); // empty
|
||||
B_MARK3(cNE);
|
||||
// check stack TODO: this test should not be needed, something is wrong with tag handling
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
ADD_IMM8(x3, x3, -i2);
|
||||
} else {
|
||||
SUB_IMM8(x3, x3, i2);
|
||||
}
|
||||
}
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK3(cLE);
|
||||
// x14 will be the actual top
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
i2 = -dyn->n.x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
} else {
|
||||
ADD_IMM8(x14, x14, i2);
|
||||
}
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 3);
|
||||
LDRD_IMM8(x2, x1, offsetof(x86emu_t, x87)); // load r2/r3 with ST0 anyway, for sign extraction
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 3);
|
||||
LDRD_IMM8(x2, x1, offsetof(x86emu_t, x87)); // load r2/r3 with ST0 anyway, for sign extraction
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 2);
|
||||
LDR_IMM9(x1, x1, offsetof(x86emu_t, p_regs));
|
||||
CMPS_IMM8(x1, 0b11);
|
||||
MOVW_COND(cEQ, x14, 0b100000100000000); // empty: C3,C2,C0 = 101
|
||||
B_MARK3(cEQ);
|
||||
} else {
|
||||
// simply move from cache reg to r2/r3
|
||||
v1 = dyn->n.x87reg[i1];
|
||||
@@ -194,7 +218,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v1, 0b01110000);
|
||||
} else {
|
||||
@@ -204,7 +228,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2t));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -216,7 +240,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2e));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -228,7 +252,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_pi));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -240,7 +264,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_lg2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -252,7 +276,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_ln2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -264,7 +288,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_8(v1/2, 0); // float is *2...
|
||||
} else {
|
||||
@@ -281,18 +305,20 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CALL(arm_f2xm1, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
//if(ST0.d!=0.0)
|
||||
// ST0.d = exp2(ST0.d)-1.0;
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(exp2, 0); // return is d0
|
||||
if((PK(0)==0xD9 && PK(1)==0xE8) && // next inst is FLD1
|
||||
(PK(2)==0xDE && PK(3)==0xC1)) {
|
||||
MESSAGE(LOG_DUMP, "Hack for fld1 / faddp st1, st0\n");
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(exp2, 0); // return is d0
|
||||
VMOV_64(v1, 0);
|
||||
addr+=4;
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000); // 1.0
|
||||
VSUB_F64(v1, 0, v1);
|
||||
//ST0.d = expm1(LN2 * ST0.d);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(0, x2, 0);
|
||||
VMUL_F64(0, 0, v1);
|
||||
CALL_1D(expm1, 0); // return is d0
|
||||
VMOV_64(v1, 0);
|
||||
}
|
||||
#endif
|
||||
// should set C1 to 0
|
||||
@@ -301,44 +327,58 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FYL2X");
|
||||
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);
|
||||
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d)*ST(1).d
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
v2 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
// seems that tan of glib doesn't follow the rounding direction mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1); // prepare call to tan
|
||||
CALL_1D(tan, 0);
|
||||
CALL_1D(tan, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C1 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 9, 2); //C1 C2 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
|
||||
// and want 1.0 = 0x3ff0000000000000
|
||||
// so 00111111 11110000 00000000 00000000....
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v2, 0b01110000);
|
||||
if(PK(0)==0xdd && PK(1)==0xd8) {
|
||||
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emiting 1\n");
|
||||
} else {
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
|
||||
// and want 1.0 = 0x3ff0000000000000
|
||||
// so 00111111 11110000 00000000 00000000....
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v2, 0b01110000);
|
||||
} else {
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
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);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v2); // prepare call to atan2
|
||||
VMOV_64(1, v1);
|
||||
CALL_2D(atan2, 0);
|
||||
CALL_2D(atan2, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v2, 0); //ST(1).d = atan2(ST1.d, ST0.d);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF4:
|
||||
@@ -346,7 +386,9 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(arm_fxtract, -1, 0);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
case 0xF5:
|
||||
@@ -445,32 +487,45 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FYL2XP1");
|
||||
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);
|
||||
VMOV_i_64(0, 0b01110000); // D0 = 1.0
|
||||
VADD_F64(0, 0, v1); // prepare call to log2
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
|
||||
//ST(1).d = (ST(1).d * log1p(ST0.d)) / M_LN2;
|
||||
VMOV_64(0, v1); // prepare call to log1p
|
||||
CALL_1D(log1p, 0);
|
||||
VMUL_F64(v2, v2, 0);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(0, x2, 0);
|
||||
VDIV_F64(v2, v2, 0);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
// seems that sin and cos function of glibc don't follow the rounding mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(sin, 0);
|
||||
CALL_1D(sin, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VSWP(v1, 0);
|
||||
CALL_1D(cos, 0); // would it be faster to do sqrt(1-sin()²) ???
|
||||
CALL_1D(cos, box86_dynarec_fastround ? 0 : (1 << u8)); // would it be faster to do sqrt(1-sin()²) ???
|
||||
VMOV_64(v2, 0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
@@ -505,26 +560,32 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
//if(ST0.d!=0.0)
|
||||
// ST0.d *= exp2(trunc(ST1.d));
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cEQ);
|
||||
if(!arm_v8) {
|
||||
VMOV_64(0, v2);
|
||||
CALL_1DD(trunc, exp2, 0);
|
||||
} else {
|
||||
VRINTZ_F64(0, v2);
|
||||
CALL_1D(exp2, 0);
|
||||
}
|
||||
VMUL_F64(v1, v1, 0);
|
||||
// ST0.d = ldexp(ST0.d, trunc(ST1.d));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// value of s0 =
|
||||
// 2^31-1 (ST1 >= 2^31), -2^31 (ST1 < -2^31) or int(ST1) (other situations)
|
||||
VCVT_S32_F64(s0 , v2);
|
||||
VMOVfrV(x2, s0);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1DDR(ldexp, x2, x3, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
// seems that sin of glib doesn't follow the rounding direction mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1); // prepare call to sin
|
||||
CALL_1D(sin, 0);
|
||||
CALL_1D(sin, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
@@ -533,9 +594,14 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
// seems that cos of glib doesn't follow the rounding direction mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1); // prepare call to cos
|
||||
CALL_1D(cos, 0);
|
||||
CALL_1D(cos, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
@@ -568,7 +634,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
@@ -594,7 +660,11 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
@@ -613,7 +683,11 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
@@ -624,7 +698,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
|
||||
@@ -33,6 +33,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int d0;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(d0);
|
||||
@@ -128,8 +129,8 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -155,7 +156,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VADD_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
@@ -165,7 +170,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMUL_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
@@ -188,7 +197,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VCMP_F64(v1, d0);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
@@ -198,7 +207,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
@@ -208,7 +221,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, d0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
@@ -218,7 +235,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
@@ -228,7 +249,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, d0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -160,7 +160,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -183,7 +183,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
@@ -218,7 +218,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
VMSR(x14); // put back values
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
@@ -260,7 +260,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
@@ -268,20 +268,18 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDR_IMM9(x2, ed, 0);
|
||||
LDR_IMM9(x3, ed, 4);
|
||||
LDM(ed, (1<<x2)|(1<<x3));
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; //0xDB
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
STM(ed, (1<<x2)|(1<<x3));
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
} else {
|
||||
if(box86_x87_no80bits) {
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if (parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
@@ -298,10 +296,10 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
X87_PUSH_OR_FAIL_empty( , dyn, ninst, x3);
|
||||
CALL(arm_fld, -1, 0);
|
||||
#else
|
||||
v1 = x87_do_push(dyn, ninst, x2, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x2, NEON_CACHE_ST_D);
|
||||
// copy 10bytes of *ED to STld(0)
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, top));
|
||||
int a = -dyn->n.x87stack;
|
||||
@@ -407,7 +405,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK2;
|
||||
#endif
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -31,6 +31,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(v2);
|
||||
@@ -48,11 +49,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FADD STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, v2);
|
||||
} else {
|
||||
VADD_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -65,11 +70,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FMUL STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, v2);
|
||||
} else {
|
||||
VMUL_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -106,7 +115,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -119,11 +128,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -136,11 +149,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUB STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -153,11 +170,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -170,11 +191,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIV STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -192,7 +217,11 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VADD_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
@@ -208,7 +237,11 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMUL_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
@@ -243,7 +276,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
@@ -259,7 +292,11 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
@@ -275,7 +312,11 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, d1, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
@@ -291,7 +332,11 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
@@ -307,7 +352,11 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint8_t ed;
|
||||
int v1, v2;
|
||||
int i1, i2, i3;
|
||||
int j32;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -45,10 +46,21 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
#if 1
|
||||
if((nextop&7)==0 && PK(0)==0xD9 && PK(1)==0xF7) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FFREE ST0 / FINCSTP\n");
|
||||
X87_POP_OR_FAIL(dyn, ninst, x1);
|
||||
addr+=2;
|
||||
SKIPTEST(x1, x14);
|
||||
} else
|
||||
x87_free(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
#else
|
||||
INST_NAME("FFREE STx");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOVW(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1, 0);
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -69,7 +81,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -81,7 +93,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -119,7 +131,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -153,7 +165,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if (parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
@@ -167,11 +179,54 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistt64, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(ninst
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)dyn->insts[ninst-1].x86.addr==0xDF
|
||||
&& (((*(uint8_t*)(dyn->insts[ninst-1].x86.addr+1))>>3)&7)==5)
|
||||
{
|
||||
if(parity) {
|
||||
STRD_IMM8(x2, ed, 0); // x2/x3 is 64bits
|
||||
} else {
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0, NEON_CACHE_ST_D);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
fpu_get_scratch_double(dyn); // to alocate v0
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(x14, x14, a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, offsetof(fpu_ll_t, sref));
|
||||
VLDR_64(v2, x14, 0);
|
||||
VCEQ_32(v2, v2, v1); // compare
|
||||
VMOVfrV_D(x2, x3, v2);
|
||||
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
|
||||
B_MARK(cEQ); // do the i64 conversion
|
||||
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
LDRD_IMM8(x2, x14, offsetof(fpu_ll_t, sq)); // load ll
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV32(x2, arm_fist64_3);
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1DR_U64(x2, x2, x3, x14, (1<<x1));
|
||||
MARK3;
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
@@ -200,7 +255,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
@@ -215,6 +270,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1, 0);
|
||||
CALL(reset_fpu, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "dynarec/arm_emitter.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86run.h"
|
||||
@@ -27,6 +28,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
int v1, v2;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -43,12 +45,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v2, v2, v1);
|
||||
} else {
|
||||
VADD_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -61,12 +67,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v2, v2, v1);
|
||||
} else {
|
||||
VMUL_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -85,7 +95,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD9:
|
||||
@@ -98,8 +108,8 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -112,12 +122,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v2, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v2, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -130,12 +144,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v2, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -148,12 +166,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v2, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -166,11 +188,21 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastnan) {
|
||||
if(!box86_dynarec_fastround || !box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
} else if(!box86_dynarec_fastround)
|
||||
MOV_REG(x3, x14);
|
||||
if(!box86_dynarec_fastround){
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x1, x1, 10, 2); // extract round...
|
||||
UBFX(x2, x1, 1, 1); // swap bits 0 and 1
|
||||
BFI(x2, x1, 1, 1);
|
||||
BFI(x3, x2, 22, 2); // inject new round
|
||||
}
|
||||
VMSR(x3); // put new fpscr
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v2, v1);
|
||||
@@ -185,9 +217,10 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VNEG_F64_cond(cNE, v2, v2);
|
||||
}
|
||||
VMSR(x14); // restore fpscr
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround || !box86_dynarec_fastnan)
|
||||
VMSR(x14); // restore fpscr
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
|
||||
@@ -53,7 +53,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -81,7 +81,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0))
|
||||
@@ -91,7 +91,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -102,7 +102,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0))
|
||||
@@ -112,7 +112,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -161,7 +161,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -186,9 +186,9 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
VCVT_S32_F32(s0, v1);
|
||||
} else {
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
}
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
@@ -197,7 +197,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
VMSR(x14);
|
||||
break;
|
||||
case 2:
|
||||
@@ -242,20 +242,22 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbld, -1, 0);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
@@ -314,8 +316,10 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbst, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 7: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
@@ -333,12 +337,10 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
#if 1
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0, NEON_CACHE_ST_D);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
fpu_get_scratch_double(dyn); // to alocate v0
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
#if 1
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
@@ -371,76 +373,8 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK3;
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
#else
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// check STll(0).ref==ST(0).q so emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top]
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(x14, x14, a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, 0);
|
||||
VLDR_64(v2, x14, 0);
|
||||
VCEQ_32(v2, v2, v1); // compare
|
||||
VMOVfrV_D(x2, x3, v2);
|
||||
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
|
||||
B_MARK(cEQ); // do the i64 conversion
|
||||
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
LDRD_IMM8(x2, x14, 8); // load ll
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
VEOR(v0, v0, v0);
|
||||
MOVW(x2, 0x41F0);
|
||||
VMOVtoDx_16(v0, 3, x2); // V0 = (1<<32) as double
|
||||
VMOVfrDx_32(x14, v1, 1); // get high part to extract sign
|
||||
VABS_F64(v1 ,v1); //ST0 will be poped, so lost...
|
||||
VDIV_F64(v2, v1, v0); // v2 = abs(ST0)/(1<<32) : so 32 bits high part
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x2); // get fpscr
|
||||
ORR_IMM8(x3, x2, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_U32_F64(s0, v2); // convert high part to U32
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMSR(x2); // put back fpscr
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
B_MARK2(cEQ); // not overflow...
|
||||
MARKLOCK;
|
||||
MOV_IMM(x3, 0b10, 1); // 0x80000000
|
||||
MOVW(x2, 0);
|
||||
B_MARK3(c__);
|
||||
MARK2; // continue conversion, it fits an int64!
|
||||
VCVT_F64_U32(v2, s0); // int part now
|
||||
VMLS_F64(v1, v2, v0); // compute low part
|
||||
VMOVfrV(x3, s0); // transfert high path
|
||||
TSTS_IMM8_ROR(x14, 0b10, 1); // test high part with 0x800000000
|
||||
B_MARKLOCK(cNE); // int overflow...
|
||||
VCVT_U32_F64(s0, v1); // convert low part
|
||||
VMOVfrV(x2, s0); // transfert low part
|
||||
TSTS_IMM8_ROR(x14, 0b10, 1); // 0x800000000
|
||||
B_MARK3(cEQ);
|
||||
RSBS_IMM8(x2, x2, 0); // NEG(i64)
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
MARK3;
|
||||
STR_IMM9(x2, x1, 0);
|
||||
STR_IMM9(x3, x1, 4);
|
||||
#endif
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x2, x3, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
#endif
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -53,7 +53,7 @@ void emit_or32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ void emit_xor32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ void emit_and32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ void emit_or8(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ void emit_xor8(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,7 +428,7 @@ void emit_and8(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +497,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +540,7 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +574,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -617,7 +617,7 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,7 +651,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,6 +694,6 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ void emit_add32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ void emit_sub32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -390,7 +390,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -495,7 +495,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,7 +547,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -615,7 +615,7 @@ void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,7 +668,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -734,7 +734,7 @@ void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,7 +823,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,7 +915,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +923,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -960,7 +960,7 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1006,7 +1006,7 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@ void emit_adc32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1127,7 +1127,7 @@ void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,7 +1179,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1232,7 +1232,7 @@ void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1285,7 +1285,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1353,7 +1353,7 @@ void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1407,7 +1407,7 @@ void emit_sbb32(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1479,7 +1479,7 @@ void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1533,7 +1533,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1587,7 +1587,7 @@ void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1642,7 +1642,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1710,7 +1710,7 @@ void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int c, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1758,7 +1758,7 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1807,7 +1807,7 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1855,6 +1855,6 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, 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);
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,17 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s2);
|
||||
} else {
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
@@ -162,27 +172,16 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF), 0);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +202,21 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
@@ -211,28 +224,16 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF), 0);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +275,567 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL8 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
RSB_IMM8(s4, s2, 8);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_REG(s1, s1, s2);
|
||||
IFX(X_ZF) {
|
||||
ANDS_IMM8(s1, s1, 0xff);
|
||||
} else IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOV32(s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 7);}
|
||||
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c<8) {
|
||||
IFX(X_CF|X_OF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 8-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s4, s1, 7);}
|
||||
XOR_REG_LSL_IMM5(s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSL_IMM5(s3, s1, c-1);
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOVW(s1, 0);
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BFC(xFlags, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF | X_ZF) {
|
||||
MOVW(s3, 1);
|
||||
IFX(X_ZF) {
|
||||
BFI(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFI(xFlags, s3, F_PF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 7);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFI(xFlags, s1, 0, 1);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR8 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_ASR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_ASR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL16 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
RSB_IMM8(s4, s2, 16);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_REG(s1, s1, s2);
|
||||
UBFX(s1, s1, 0, 16);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOV32(s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 15);}
|
||||
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c<16) {
|
||||
IFX(X_CF|X_OF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 16-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
|
||||
UBFX(s1, s1, 0, 16);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s4, s1, 15);}
|
||||
XOR_REG_LSL_IMM5(s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSL_IMM5(s3, s1, c-1);
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOVW(s1, 0);
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BFC(xFlags, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF | X_ZF) {
|
||||
MOVW(s3, 1);
|
||||
IFX(X_ZF) {
|
||||
BFI(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFI(xFlags, s3, F_PF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 16);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFI(xFlags, s1, 0, 1);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR16 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_ASR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_REG(s1, s1, s2);
|
||||
UBFX(s1, s1, 0, 16);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_ASR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND | X_ZF) {
|
||||
UXTH(s1, s1, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,6 +926,12 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
@@ -394,13 +960,15 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8(s4, s4, xFlags, F_OF); // set if sign changed
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,6 +993,12 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
@@ -436,9 +1010,9 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
UBFX(s3, s1, (31-c), 1);
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8(s4, s4, xFlags, F_OF); // set if sign changed
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
@@ -461,7 +1035,7 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +1048,7 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shr32
|
||||
SET_DF(s4, d_shr32);
|
||||
SET_DF(s4, d_shrd32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
@@ -484,6 +1058,10 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s3);
|
||||
} else {
|
||||
@@ -513,12 +1091,12 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s3, 31); // 32-c
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, xFlags, F_OF);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,7 +1109,7 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shl32
|
||||
SET_DF(s4, d_shl32);
|
||||
SET_DF(s4, d_shld32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
@@ -544,6 +1122,10 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
IFX(X_CF) {
|
||||
RSB_IMM8(s4, s3, 32);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
@@ -555,13 +1137,10 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSL_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVW_COND(cCS, s4, 1);
|
||||
MOVW_COND(cCC, s4, 0);
|
||||
CMPS_IMM8(s3, 1);
|
||||
ORR_REG_LSR_IMM5_COND(cEQ, s4, s4, s1, 30);
|
||||
CMPS_IMM8(s3, 31); // 32-c
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, xFlags, F_OF);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
//else
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
RSB_IMM8(s3, s3, 32);
|
||||
IFX(X_ZF) {
|
||||
@@ -581,7 +1160,7 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,8 +1181,8 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
return;
|
||||
}
|
||||
if(c&7) {
|
||||
BFI(s1, s1, 24, 8); // duplicate the value for rotate left
|
||||
MOV_REG_ROR_IMM5(s1, s1, 32-(c&7));
|
||||
BFI(s1, s1, 8, 8);
|
||||
MOV_REG_LSR_IMM5(s1, s1, 8-(c&7));
|
||||
}
|
||||
//AND_IMM8(s1, s1, 0xff);
|
||||
IFX(X_PEND) {
|
||||
@@ -614,7 +1193,7 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADD_REG_LSR_IMM5(s3, s1, s1, 7);
|
||||
XOR_REG_LSR_IMM8(s3, s1, s1, 7);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
@@ -638,7 +1217,7 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
if(c&7) {
|
||||
BFI(s1, s1, 8, 8); // duplicate the value for Rotate right
|
||||
MOV_REG_ROR_IMM5(s1, s1, c&7);
|
||||
MOV_REG_LSR_IMM5(s1, s1, c&7);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
@@ -656,3 +1235,75 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_rol16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(c&15) {
|
||||
BFI(s1, s1, 16, 16);
|
||||
MOV_REG_LSR_IMM5(s1, s1, 16-(c&15));
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
UBFX(s1, s1, 0, 16);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
XOR_REG_LSR_IMM8(s3, s1, s1, 15);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_ror16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(c&15) {
|
||||
BFI(s1, s1, 16, 16); // duplicate the value for Rotate right
|
||||
MOV_REG_LSR_IMM5(s1, s1, c&15);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
UBFX(s1, s1, 0, 16);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 14);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,10 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), AF
|
||||
IFX(X_AF) {
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
@@ -68,19 +71,6 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_CF|X_AF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
@@ -112,7 +102,7 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +130,9 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
@@ -161,18 +154,6 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
@@ -204,7 +185,7 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
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
|
||||
@@ -230,6 +211,9 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
@@ -251,18 +235,6 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
@@ -292,7 +264,7 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,19 +293,8 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
if(s1==s2) {
|
||||
AND_IMM8(s3, s1, 31);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
}
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,15 +323,8 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,13 +353,7 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s2, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s2, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
+121
-104
@@ -42,8 +42,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
@@ -66,8 +65,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -85,8 +83,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK OR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETGB(x2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
@@ -111,8 +108,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_or32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -132,8 +128,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
@@ -157,8 +152,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_adc32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -178,8 +172,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
@@ -203,8 +196,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sbb32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -222,8 +214,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETGB(x2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
@@ -248,8 +239,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_and32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -268,8 +258,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
@@ -292,8 +281,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sub32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -311,8 +299,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK XOR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETGB(x2);
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
@@ -337,8 +324,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_xor32(dyn, ninst, ed, gd, x3, x14);
|
||||
} else {
|
||||
@@ -368,8 +354,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x14);
|
||||
@@ -409,8 +394,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x14);
|
||||
@@ -430,8 +414,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(opcode==0x81) {INST_NAME("LOCK ADC Ed, Id");} else {INST_NAME("LOCK ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
|
||||
@@ -451,8 +434,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(opcode==0x81) {INST_NAME("LOCK SBB Ed, Id");} else {INST_NAME("LOCK SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
|
||||
@@ -471,8 +453,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("LOCK AND Ed, Id");} else {INST_NAME("LOCK AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x14);
|
||||
@@ -491,12 +472,11 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SUB Ed, Id");} else {INST_NAME("LOCK SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
if(!fixedaddress) {
|
||||
@@ -532,12 +512,11 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("LOCK XOR Ed, Id");} else {INST_NAME("LOCK XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
|
||||
} else {
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
MARKLOCK;
|
||||
@@ -552,7 +531,6 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("(LOCK) CMP Ed, Id");} else {INST_NAME("(LOCK) CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
GETEDH(x1);
|
||||
// No need to LOCK, this is readonly
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
@@ -566,7 +544,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
// generic case, no lock needed, the value is only read (note that on x86 locked read is always followed wy a locked write)
|
||||
// generic case, no lock needed, the value is only read (note that on x86 locked read is always followed by a locked write)
|
||||
#define GO(A) \
|
||||
case A+0x02: \
|
||||
case A+0x03: \
|
||||
@@ -585,17 +563,6 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SMDMB();
|
||||
--addr;
|
||||
break;
|
||||
case 0x90: // This is xchg reg, reg, so let's ignore the LOCK prefix...
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
SMDMB();
|
||||
--addr;
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
@@ -603,9 +570,8 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xB0:
|
||||
INST_NAME("LOCK CMPXCHG Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMDMB();
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
@@ -649,8 +615,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
// same as no lock, all in regs...
|
||||
CMPS_REG_LSL_IMM5(xEAX, ed, 0);
|
||||
@@ -721,8 +686,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -736,30 +700,26 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
AND_IMM8(x2, gd, 0x1f);
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cEQ); // bit already clear, jump to end of instruction
|
||||
MOVW(x14, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
BIC_REG_LSL_REG(ed, ed, x14, x2);
|
||||
if(wback) {
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
MARK3;
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("(LOCK) BT Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
gd = x2;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095-32, 0, 0, LOCK_LOCK);
|
||||
@@ -778,26 +738,21 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
gd = x2;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
MOVW(gd, u8&0x1f);
|
||||
u8 = F8&0x1f;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
u8 = F8;
|
||||
u8 = F8&0x1f;
|
||||
ed = x1;
|
||||
MOVW(gd, u8&0x1f);
|
||||
MARKLOCK;
|
||||
LDREX(ed, wback);
|
||||
}
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
MOV_REG_LSR_IMM5(x14, ed, u8);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cNE); // bit already set, jump to next instruction
|
||||
MOVW(x14, 1);
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
BFI(ed, x14, u8, 1);
|
||||
if(wback) {
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
@@ -809,26 +764,46 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("LOCK BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
gd = x2;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8;
|
||||
MOVW(gd, u8&0x1f);
|
||||
u8 = F8&0x1f;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
u8 = F8;
|
||||
u8 = F8&0x1f;
|
||||
ed = x1;
|
||||
MOVW(gd, u8&0x1f);
|
||||
MARKLOCK;
|
||||
LDREX(ed, wback);
|
||||
}
|
||||
MOV_REG_LSR_REG(x14, ed, x2);
|
||||
ANDS_IMM8(x14, x14, 1);
|
||||
MOV_REG_LSR_IMM5(x14, ed, u8);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
B_MARK3(cEQ); // bit already clear, jump to next instruction
|
||||
//MOVW(x14, 1); // already 0x01
|
||||
XOR_REG_LSL_REG(ed, ed, x14, x2);
|
||||
BFC(ed, u8, 1);
|
||||
if(wback) {
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("LOCK BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u8 = F8&0x1f;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
u8 = F8&0x1f;
|
||||
ed = x1;
|
||||
MARKLOCK;
|
||||
LDREX(ed, wback);
|
||||
}
|
||||
MOV_REG_LSR_IMM5(x14, ed, u8);
|
||||
BFI(xFlags, x14, F_CF, 1);
|
||||
MOV32(x14, 1);
|
||||
XOR_REG_LSL_IMM5(ed, ed, x14, u8);
|
||||
if(wback) {
|
||||
STREX(x14, ed, wback);
|
||||
CMPS_IMM8(x14, 0);
|
||||
@@ -847,8 +822,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
@@ -879,7 +853,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
GETGB(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xEAX+(wback&3);
|
||||
@@ -909,8 +883,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(gd!=ed) {
|
||||
XOR_REG_LSL_IMM5(gd, gd, ed, 0); // swap gd, ed
|
||||
@@ -964,7 +937,6 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 1:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
@@ -1010,11 +982,56 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
default:
|
||||
// dafault to NO LOCK
|
||||
addr-=2;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFE:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Eb
|
||||
INST_NAME("INC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if(MODREG) {
|
||||
GETEB(x1);
|
||||
emit_inc8(dyn, ninst, x1, x2, x14);
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_inc8(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if(MODREG) {
|
||||
GETEB(x1);
|
||||
emit_dec8(dyn, ninst, x1, x2, x14);
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
MARKLOCK;
|
||||
LDREXB(x1, wback);
|
||||
emit_dec8(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
@@ -1023,7 +1040,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_inc32(dyn, ninst, ed, x3, x14);
|
||||
} else {
|
||||
@@ -1039,9 +1056,9 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
SMDMB();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
@@ -1054,13 +1071,14 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STR_IMM9(x1, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
} else {
|
||||
@@ -1076,9 +1094,9 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STREX(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
SMDMB();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
@@ -1091,19 +1109,18 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STR_IMM9(x1, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// default to NO LOCK
|
||||
addr-=2;
|
||||
DEFAULT;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
default:
|
||||
// default to NO LOCK
|
||||
--addr;
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x2 and x3 may get used)
|
||||
#define GETEX(a, w) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7,w);\
|
||||
} else { \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3); \
|
||||
@@ -68,7 +68,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0, d0);
|
||||
@@ -87,7 +87,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
VMOVD(d0, v0);
|
||||
} else {
|
||||
@@ -102,7 +102,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, d0);
|
||||
@@ -133,7 +133,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -165,7 +165,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -328,7 +328,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -364,7 +364,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -434,7 +434,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -460,7 +460,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("LDDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
// Get Ex as a single, not a quad, with b a intermediary double
|
||||
#define GETEX(a, b) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
b = sse_get_reg(dyn, ninst, x1, nextop&7,0);\
|
||||
if(b<16) \
|
||||
a = b; \
|
||||
@@ -81,7 +81,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
@@ -121,7 +121,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -156,7 +156,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -173,7 +173,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -223,7 +223,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -268,7 +268,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -420,7 +420,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0x5B:
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -523,7 +523,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
@@ -543,7 +543,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -579,7 +579,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, v1);
|
||||
@@ -596,7 +596,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
@@ -666,7 +666,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVQ2DQ Gx, Em");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV_64(v0, v1);
|
||||
@@ -688,7 +688,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v1<16)
|
||||
v0 = v1;
|
||||
|
||||
@@ -62,19 +62,41 @@ void arm_fpatan(x86emu_t* emu)
|
||||
}
|
||||
void arm_fxtract(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
int tmp32s;
|
||||
if(isnan(ST1.d)) {
|
||||
ST0.d = ST1.d;
|
||||
} else if(isinf(ST1.d)) {
|
||||
ST0.d = ST1.d;
|
||||
ST1.d = INFINITY;
|
||||
} else if(ST1.d==0.0) {
|
||||
ST0.d = ST1.d;
|
||||
ST1.d = -INFINITY;
|
||||
} else {
|
||||
// LD80bits doesn't have implicit "1" bit, so need to adjust for that
|
||||
ST0.d = frexp(ST1.d, &tmp32s)*2;
|
||||
ST1.d = tmp32s-1;
|
||||
}
|
||||
}
|
||||
void arm_fprem(x86emu_t* emu)
|
||||
{
|
||||
int64_t tmp64s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp64s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (tmp64s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp64s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
int e0, e1;
|
||||
int64_t ll;
|
||||
frexp(ST0.d, &e0);
|
||||
frexp(ST1.d, &e1);
|
||||
int32_t tmp32s = e0 - e1;
|
||||
if(tmp32s<64)
|
||||
{
|
||||
ll = (int64_t)floor(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll&1)?1:0;
|
||||
emu->sw.f.F87_C3 = (ll&2)?1:0;
|
||||
emu->sw.f.F87_C0 = (ll&4)?1:0;
|
||||
} else {
|
||||
ll = (int64_t)(floor((ST0.d/ST1.d))/exp2(tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
}
|
||||
void arm_frndint(x86emu_t* emu)
|
||||
{
|
||||
@@ -104,21 +126,6 @@ void arm_fbstp(x86emu_t* emu, uint8_t* ed)
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).sref==ST(0).sq) {
|
||||
memcpy(ed, &STll(0).sq, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(uint64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t arm_fist64_0(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
@@ -156,13 +163,6 @@ int64_t arm_fist64_3(double d)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
@@ -179,13 +179,13 @@ void arm_ud(x86emu_t* emu)
|
||||
void arm_priv(x86emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
}
|
||||
|
||||
void arm_singlestep(x86emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGTRAP, (void*)R_EIP, 1);
|
||||
emit_signal(emu, SIGTRAP, (void*)R_EIP, 2);
|
||||
}
|
||||
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed)
|
||||
@@ -214,13 +214,179 @@ void arm_frstor(x86emu_t* emu, uint8_t* ed)
|
||||
|
||||
void arm_fprem1(x86emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int64_t tmp64s = lrint(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp64s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (tmp64s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp64s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
int e0, e1;
|
||||
int64_t ll;
|
||||
frexp(ST0.d, &e0);
|
||||
frexp(ST1.d, &e1);
|
||||
int32_t tmp32s = e0 - e1;
|
||||
if(tmp32s<64)
|
||||
{
|
||||
ll = (int64_t)round(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll&1)?1:0;
|
||||
emu->sw.f.F87_C3 = (ll&2)?1:0;
|
||||
emu->sw.f.F87_C0 = (ll&4)?1:0;
|
||||
} else {
|
||||
ll = (int64_t)(trunc((ST0.d/ST1.d))/exp2(tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void arm_aesimc(x86emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void arm_aesmc(x86emu_t* emu, int xmm)
|
||||
{
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
void arm_aesdlast(x86emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
const uint8_t invsubbytes[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
};
|
||||
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
|
||||
|
||||
}
|
||||
static const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
static const uint8_t subbytes[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
};
|
||||
void arm_aeselast(x86emu_t* emu, int xmm)
|
||||
{
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A F K P E J O D I N C H M B G L
|
||||
sse_regs_t eax1;
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
|
||||
//STATE ← SubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
|
||||
}
|
||||
void arm_aesd(x86emu_t* emu, int xmm)
|
||||
{
|
||||
arm_aesdlast(emu, xmm);
|
||||
arm_aesimc(emu, xmm);
|
||||
}
|
||||
void arm_aese(x86emu_t* emu, int xmm)
|
||||
{
|
||||
arm_aeselast(emu, xmm);
|
||||
arm_aesmc(emu, xmm);
|
||||
}
|
||||
void arm_aeskeygenassist(x86emu_t* emu, int gx, void* p, uint32_t u8)
|
||||
{
|
||||
sse_regs_t *EX = ((uintptr_t)p>8)?((sse_regs_t*)p):&emu->xmm[(uintptr_t)p];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
for (int i = 4; i < 8; ++i)
|
||||
GX->ub[i] = subbytes[EX->ub[i]];
|
||||
for (int i = 12; i < 16; ++i)
|
||||
GX->ub[i] = subbytes[EX->ub[i]];
|
||||
GX->ud[0] = GX->ud[1];
|
||||
uint8_t tmp8u = GX->ub[4];
|
||||
GX->ud[1] = GX->ud[1] >> 8;
|
||||
GX->ub[7] = tmp8u;
|
||||
GX->ud[1] ^= u8;
|
||||
GX->ud[2] = GX->ud[3];
|
||||
tmp8u = GX->ub[12];
|
||||
GX->ud[3] = GX->ud[3] >> 8;
|
||||
GX->ub[15] = tmp8u;
|
||||
GX->ud[3] ^= u8;
|
||||
}
|
||||
|
||||
void arm_pclmul(x86emu_t* emu, int gx, void* p, uint32_t u8)
|
||||
{
|
||||
int ex = (((uintptr_t)p)<8)?((uintptr_t)p):-1;
|
||||
sse_regs_t *EX = (ex==-1)?((sse_regs_t*)p):&emu->xmm[ex];
|
||||
sse_regs_t *GX = &emu->xmm[gx];
|
||||
int g = (u8&1)?1:0;
|
||||
int e = (u8&0b10000)?1:0;
|
||||
uint64_t result[2] = {0};
|
||||
uint64_t op2 = EX->q[e];
|
||||
for (int i=0; i<64; ++i)
|
||||
if(GX->q[g]&(1LL<<i)) {
|
||||
result[0] ^= (EX->q[e]<<i);
|
||||
if(i)
|
||||
result[1] ^= (EX->q[e]>>(64-i));
|
||||
|
||||
}
|
||||
GX->q[0] = result[0];
|
||||
GX->q[1] = result[1];
|
||||
}
|
||||
|
||||
void arm_clflush(x86emu_t* emu, void* p)
|
||||
@@ -309,13 +475,18 @@ void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
|
||||
dyn->n.neoncache[i+1].v = 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) {
|
||||
n->fpuused[i]=0;
|
||||
n->neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
}
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->n.fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i) {
|
||||
dyn->n.fpuused[i]=0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
fpu_reset_reg_neoncache(&dyn->n);
|
||||
}
|
||||
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
@@ -562,6 +733,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
// unswap
|
||||
int a = -1;
|
||||
int b = -1;
|
||||
// in neoncache
|
||||
for(int j=0; j<24 && ((a==-1) || (b==-1)); ++j)
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n == cache->combined1)
|
||||
@@ -578,7 +750,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->combined1 = cache->combined2 = 0;
|
||||
}
|
||||
if(cache->news) {
|
||||
// reove the newly created neoncache
|
||||
// remove the newly created neoncache
|
||||
for(int i=0; i<24; ++i)
|
||||
if(cache->news&(1<<i))
|
||||
cache->neoncache[i].v = 0;
|
||||
@@ -595,11 +767,23 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
}
|
||||
}
|
||||
cache->x87stack-=cache->stack_push;
|
||||
cache->tags>>=(cache->stack_push*2);
|
||||
cache->stack-=cache->stack_push;
|
||||
if(cache->pushed>=cache->stack_push)
|
||||
cache->pushed-=cache->stack_push;
|
||||
else
|
||||
cache->pushed = 0;
|
||||
cache->stack_push = 0;
|
||||
}
|
||||
cache->x87stack+=cache->stack_pop;
|
||||
cache->stack_next = cache->stack;
|
||||
if(cache->stack_pop) {
|
||||
if(cache->poped>=cache->stack_pop)
|
||||
cache->poped-=cache->stack_pop;
|
||||
else
|
||||
cache->poped = 0;
|
||||
cache->tags<<=(cache->stack_pop*2);
|
||||
}
|
||||
cache->stack_pop = 0;
|
||||
cache->barrier = 0;
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
@@ -714,6 +898,12 @@ uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
// return Ib on a mod/rm opcode without emiting anything
|
||||
uint8_t geted_ib(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
return F8;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
@@ -763,35 +953,27 @@ static int flagsCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
return 0;
|
||||
if(dyn->insts[ninst].f_exit.dfnone) // flags are fully known, nothing we can do more
|
||||
return 0;
|
||||
/* if((dyn->f.pending!=SF_SET)
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) {
|
||||
if(dyn->f.pending!=SF_PENDING) {*/
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
case SF_SET:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET && dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING
|
||||
&& dyn->insts[ninst].f_exit.pending!=SF_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
return 1;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
case SF_SET:
|
||||
if(dyn->insts[ninst].f_exit.pending!=SF_SET && dyn->insts[ninst].f_exit.pending!=SF_SET_PENDING)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending==SF_SET_PENDING)
|
||||
return 0;
|
||||
return 1;
|
||||
case SF_PENDING:
|
||||
if(dyn->insts[ninst].f_exit.pending==SF_PENDING || dyn->insts[ninst].f_exit.pending==SF_SET_PENDING)
|
||||
return 0;
|
||||
return (dyn->insts[jmp].f_entry.dfnone == dyn->insts[ninst].f_exit.dfnone)?0:1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int ret = 0;
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=1;
|
||||
@@ -852,3 +1034,56 @@ void print_opcode(dynarec_arm_t* dyn, int ninst, uint32_t opcode)
|
||||
{
|
||||
dynarec_log(LOG_NONE, "\t%08x\t%s\n", opcode, arm_print(opcode));
|
||||
}
|
||||
|
||||
static void x87_reset(neoncache_t* n)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
n->x87cache[i] = -1;
|
||||
n->x87stack = 0;
|
||||
n->stack = 0;
|
||||
n->stack_next = 0;
|
||||
n->stack_pop = 0;
|
||||
n->stack_push = 0;
|
||||
n->combined1 = n->combined2 = 0;
|
||||
n->swapped = 0;
|
||||
n->barrier = 0;
|
||||
n->pushed = 0;
|
||||
n->poped = 0;
|
||||
|
||||
for(int i=0; i<24; ++i)
|
||||
if(n->neoncache[i].t == NEON_CACHE_ST_F || n->neoncache[i].t == NEON_CACHE_ST_D)
|
||||
n->neoncache[i].v = 0;
|
||||
}
|
||||
static void mmx_reset(neoncache_t* n)
|
||||
{
|
||||
n->mmxcount = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
n->mmxcache[i] = -1;
|
||||
}
|
||||
static void sse_reset(neoncache_t* n)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
n->ssecache[i].v = -1;
|
||||
}
|
||||
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
x87_reset(&dyn->n);
|
||||
mmx_reset(&dyn->n);
|
||||
sse_reset(&dyn->n);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
void fpu_reset_ninst(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
x87_reset(&dyn->insts[ninst].n);
|
||||
mmx_reset(&dyn->insts[ninst].n);
|
||||
sse_reset(&dyn->insts[ninst].n);
|
||||
fpu_reset_reg_neoncache(&dyn->insts[ninst].n);
|
||||
}
|
||||
|
||||
int fpu_is_st_freed(dynarec_arm_t* dyn, int ninst, int st)
|
||||
{
|
||||
return (dyn->n.tags&(0b11<<(st*2)))?1:0;
|
||||
}
|
||||
@@ -16,13 +16,19 @@ void arm_fscale(x86emu_t* emu);
|
||||
void arm_fbld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fbst(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x86emu_t* emu);
|
||||
|
||||
void arm_aesd(x86emu_t* emu, int xmm);
|
||||
void arm_aese(x86emu_t* emu, int xmm);
|
||||
void arm_aesdlast(x86emu_t* emu, int xmm);
|
||||
void arm_aeselast(x86emu_t* emu, int xmm);
|
||||
void arm_aesimc(x86emu_t* emu, int xmm);
|
||||
void arm_aeskeygenassist(x86emu_t* emu, int gx, void* p, uint32_t u8);
|
||||
void arm_pclmul(x86emu_t* emu, int gx, void* p, uint32_t u8);
|
||||
|
||||
void arm_clflush(x86emu_t* emu, void* p);
|
||||
|
||||
int64_t arm_fist64_0(double d);
|
||||
@@ -83,6 +89,7 @@ int getNominalPred(dynarec_arm_t* dyn, int ninst);
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
uint8_t geted_ib(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
@@ -92,4 +99,10 @@ const char* getCacheName(int t, int n);
|
||||
void inst_name_pass3(dynarec_arm_t* dyn, int ninst, const char* name);
|
||||
void print_opcode(dynarec_arm_t* dyn, int ninst, uint32_t opcode);
|
||||
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
void fpu_reset_ninst(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// is st freed
|
||||
int fpu_is_st_freed(dynarec_arm_t* dyn, int ninst, int st);
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
+399
-206
@@ -40,6 +40,9 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if(hint>0 && hint<xEAX) scratch = hint;
|
||||
if(hint==xEIP) scratch = hint; // allow this one as a scratch and return register
|
||||
MAYUSE(scratch);
|
||||
|
||||
if(l==LOCK_LOCK) { /*SMDMB();*/DMB_ISH(); }
|
||||
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
@@ -285,47 +288,68 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Ret next\n");
|
||||
POP1(xEIP);
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
SMEND();
|
||||
BX(x3);
|
||||
MESSAGE(LOG_DUMP, "Ret next\n");
|
||||
POP1(xEIP);
|
||||
SMEND();
|
||||
if(box86_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
POP(xSP, (1<<x2)|(1<<x3));
|
||||
CMPS_REG_LSL_IMM5(x2, xEIP, 0); // is it the right address?
|
||||
BXcond(cEQ, x3);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
CMPS_IMM8(x3, 0); // that was already the top of the stack...
|
||||
LDR_IMM9_COND(cNE, xSP, xEmu, offsetof(x86emu_t, xSPSave)); // load pointer only if not already on top
|
||||
SUB_COND_IMM8(cEQ, xSP, xSP, 8); // unpop
|
||||
}
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
BX(x3);
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Retn epilog\n");
|
||||
POP1(xEIP);
|
||||
if(n>0xff) {
|
||||
MOVW(x1, n);
|
||||
ADD_REG_LSL_IMM5(xESP, xESP, x1, 0);
|
||||
} else {
|
||||
ADD_IMM8(xESP, xESP, n);
|
||||
}
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
SMEND();
|
||||
BX(x3);
|
||||
MESSAGE(LOG_DUMP, "Retn epilog\n");
|
||||
POP1(xEIP);
|
||||
if(n>0xff) {
|
||||
MOVW(x1, n);
|
||||
ADD_REG_LSL_IMM5(xESP, xESP, x1, 0);
|
||||
} else {
|
||||
ADD_IMM8(xESP, xESP, n);
|
||||
}
|
||||
SMEND();
|
||||
if(box86_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
POP(xSP, (1<<x2)|(1<<x3));
|
||||
CMPS_REG_LSL_IMM5(x2, xEIP, 0); // is it the right address?
|
||||
BXcond(cEQ, x3);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
CMPS_IMM8(x3, 0); // that was already the top of the stack...
|
||||
LDR_IMM9_COND(cNE, xSP, xEmu, offsetof(x86emu_t, xSPSave));
|
||||
SUB_COND_IMM8(cEQ, xSP, xSP, 8); // unpop
|
||||
}
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
#ifdef HAVE_TRACE
|
||||
MOV_REG(x2, 15); // move current PC to x2, for tracing
|
||||
#endif
|
||||
BX(x3);
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "IRet epilog\n");
|
||||
SET_DFNONE(x1);
|
||||
// POP IP
|
||||
POP1(xEIP);
|
||||
// POP CS
|
||||
@@ -372,7 +396,6 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t
|
||||
if(saveflags) {
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
SET_NODF();
|
||||
}
|
||||
|
||||
#if defined(__ARM_PCS) && !defined(__ARM_PCS_VFP)
|
||||
@@ -424,7 +447,6 @@ void call_dr(dynarec_arm_t* dyn, int ninst, int reg, int n, int s1, int ret, int
|
||||
if(saveflags) {
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
SET_NODF();
|
||||
}
|
||||
// call a function with n double args (taking care of the SOFTFP / HARD call) that return a double too
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg, int ret, uint32_t mask, int saveflags)
|
||||
@@ -473,8 +495,53 @@ void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg
|
||||
if(saveflags) {
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
SET_NODF();
|
||||
}
|
||||
// call a function with 1 double arg (taking care of the SOFTFP / HARD call) and 1 non-float arg that return a double
|
||||
void call_ddr(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int arg, int reg, int ret, uint32_t mask, int saveflags)
|
||||
{
|
||||
if(ret!=-2 && !mask) {
|
||||
// ARM ABI require the stack to be 8-bytes aligned!
|
||||
// so, if no mask asked, add one to stay 8-bytes aligned
|
||||
if(ret!=xFlags) mask=1<<xFlags; else mask=1<<x3;
|
||||
}
|
||||
if(ret!=-2) {
|
||||
PUSH(xSP, (1<<xEmu) | mask);
|
||||
}
|
||||
fpu_pushcache(dyn, ninst, reg);
|
||||
if(saveflags) {
|
||||
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
#ifdef ARM_SOFTFP
|
||||
VMOVfrV_64(0, 1, 0);// D0 -> r0:r1
|
||||
MOV_REG(2, arg);
|
||||
#else
|
||||
MOV_REG(0, arg);
|
||||
#endif
|
||||
MOV32(reg, (uintptr_t)fnc);
|
||||
BLX(reg);
|
||||
if(fnc2) {
|
||||
#ifdef ARM_SOFTFP
|
||||
// result are already in r0:r1 for next call
|
||||
#endif
|
||||
MOV32(reg, (uintptr_t)fnc2);
|
||||
BLX(reg);
|
||||
}
|
||||
#ifdef ARM_SOFTFP
|
||||
POP(xSP, (1<<2) | (1<<3));
|
||||
VMOVtoV_64(0, 0, 1); // load r0:r1 to D0 to simulate hardfo
|
||||
#endif
|
||||
fpu_popcache(dyn, ninst, reg);
|
||||
if(ret>=0) {
|
||||
MOV_REG(ret, 0);
|
||||
}
|
||||
if(ret!=-2) {
|
||||
POP(xSP, (1<<xEmu) | mask);
|
||||
}
|
||||
if(saveflags) {
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
}
|
||||
|
||||
// call a function with 1 arg, (taking care of the SOFTFP / HARD call) that return a double, using s1 as scratch
|
||||
void call_rd(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int s1, uint32_t mask, int saveflags)
|
||||
{
|
||||
@@ -536,27 +603,10 @@ void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
|
||||
}
|
||||
|
||||
// x87 stuffs
|
||||
static void x87_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->n.x87cache[i] = -1;
|
||||
dyn->n.x87stack = 0;
|
||||
dyn->n.stack = 0;
|
||||
dyn->n.stack_next = 0;
|
||||
dyn->n.stack_pop = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;
|
||||
dyn->n.swapped = 0;
|
||||
dyn->n.barrier = 0;
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].t == NEON_CACHE_ST_F || dyn->n.neoncache[i].t == NEON_CACHE_ST_D)
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
int x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
{
|
||||
if(!dyn->n.x87stack)
|
||||
return;
|
||||
return 0;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, scratch);
|
||||
MESSAGE(LOG_DUMP, "\tSynch x87 Stackcount (%d)\n", dyn->n.x87stack);
|
||||
@@ -583,6 +633,39 @@ void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
dyn->n.stack_next -= dyn->n.stack;
|
||||
dyn->n.stack = 0;
|
||||
MESSAGE(LOG_DUMP, "\t------x87 Stackcount\n");
|
||||
return a;
|
||||
}
|
||||
|
||||
void x87_unstackcount(dynarec_arm_t* dyn, int ninst, int scratch, int count)
|
||||
{
|
||||
if(!count)
|
||||
return;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, scratch);
|
||||
MESSAGE(LOG_DUMP, "\tSynch x87 Unstackcount (%d)\n", dyn->n.x87stack);
|
||||
int a = -count;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDR_IMM9(scratch, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADD_IMM8(scratch, scratch, a);
|
||||
} else {
|
||||
SUB_IMM8(scratch, scratch, -a);
|
||||
}
|
||||
STR_IMM9(scratch, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(scratch, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
SUB_IMM8(scratch, scratch, a);
|
||||
} else {
|
||||
ADD_IMM8(scratch, scratch, -a);
|
||||
}
|
||||
AND_IMM8(scratch, scratch, 7);
|
||||
STR_IMM9(scratch, xEmu, offsetof(x86emu_t, top));
|
||||
// reset x87stack, but not the stack count of neoncache
|
||||
dyn->n.x87stack = count;
|
||||
dyn->n.stack = count;
|
||||
dyn->n.stack_next += dyn->n.stack;
|
||||
MESSAGE(LOG_DUMP, "\t------x87 Unstackcount\n");
|
||||
}
|
||||
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
@@ -607,11 +690,15 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
dyn->n.stack+=1;
|
||||
dyn->n.stack_next+=1;
|
||||
dyn->n.stack_push+=1;
|
||||
++dyn->n.pushed;
|
||||
if(dyn->n.poped)
|
||||
--dyn->n.poped;
|
||||
// move all regs in cache, and find a free one
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D) || (dyn->n.neoncache[j].t == NEON_CACHE_ST_F))
|
||||
++dyn->n.neoncache[j].n;
|
||||
int ret = -1;
|
||||
dyn->n.tags<<=2;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1)
|
||||
++dyn->n.x87cache[i];
|
||||
@@ -636,6 +723,9 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
dyn->n.stack+=1;
|
||||
dyn->n.stack_next+=1;
|
||||
dyn->n.stack_push+=1;
|
||||
++dyn->n.pushed;
|
||||
if(dyn->n.poped)
|
||||
--dyn->n.poped;
|
||||
// move all regs in cache
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D) || (dyn->n.neoncache[j].t == NEON_CACHE_ST_F))
|
||||
@@ -643,17 +733,12 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1)
|
||||
++dyn->n.x87cache[i];
|
||||
dyn->n.tags<<=2;
|
||||
if(s1)
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
void static internal_x87_dopop(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
dyn->n.x87stack-=1;
|
||||
dyn->n.stack_next-=1;
|
||||
dyn->n.stack_pop+=1;
|
||||
// move all regs in cache, poping ST0
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
--dyn->n.x87cache[i];
|
||||
@@ -663,6 +748,30 @@ void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
}
|
||||
}
|
||||
}
|
||||
int static internal_x87_dofree(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->n.tags&0b11) {
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 FREED ST0, poping 1 more\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
do {
|
||||
dyn->n.x87stack-=1;
|
||||
dyn->n.stack_next-=1;
|
||||
dyn->n.stack_pop+=1;
|
||||
dyn->n.tags>>=2;
|
||||
++dyn->n.poped;
|
||||
if(dyn->n.pushed)
|
||||
--dyn->n.pushed;
|
||||
// move all regs in cache, poping ST0
|
||||
internal_x87_dopop(dyn);
|
||||
} while(internal_x87_dofree(dyn));
|
||||
}
|
||||
|
||||
static void x87_purgecache_full(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3)
|
||||
{
|
||||
@@ -682,20 +791,11 @@ static void x87_purgecache_full(dynarec_arm_t* dyn, int ninst, int next, int s1,
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
}
|
||||
// Setting all 8 xp_regs to "FULL"
|
||||
int offs = offsetof(x86emu_t, p_regs);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOVW(s1, offs);
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
MOVW(s3, 0);
|
||||
for (int i=0; i<8; ++i) {
|
||||
STRAI_IMM9_W(s3, s1, sizeof(fpu_p_reg_t));
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
// setup TOP => full stack so = 0
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, top));
|
||||
offs = offsetof(x86emu_t, x87);
|
||||
uintptr_t offs = offsetof(x86emu_t, x87);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
@@ -706,28 +806,28 @@ static void x87_purgecache_full(dynarec_arm_t* dyn, int ninst, int next, int s1,
|
||||
//Stack is full, so STi is just x87reg[i]
|
||||
int j=0;
|
||||
while(dyn->n.x87cache[j]!=i) ++j; // look for STi
|
||||
int st = dyn->n.x87cache[j]+dyn->n.stack_pop;
|
||||
#if STEP == 1
|
||||
if(!next) { // don't force promotion here
|
||||
// pre-apply pop, because purge happens in-between
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.x87cache[j]+dyn->n.stack_pop);
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
}
|
||||
#endif
|
||||
if(next) {
|
||||
// need to check if a ST_F need local promotion
|
||||
if(neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[j])>=0) {
|
||||
#if STEP == 3
|
||||
if(!next && neoncache_get_current_st(dyn, ninst, st)!=NEON_CACHE_ST_D) {
|
||||
MESSAGE(LOG_DUMP, "Warning, incoherency with purged ST%d cache\n", st);
|
||||
}
|
||||
#endif
|
||||
switch(neoncache_get_current_st(dyn, ninst, st)) {
|
||||
case NEON_CACHE_ST_D:
|
||||
VSTM_64_W(dyn->n.x87reg[j], s1); // save the value
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
VCVT_F64_F32(0, dyn->n.x87reg[j]*2);
|
||||
VSTM_64_W(0, s1); // save the value
|
||||
} else {
|
||||
VSTM_64_W(dyn->n.x87reg[j], s1); // save the value
|
||||
}
|
||||
} else {
|
||||
// need to check if a ST_F need local promotion
|
||||
if(neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[j])>=0) {
|
||||
VCVT_F64_F32(0, dyn->n.x87reg[j]*2);
|
||||
VSTM_64_W(0, s1); // save the value
|
||||
} else {
|
||||
VSTM_64_W(dyn->n.x87reg[j], s1); // save the value
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!next) {
|
||||
fpu_free_reg_double(dyn, dyn->n.x87reg[j]);
|
||||
dyn->n.x87reg[j] = -1;
|
||||
dyn->n.x87cache[j] = -1;
|
||||
@@ -736,9 +836,13 @@ static void x87_purgecache_full(dynarec_arm_t* dyn, int ninst, int next, int s1,
|
||||
}
|
||||
if(!next) {
|
||||
dyn->n.stack_next = 0;
|
||||
dyn->n.tags = 0;
|
||||
#if STEP < 2
|
||||
// refresh the cached valued, in case it's a purge outside a instruction
|
||||
dyn->insts[ninst].n.barrier = 1;
|
||||
dyn->n.pushed = 0;
|
||||
dyn->n.poped = 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---Purge Full x87 Cache and Synch Stackcount\n");
|
||||
@@ -773,44 +877,37 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
SUB_IMM8(s2, s2, -a);
|
||||
}
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
// update tags (and top at the same time)
|
||||
// update tags
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
// new tag to fulls
|
||||
MOVW(s3, 0);
|
||||
int offs = offsetof(x86emu_t, p_regs);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOVW(s1, offs);
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
for (int i=0; i<a; ++i) {
|
||||
SUB_IMM8(s2, s2, 1);
|
||||
AND_IMM8(s2, s2, 7); // (emu->top + st)&7
|
||||
STR_REG_LSL_IMM5(s3, s1, s2, 2); // that slot is full
|
||||
}
|
||||
MOV_REG_LSL_IMM5(s1, s1, a*2);
|
||||
} else {
|
||||
// empty tags
|
||||
MOVW(s3, 0b11);
|
||||
int offs = offsetof(x86emu_t, p_regs);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, p_regs));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
for (int i=0; i<-a; ++i) {
|
||||
STR_REG_LSL_IMM5(s3, s1, s2, 2); // empty slot before leaving it
|
||||
ADD_IMM8(s2, s2, 1);
|
||||
AND_IMM8(s2, s2, 7); // (emu->top + st)&7
|
||||
}
|
||||
MOV32(s2, 0xffff);
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 16);
|
||||
MOV_REG_LSR_IMM5(s1, s1, -a*2);
|
||||
}
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
SUB_IMM8(s2, s2, a);
|
||||
} else {
|
||||
ADD_IMM8(s2, s2, -a);
|
||||
}
|
||||
AND_IMM8(s2, s2, 7);
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
} else {
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
}
|
||||
// check if free is used
|
||||
if(dyn->n.tags) {
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
MOV32(s3, dyn->n.tags);
|
||||
ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
}
|
||||
|
||||
if(ret!=0) {
|
||||
// --- set values
|
||||
// Get top
|
||||
@@ -854,9 +951,13 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
}
|
||||
if(!next) {
|
||||
dyn->n.stack_next = 0;
|
||||
dyn->n.tags = 0;
|
||||
#if STEP < 2
|
||||
// refresh the cached valued, in case it's a purge outside a instruction
|
||||
dyn->insts[ninst].n.barrier = 1;
|
||||
dyn->n.pushed = 0;
|
||||
dyn->n.poped = 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---Purge x87 Cache and Synch Stackcount\n");
|
||||
@@ -875,6 +976,16 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
SUB_IMM8(s2, s2, -a);
|
||||
}
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// update tags
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
MOV_REG_LSL_IMM5(s1, s1, a*2);
|
||||
} else {
|
||||
MOV32(s2, 0xffff);
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 16);
|
||||
MOV_REG_LSR_IMM5(s1, s1, -a*2);
|
||||
}
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
@@ -928,6 +1039,16 @@ static void x87_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, in
|
||||
ADD_IMM8(s1, s1, -a);
|
||||
}
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// update tags
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
MOV32(s2, 0xffff);
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 16);
|
||||
MOV_REG_LSR_IMM5(s1, s1, a*2);
|
||||
} else {
|
||||
MOV_REG_LSL_IMM5(s1, s1, -a*2);
|
||||
}
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
@@ -1049,8 +1170,10 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
if(ret==-1) // nothing to do
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tForget x87 Cache for ST%d\n", st);
|
||||
int reg = dyn->n.x87reg[ret];
|
||||
#if STEP == 1
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
// prepare offset to fpu => s1
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, x87));
|
||||
@@ -1062,11 +1185,17 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
AND_IMM8(s2, s2, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(s2, s1, s2, 3); // fpu[(emu->top+i)&7] lsl 3 because fpu are double, so 8 bytes
|
||||
VSTR_64(dyn->n.x87reg[ret], s2, 0); // save the value
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F) {
|
||||
// this should not happens
|
||||
VCVT_F64_F32(0, reg*2); // use D0 as scratch...
|
||||
VSTR_64(0, s2, 0);
|
||||
} else {
|
||||
VSTR_64(reg, s2, 0); // save the value
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t--------Forget x87 Cache for ST%d\n", st);
|
||||
// and forget that cache
|
||||
fpu_free_reg_double(dyn, dyn->n.x87reg[ret]);
|
||||
dyn->n.neoncache[dyn->n.x87reg[ret]].v = 0;
|
||||
fpu_free_reg_double(dyn, reg);
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
dyn->n.x87cache[ret] = -1;
|
||||
dyn->n.x87reg[ret] = -1;
|
||||
}
|
||||
@@ -1122,6 +1251,65 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
MESSAGE(LOG_DUMP, "\t-------x87 Cache for ST%d\n", st);
|
||||
}
|
||||
|
||||
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st)
|
||||
{
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i] == st)
|
||||
ret = i;
|
||||
MESSAGE(LOG_DUMP, "\tFFREE%s x87 Cache for ST%d\n", (ret!=-1)?" (and Forget)":"", st);
|
||||
if(ret!=-1) {
|
||||
const int reg = dyn->n.x87reg[ret];
|
||||
#if STEP == 1
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F)
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
#endif
|
||||
// prepare offset to fpu => s1
|
||||
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, x87));
|
||||
// Get top
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
// Update
|
||||
int ast = st - dyn->n.x87stack;
|
||||
if(ast) {
|
||||
if(ast>0) {
|
||||
ADD_IMM8(s2, s2, ast);
|
||||
} else {
|
||||
SUB_IMM8(s2, s2, -ast);
|
||||
}
|
||||
AND_IMM8(s2, s2, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(s2, s1, s2, 3); // fpu[(emu->top+i)&7] lsl 3 because fpu are double, so 8 bytes
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_ST_F) {
|
||||
// this should not happens
|
||||
VCVT_F64_F32(0, reg*2); // use D0 as scratch...
|
||||
VSTR_64(0, s2, 0);
|
||||
} else {
|
||||
VSTR_64(reg, s2, 0); // save the value
|
||||
}
|
||||
// and forget that cache
|
||||
fpu_free_reg_double(dyn, reg);
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
dyn->n.x87cache[ret] = -1;
|
||||
dyn->n.x87reg[ret] = -1;
|
||||
} else {
|
||||
// Get top
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
// Update
|
||||
int ast = st - dyn->n.x87stack;
|
||||
if(ast) {
|
||||
if(ast>0) {
|
||||
ADD_IMM8(s2, s2, ast);
|
||||
} else {
|
||||
SUB_IMM8(s2, s2, -ast);
|
||||
}
|
||||
AND_IMM8(s2, s2, 7); // (emu->top + i)&7
|
||||
}
|
||||
}
|
||||
// add mark in the freed array
|
||||
dyn->n.tags |= 0b11<<(st*2);
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 FFREE for ST%d\n", st);
|
||||
}
|
||||
|
||||
// Set rounding according to cw flags, return reg to restore flags
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
@@ -1130,7 +1318,8 @@ int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
UBFX(s2, s1, 1, 1); // swap bits 0 and 1
|
||||
BFI(s2, s1, 1, 1);
|
||||
VMRS(s1); // get fpscr
|
||||
MOV_REG(s3, s1);
|
||||
if (s3 >= 0)
|
||||
MOV_REG(s3, s1);
|
||||
BFI(s1, s2, 22, 2); // inject new round
|
||||
VMSR(s1); // put new fpscr
|
||||
return s3;
|
||||
@@ -1207,12 +1396,6 @@ void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
}
|
||||
|
||||
// MMX helpers
|
||||
static void mmx_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->n.mmxcount = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->n.mmxcache[i] = -1;
|
||||
}
|
||||
static int isx87Empty(dynarec_arm_t* dyn)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
@@ -1294,11 +1477,6 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
|
||||
|
||||
// SSE / SSE2 helpers
|
||||
static void sse_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->n.ssecache[i].v = -1;
|
||||
}
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite)
|
||||
{
|
||||
@@ -1336,6 +1514,26 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
dyn->n.ssecache[a].write = 1; // it will be write...
|
||||
return dyn->n.ssecache[a].reg;
|
||||
}
|
||||
// forget neon register for a SSE reg
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a, int s1)
|
||||
{
|
||||
if(dyn->n.ssecache[a].v==-1)
|
||||
return;
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg+0-FPUFIRST].t == NEON_CACHE_XMMW) {
|
||||
int offs = offsetof(x86emu_t, xmm[a]);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOV32(s1, offs);
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
VST1Q_64(dyn->n.ssecache[a].reg, s1);
|
||||
}
|
||||
fpu_free_reg_quad(dyn, dyn->n.ssecache[a].reg);
|
||||
dyn->n.ssecache[a].v = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// purge the SSE cache only(needs 1 scratch registers)
|
||||
static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
{
|
||||
@@ -1394,6 +1592,24 @@ static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
}
|
||||
}
|
||||
|
||||
int sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a, int s1)
|
||||
{
|
||||
if(dyn->n.ssecache[a].v==-1)
|
||||
return 0;
|
||||
if(dyn->n.ssecache[a].write) {
|
||||
int offs = offsetof(x86emu_t, xmm[a]);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOV32(s1, offs);
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
VST1Q_32(dyn->n.ssecache[a].reg, s1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
// only need to push 16-31...
|
||||
@@ -1716,55 +1932,6 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
int stack_cnt = dyn->n.stack_next;
|
||||
int s3_top = 0xffff;
|
||||
if(stack_cnt != cache_i2.stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d -\n", stack_cnt, cache_i2.stack);
|
||||
int a = stack_cnt - cache_i2.stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDR_IMM9(s3, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADD_IMM8(s3, s3, a);
|
||||
} else {
|
||||
SUB_IMM8(s3, s3, -a);
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s3, xEmu, offsetof(x86emu_t, top));
|
||||
// update tags (and top at the same time)
|
||||
if(a>0) {
|
||||
// new tag to fulls
|
||||
MOVW(s2, 0);
|
||||
int offs = offsetof(x86emu_t, p_regs);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOVW(s1, offs);
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
for (int i=0; i<a; ++i) {
|
||||
SUB_IMM8(s3, s3, 1);
|
||||
AND_IMM8(s3, s3, 7); // (emu->top + st)&7
|
||||
STR_REG_LSL_IMM5(s2, s1, s3, 2); // that slot is full
|
||||
}
|
||||
} else {
|
||||
// empty tags
|
||||
MOVW(s2, 0b11);
|
||||
int offs = offsetof(x86emu_t, p_regs);
|
||||
if(!(offs&3) && (offs>>2)<256) {
|
||||
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
|
||||
} else {
|
||||
MOVW(s1, offsetof(x86emu_t, p_regs));
|
||||
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
|
||||
}
|
||||
for (int i=0; i<-a; ++i) {
|
||||
STR_REG_LSL_IMM5(s2, s1, s3, 2); // empty slot before leaving it
|
||||
ADD_IMM8(s3, s3, 1);
|
||||
AND_IMM8(s3, s3, 7); // (emu->top + st)&7
|
||||
}
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, top));
|
||||
s3_top = 0;
|
||||
stack_cnt = cache_i2.stack;
|
||||
}
|
||||
neoncache_t cache = dyn->n;
|
||||
// sanitize XMM regs alocation, cache_i2 has been sanitized in neoncacheUnwind already
|
||||
for(int i=0; i<24; i+=2) {
|
||||
@@ -1833,6 +2000,40 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
}
|
||||
if(stack_cnt != cache_i2.stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d -\n", stack_cnt, cache_i2.stack);
|
||||
int a = stack_cnt - cache_i2.stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDR_IMM9(s3, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADD_IMM8(s3, s3, a);
|
||||
} else {
|
||||
SUB_IMM8(s3, s3, -a);
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// update tags
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
MOV_REG_LSL_IMM5(s1, s1, a*2);
|
||||
} else {
|
||||
// empty tags
|
||||
MOV32(s3, 0xffff);
|
||||
ORR_REG_LSL_IMM5(s1, s1, s3, 16);
|
||||
MOV_REG_LSR_IMM5(s1, s1, -a*2);
|
||||
}
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s3, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
SUB_IMM8(s3, s3, a);
|
||||
} else {
|
||||
ADD_IMM8(s3, s3, -a);
|
||||
}
|
||||
AND_IMM8(s3, s3, 7);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, top));
|
||||
s3_top = 0;
|
||||
stack_cnt = cache_i2.stack;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
#endif
|
||||
}
|
||||
@@ -1846,7 +2047,7 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
if(dyn->f.dfnone) // flags are fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go = 0;
|
||||
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone)?1:0;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: break;
|
||||
case SF_SET:
|
||||
@@ -1864,12 +2065,10 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
else
|
||||
go = (dyn->insts[jmp].f_entry.dfnone == dyn->f.dfnone)?0:1;
|
||||
else if(dyn->insts[jmp].f_entry.dfnone!=dyn->f.dfnone)
|
||||
go = 1;
|
||||
break;
|
||||
}
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone)
|
||||
go = 1;
|
||||
if(go) {
|
||||
if(dyn->f.pending!=SF_PENDING) {
|
||||
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, df));
|
||||
@@ -1902,14 +2101,6 @@ void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
x87_unreflectcache(dyn, ninst, s1, s2, s3);
|
||||
}
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
x87_reset(dyn);
|
||||
mmx_reset(dyn);
|
||||
sse_reset(dyn);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
// get the single reg that from the double "reg" (so Dx[idx])
|
||||
int fpu_get_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx)
|
||||
{
|
||||
@@ -1927,14 +2118,13 @@ void fpu_putback_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx, int
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
// 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
|
||||
XOR_REG_LSR_IMM8(s4, s1, s1, 4);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 2);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
MVN_REG_LSL_IMM5(s4, s4, 0);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
|
||||
@@ -1944,8 +2134,14 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
#if STEP == 0
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "New x87stack=%d\n", dyn->n.x87stack);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
if(box86_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
@@ -1975,9 +2171,6 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
}
|
||||
|
||||
// propagate ST stack state, especial stack pop that are deferred
|
||||
|
||||
@@ -27,29 +27,34 @@
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
#define PKa(a) *(uint8_t*)(a)
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
// Strong mem emulation helpers
|
||||
// Sequence of Read will trigger a DMB on "first" read if strongmem is 2
|
||||
// Squence of Write will trigger a DMB on "last" write if strongmem is 1
|
||||
#define SMREAD_MIN 2
|
||||
#define SMWRITE_MIN 1
|
||||
// Sequence of Read will trigger a DMB on "first" read if strongmem is >= SMREAD_MIN
|
||||
// Sequence of Write will trigger a DMB on "last" write if strongmem is >= 1
|
||||
// All Write operation that might use a lock all have a memory barrier if strongmem is >= SMWRITE_MIN
|
||||
// Opcode will read
|
||||
#define SMREAD() if(!dyn->smread && box86_dynarec_strongmem>1) {SMDMB();}
|
||||
#define SMREAD() if((dyn->smread==0) && (box86_dynarec_strongmem>SMREAD_MIN)) {SMDMB();} else dyn->smread=1
|
||||
// Opcode will read with option forced lock
|
||||
#define SMREADLOCK(lock) if(lock || (!dyn->smread && box86_dynarec_strongmem>1)) {SMDMB();}
|
||||
// Opcode migh read (depend on nextop)
|
||||
#define SMREADLOCK(lock) if((lock) || ((dyn->smread==0) && (box86_dynarec_strongmem>SMREAD_MIN))) {SMDMB();}
|
||||
// Opcode might read (depend on nextop)
|
||||
#define SMMIGHTREAD() if(!MODREG) {SMREAD();}
|
||||
// Opcode has wrote
|
||||
#define SMWRITE() dyn->smwrite=1
|
||||
// Opcode has wrote (strongmem>1 only)
|
||||
#define SMWRITE2() if(box86_dynarec_strongmem>1) dyn->smwrite=1
|
||||
#define SMWRITE2() if(box86_dynarec_strongmem>SMREAD_MIN) dyn->smwrite=1
|
||||
// Opcode has wrote with option forced lock
|
||||
#define SMWRITELOCK(lock) if(lock) {SMDMB();} else dyn->smwrite=1
|
||||
// Opcode migh have wrote (depend on nextop)
|
||||
#define SMWRITELOCK(lock) if(lock || (box86_dynarec_strongmem>SMWRITE_MIN)) {SMDMB();} else dyn->smwrite=1
|
||||
// Opcode might have wrote (depend on nextop)
|
||||
#define SMMIGHTWRITE() if(!MODREG) {SMWRITE();}
|
||||
// Start of sequence
|
||||
#define SMSTART() SMEND()
|
||||
// End of sequence
|
||||
#define SMEND() if(dyn->smwrite && box86_dynarec_strongmem) {DMB_ISH();} dyn->smwrite=0; dyn->smread=0;
|
||||
#define SMEND() if(dyn->smwrite && box86_dynarec_strongmem) {if(box86_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();}} dyn->smwrite=0; dyn->smread=0;
|
||||
// Force a Data memory barrier (for LOCK: prefix)
|
||||
#define SMDMB() DMB_ISH(); dyn->smwrite=0; dyn->smread=1
|
||||
#define SMDMB() if(box86_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();} dyn->smwrite=0; dyn->smread=1
|
||||
|
||||
//LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
@@ -120,6 +125,8 @@
|
||||
}
|
||||
// GETGW extract x86 register in gd, that is i
|
||||
#define GETGW(i) gd = xEAX+((nextop&0x38)>>3); UXTH(i, gd, 0); gd = i;
|
||||
// GETSGW extract x86 signed register in gd, that is i
|
||||
#define GETSGW(i) gd = xEAX+((nextop&0x38)>>3); SXTH(i, gd, 0); gd = i;
|
||||
//GETEWW will use i for ed, and can use w for wback.
|
||||
#define GETEWW(w, i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = xEAX+(nextop&7);\
|
||||
@@ -255,8 +262,10 @@
|
||||
#define CALL_1DD(F, F2, M) call_d(dyn, ninst, F, F2, 1, x3, -1, M, 0)
|
||||
// CALL_1D_U64 will use S as scratch. Return value in ret/ret2, 1 ARG in D0
|
||||
#define CALL_1DR_U64(R, ret, ret2, S, M) call_dr(dyn, ninst, R, 1, S, ret, ret2, M, 1)
|
||||
// CALL_1D will use S as scratch. Return value in D0, 1 ARG in D0
|
||||
// CALL_1DR will use S as scratch. Return value in D0, 1 ARG in D0
|
||||
#define CALL_1DR(R, S, M) call_dr(dyn, ninst, R, 1, S, -1, -1, M, 0)
|
||||
// CALL_1DI will use S as scratch. Return value in D0, 1 ARG in D0, 1 ARG in R0
|
||||
#define CALL_1DDR(F, R, S, M) call_ddr(dyn, ninst, F, NULL, R, S, -1, M, 0)
|
||||
// CALL_1RD will use S as scratch. Return value in D0, 1 ARG in R
|
||||
#define CALL_1RD(F, R, S, M) call_rd(dyn, ninst, F, R, S, M, 0);
|
||||
|
||||
@@ -307,7 +316,7 @@
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x86.gen_flags&(A) && !(dyn->insts[ninst].x86.gen_flags&(B))))
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2) \
|
||||
#define FCOM(s1, s2) \
|
||||
VMRS_APSR(); /* 0b0100011100000000 */ \
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
|
||||
BIC_IMM8(s1, s1, 0b01000111, 12); \
|
||||
@@ -318,7 +327,7 @@
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
#define FCOMI(s1, s2) \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
|
||||
@@ -326,16 +335,55 @@
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 0b01000000, 0); /* zero */ \
|
||||
ORR_IMM8_COND(cMI, xFlags, xFlags, 0b00000001, 0); /* less than */ \
|
||||
/* greater than leave 0 */ \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
IFX(X_OF|X_AF|X_SF|X_PEND) { \
|
||||
/* clear 0b100010010000 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b10001001, 14); \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
|
||||
|
||||
#if STEP == 0
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) var = x87_do_push(dyn, ninst, scratch, t)
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) x87_do_push_empty(dyn, ninst, scratch)
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) x87_do_pop(dyn, ninst, scratch)
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
var = x87_do_push(dyn, ninst, scratch, t)
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_push_empty(dyn, ninst, scratch)
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_pop(dyn, ninst, scratch)
|
||||
#endif
|
||||
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->f.dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->f.dfnone=1;}
|
||||
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->f.dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_DF(S, N) \
|
||||
if(N) { \
|
||||
MOVW(S, N);\
|
||||
STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); \
|
||||
if(dyn->f.pending==SF_PENDING && dyn->insts[ninst].x86.need_after && !(dyn->insts[ninst].x86.need_after&X_PEND)) { \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_NODF(); \
|
||||
} \
|
||||
dyn->f.dfnone=0;\
|
||||
} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
|
||||
@@ -369,6 +417,8 @@
|
||||
if(dyn->insts[ninst].x86.gen_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_SET_DF: dyn->f.pending = SF_SET; dyn->f.dfnone = 1; break; \
|
||||
case SF_SET_NODF: dyn->f.pending = SF_SET; dyn->f.dfnone = 0; break; \
|
||||
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
|
||||
case SF_SUBSET_PENDING: \
|
||||
case SF_SET_PENDING: \
|
||||
@@ -377,7 +427,7 @@
|
||||
} else dyn->f.pending = SF_SET
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A, C)
|
||||
#define JUMP(A, C) SMEND()
|
||||
#endif
|
||||
#ifndef BARRIER
|
||||
#define BARRIER(A)
|
||||
@@ -385,6 +435,9 @@
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#ifndef SET_HASCALLRET
|
||||
#define SET_HASCALLRET()
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
@@ -443,6 +496,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog_)
|
||||
#define call_c STEPNAME(call_c_)
|
||||
#define call_d STEPNAME(call_d_)
|
||||
#define call_ddr STEPNAME(call_ddr_)
|
||||
#define call_dr STEPNAME(call_dr_)
|
||||
#define call_rd STEPNAME(call_rd_)
|
||||
#define grab_fsdata STEPNAME(grab_fsdata_)
|
||||
@@ -512,10 +566,24 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define emit_shr32 STEPNAME(emit_shr32)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_shl8 STEPNAME(emit_shl8)
|
||||
#define emit_shl8c STEPNAME(emit_shl8c)
|
||||
#define emit_shr8 STEPNAME(emit_shr8)
|
||||
#define emit_shr8c STEPNAME(emit_shr8c)
|
||||
#define emit_sar8 STEPNAME(emit_sar8)
|
||||
#define emit_sar8c STEPNAME(emit_sar8c)
|
||||
#define emit_shl16 STEPNAME(emit_shl16)
|
||||
#define emit_shl16c STEPNAME(emit_shl16c)
|
||||
#define emit_shr16 STEPNAME(emit_shr16)
|
||||
#define emit_shr16c STEPNAME(emit_shr16c)
|
||||
#define emit_sar16 STEPNAME(emit_sar16)
|
||||
#define emit_sar16c STEPNAME(emit_sar16c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_rol8c STEPNAME(emit_rol8c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_ror8c STEPNAME(emit_ror8c)
|
||||
#define emit_rol16c STEPNAME(emit_rol16c)
|
||||
#define emit_ror16c STEPNAME(emit_ror16c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
#define emit_shrd32 STEPNAME(emit_shrd32)
|
||||
@@ -531,10 +599,12 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st)
|
||||
#define x87_free STEPNAME(x87_free)
|
||||
#define x87_refresh STEPNAME(x87_refresh)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_unstackcount STEPNAME(x87_unstackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_setround_reset STEPNAME(x87_setround_reset)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
@@ -545,10 +615,11 @@ void* arm_next(x86emu_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_reflect_reg STEPNAME(sse_reflect_reg)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_reset_cache STEPNAME(fpu_reset_cache)
|
||||
#define fpu_propagate_stack STEPNAME(fpu_propagate_stack)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
@@ -580,6 +651,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_dr(dynarec_arm_t* dyn, int ninst, int reg, int n, int s1, int ret, int ret2, uint32_t mask, int saveflags);
|
||||
void call_ddr(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int arg, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_rd(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int s1, uint32_t mask, int saveflags);
|
||||
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
@@ -648,20 +720,36 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, 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 upadte at every call
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
int x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
// restore the local stack counter
|
||||
void x87_unstackcount(dynarec_arm_t* dyn, int ninst, int scratch, int count);
|
||||
// fpu push. Return the Dd value to be used
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
@@ -678,6 +766,8 @@ int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
|
||||
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// Free st, using the FFREE opcode (so it's freed but stack is not moved)
|
||||
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st);
|
||||
// refresh a value from the cache ->emu (nothing done if value is not cached)
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
|
||||
@@ -740,10 +830,12 @@ 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 an SSE reg
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a, int s1);
|
||||
// sync reg with emu for sse reg (return 1 if reflect was done, s1 = &xmm[a] then)
|
||||
int sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a, int s1);
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
// reset the cache with n
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n);
|
||||
// propagate stack state
|
||||
@@ -800,21 +892,25 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#define NOTEST(s1) \
|
||||
#define NOTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s1, 0); \
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, test.test)); \
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, test.clean)); \
|
||||
MOVW(s2, offsetof(x86emu_t, test.test)); \
|
||||
STR_REG_LSL_IMM5(s1, xEmu, s2, 0); \
|
||||
ADD_IMM8(s2, s2, offsetof(x86emu_t, test.clean)-offsetof(x86emu_t, test.test));\
|
||||
STR_REG_LSL_IMM5(s1, xEmu, s2, 0); \
|
||||
}
|
||||
#define SKIPTEST(s1) \
|
||||
#define SKIPTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s1, 0); \
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, test.clean)); \
|
||||
MOVW(s2, offsetof(x86emu_t, test.clean)); \
|
||||
STR_REG_LSL_IMM5(s1, xEmu, s2, 0); \
|
||||
}
|
||||
#define GOTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s2, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, test.test)); \
|
||||
MOVW(s1, offsetof(x86emu_t, test.test)); \
|
||||
STR_REG_LSL_IMM5(s2, xEmu, s1, 0); \
|
||||
}
|
||||
|
||||
#endif //__DYNAREC_ARM_HELPER_H__
|
||||
@@ -27,6 +27,12 @@
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
#if STEP == 0
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 0x1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
@@ -43,12 +49,28 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_arm_t));
|
||||
#endif
|
||||
fpu_reset(dyn);
|
||||
int reset_n = -1;
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with bligblocks==2, else it needs 3 // ok, go now
|
||||
INIT;
|
||||
#if STEP == 0
|
||||
uintptr_t cur_page = (addr)&~box86_pagesize;
|
||||
#endif
|
||||
while(ok) {
|
||||
#if STEP == 0
|
||||
if(cur_page != (addr)&~box86_pagesize) {
|
||||
cur_page = (addr)&~box86_pagesize;
|
||||
if(!(getProtection(addr)&PROT_READ)) {
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ip = addr;
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
if (reset_n!=-1) {
|
||||
if(reset_n==-2) {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
|
||||
@@ -70,8 +92,12 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
}
|
||||
reset_n = -1;
|
||||
}
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
NEW_INST;
|
||||
#if STEP == 0
|
||||
if(ninst && dyn->insts[ninst-1].x86.barrier_next) {
|
||||
BARRIER(dyn->insts[ninst-1].x86.barrier_next);
|
||||
}
|
||||
#endif
|
||||
if(!ninst) {
|
||||
GOTEST(x1, x2);
|
||||
}
|
||||
@@ -116,7 +142,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
#if STEP > 0
|
||||
if(!dyn->insts[ninst].x86.has_next && dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts!=-1)
|
||||
next = dyn->insts[ninst].x86.jmp_insts;
|
||||
#endif
|
||||
if(dyn->insts[ninst].x86.has_next && dyn->insts[next].x86.barrier) {
|
||||
if(dyn->insts[next].x86.barrier&BARRIER_FLOAT)
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
@@ -125,6 +150,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->f.dfnone = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
@@ -133,8 +159,8 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
if(ii<dyn->size && !dyn->insts[ii].pred_sz) {
|
||||
while(ii<dyn->size && (!dyn->insts[ii].pred_sz || (dyn->insts[ii].pred_sz==1 && dyn->insts[ii].pred[0]==ii-1))) {
|
||||
if(ii<dyn->size && !dyn->insts[ii].x86.alive) {
|
||||
while(ii<dyn->size && !dyn->insts[ii].x86.alive) {
|
||||
// may need to skip opcodes to advance
|
||||
++ninst;
|
||||
NEW_INST;
|
||||
@@ -156,16 +182,25 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
#else
|
||||
// check if block need to be stopped, because it's a 00 00 opcode (unreadeable is already checked earlier)
|
||||
if((ok>0) && !dyn->forward && !(*(uint8_t*)addr) && !(*(uint8_t*)(addr+1))) {
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00");
|
||||
ok = 0;
|
||||
need_epilog = 1;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog) {
|
||||
if(dyn->forward_to == addr && !need_epilog && ok>=0) {
|
||||
// we made it!
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
reset_n = get_first_jump(dyn, addr);
|
||||
if(box86_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].x86.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to, reset_n, ninst);
|
||||
if(dyn->insts[dyn->forward_ninst].x86.has_callret && !dyn->insts[dyn->forward_ninst].x86.has_next)
|
||||
dyn->insts[dyn->forward_ninst].x86.has_next = 1; // this block actually continue
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
ok = 1; // in case it was 0
|
||||
} else if ((dyn->forward_to < addr) || !ok) {
|
||||
} else if ((dyn->forward_to < addr) || ok<=0) {
|
||||
// something when wrong! rollback
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
ok = 0;
|
||||
@@ -186,14 +221,14 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
|
||||
{
|
||||
ok = 1;
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
reset_n = -2;
|
||||
for(int ii=0; ii<ninst; ++ii)
|
||||
if(dyn->insts[ii].x86.jmp == next) {
|
||||
reset_n = ii;
|
||||
ii=ninst;
|
||||
}
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %p -> %p (ninst=%d, jump from %d)\n", dyn, (void*)addr, (void*)next, ninst, reset_n);
|
||||
if(dyn->insts[ninst].x86.has_callret && !dyn->insts[ninst].x86.has_next) {
|
||||
dyn->insts[ninst].x86.has_next = 1; // this block actually continue
|
||||
} else {
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
// and pred table is not ready yet
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
}
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x86.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst, dyn->insts[ninst].x86.has_callret?ninst:reset_n);
|
||||
} else if(next && (next-addr)<box86_dynarec_forward && (getProtection(next)&PROT_READ)/*box86_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
@@ -236,12 +271,15 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if((ok>0) && dyn->insts[ninst].x86.has_callret)
|
||||
reset_n = -2;
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && (((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)addr))
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_arm_t));
|
||||
if((ok>0) && (((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)addr))
|
||||
|| (addr>=box86_nodynarec_start && addr<box86_nodynarec_end)))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
if((ok>0) && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 0
|
||||
@@ -269,14 +307,14 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->insts[ninst].x86.need_after |= X_PEND;
|
||||
#endif
|
||||
++ninst;
|
||||
NOTEST(x3);
|
||||
NOTEST(x1, x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
NOTEST(x3);
|
||||
NOTEST(x1, x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
|
||||
@@ -12,20 +12,16 @@
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x86.set_flags = A; \
|
||||
dyn->insts[ninst].x86.state_flags = B; \
|
||||
dyn->insts[ninst].x86.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0;
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C; dyn->insts[ninst].x86.jmp_insts = 0
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x86.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst+1].x86.barrier = A
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst].x86.barrier_next = A
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x86.has_callret = 1
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_arm_t*)dynaRealloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2);\
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
dyn->insts[ninst].x86.addr = ip; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
@@ -40,7 +36,7 @@
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box86_dynarec_log>=LOG_INFO || box86_dynarec_dump) {\
|
||||
if(box86_dynarec_log>=LOG_INFO || box86_dynarec_dump || box86_dynarec_missing) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped @ %s (%s:%u) because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, __FUNCTION__, __FILE__, __LINE__, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
|
||||
@@ -41,10 +41,13 @@ typedef struct neoncache_s {
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint8_t pushed; // positive pushed value (to check for overflow)
|
||||
uint8_t poped; // positive poped value (to check for underflow)
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int16_t tags; // similar to fpu_tags
|
||||
int8_t mmxcache[8];// cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int8_t fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
@@ -97,6 +100,9 @@ typedef struct dynarec_arm_s {
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
int* jmps; // variable array of jump instructions
|
||||
int jmp_sz;
|
||||
int jmp_cap;
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
@@ -108,10 +114,13 @@ typedef struct dynarec_arm_s {
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint8_t always_test;
|
||||
uint8_t abort; // abort the creation of the block
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
void add_jump(dynarec_arm_t *dyn, int ninst);
|
||||
int get_first_jump(dynarec_arm_t *dyn, int next);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
|
||||
@@ -24,15 +24,22 @@
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
#define SF_DF 8
|
||||
#define SF_SET_DF (SF_SET|SF_DF)
|
||||
#define SF_NODF 16
|
||||
#define SF_SET_NODF (SF_SET|SF_NODF)
|
||||
|
||||
typedef struct instruction_x86_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint8_t jmp_cond; // 1 of conditionnal jump
|
||||
uint8_t has_next; // does this opcode can continue to the next?
|
||||
uint8_t jmp_cond:1; // 1 of conditionnal jump
|
||||
uint8_t has_next:1; // does this opcode can continue to the next?
|
||||
uint8_t has_callret:1; // this instruction have an optimised call setup
|
||||
uint8_t alive:1; // this opcode gets executed (0 if dead code in that block)
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
uint8_t barrier_next; // next instruction needs a barrier
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
uint8_t use_flags; // 0 or combination of X_?F
|
||||
uint8_t set_flags; // 0 or combination of X_?F
|
||||
|
||||
@@ -353,8 +353,10 @@ ARM_ cond 0 0 0 1 1 1 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXH<c> <Rd>, <Rt>,
|
||||
ARM_ cond 0 0 0 1 1 1 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXH<c> <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 1 0 0 0 0 S Rn Rd imm12 AND{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 0 1 S Rn Rd imm12 EOR{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #-<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 S Rn Rd imm12 SUB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 1 S Rn Rd imm12 RSB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 S Rn Rd imm12 ADD{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 1 S Rn Rd imm12 ADC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 1 0 S Rn Rd imm12 SBC{S}<c> <Rd>, <Rn>, #<const>
|
||||
|
||||
@@ -45,7 +45,9 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
|
||||
GO(SHT_GNU_ATTRIBUTES);
|
||||
GO(SHT_GNU_HASH);
|
||||
GO(SHT_GNU_LIBLIST);
|
||||
GO(SHT_CHECKSUM);
|
||||
#ifndef TERMUX
|
||||
GO(SHT_CHECKSUM);
|
||||
#endif
|
||||
GO(SHT_LOSUNW);
|
||||
//GO(SHT_SUNW_move);
|
||||
GO(SHT_SUNW_COMDAT);
|
||||
|
||||
+234
-223
@@ -67,6 +67,9 @@ elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
|
||||
h->globaldefver = NewDefaultVersion();
|
||||
h->weakdefver = NewDefaultVersion();
|
||||
h->refcnt = 1;
|
||||
|
||||
h->file = f;
|
||||
h->fileno = fileno(f);
|
||||
|
||||
return h;
|
||||
}
|
||||
@@ -98,6 +101,8 @@ void FreeElfHeader(elfheader_t** head)
|
||||
|
||||
box_free(h->name);
|
||||
box_free(h->path);
|
||||
if(h->file)
|
||||
fclose(h->file);
|
||||
box_free(h);
|
||||
|
||||
*head = NULL;
|
||||
@@ -167,196 +172,196 @@ const char* ElfPath(elfheader_t* head)
|
||||
return NULL;
|
||||
return head->path;
|
||||
}
|
||||
int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
|
||||
int AllocLoadElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
{
|
||||
uintptr_t offs = 0;
|
||||
loadProtectionFromMap();
|
||||
int log_level = box86_load_addr?LOG_INFO:LOG_DEBUG;
|
||||
|
||||
head->multiblock_n = 0; // count PHEntrie with LOAD
|
||||
uintptr_t max_align = (box86_pagesize-1);
|
||||
for (size_t i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags) {
|
||||
++head->multiblock_n;
|
||||
}
|
||||
|
||||
if(!head->vaddr && box86_load_addr) {
|
||||
offs = (uintptr_t)findBlockNearHint((void*)box86_load_addr, head->memsz);
|
||||
box86_load_addr += head->memsz*(1+mainbin);
|
||||
box86_load_addr = (box86_load_addr+0xffffffLL)&~0xffffffLL;
|
||||
offs = (uintptr_t)findBlockNearHint((void*)box86_load_addr, head->memsz, max_align);
|
||||
box86_load_addr = offs + head->memsz;
|
||||
box86_load_addr = (box86_load_addr+0x10ffffff)&~0xffffff;
|
||||
}
|
||||
int log_level = box86_load_addr?LOG_INFO:LOG_NEVER;
|
||||
if(!offs)
|
||||
offs = head->vaddr;
|
||||
if(head->vaddr) {
|
||||
head->multiblock_n = 0; // count PHEntrie with LOAD
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags)
|
||||
++head->multiblock_n;
|
||||
head->multiblock_size = (uint32_t*)box_calloc(head->multiblock_n, sizeof(uint32_t));
|
||||
head->multiblock_offs = (uintptr_t*)box_calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)box_calloc(head->multiblock_n, sizeof(void*));
|
||||
// and now, create all individual blocks
|
||||
head->memory = (char*)0xffffffff;
|
||||
int n = 0;
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
uintptr_t bstart = e->p_vaddr;
|
||||
uint32_t bsize = e->p_memsz;
|
||||
uintptr_t balign = e->p_align;
|
||||
if (balign) balign = balign-1; else balign = 1;
|
||||
if(balign<4095) balign = 4095;
|
||||
uintptr_t bend = (bstart + bsize + balign)&(~balign);
|
||||
bstart &= ~balign;
|
||||
int ok = 0;
|
||||
for (int j=0; !ok && j<n; ++j) {
|
||||
uintptr_t start = head->multiblock_offs[j];
|
||||
uintptr_t end = head->multiblock_offs[j] + head->multiblock_size[j];
|
||||
start &= ~balign;
|
||||
if( (head->e_type == ET_DYN) ||
|
||||
(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))))
|
||||
{
|
||||
// merge
|
||||
ok = 1;
|
||||
if(bstart<start)
|
||||
head->multiblock_offs[j] = bstart;
|
||||
head->multiblock_size[j] = ((bend>end)?bend:end) - head->multiblock_offs[j];
|
||||
--head->multiblock_n;
|
||||
if(!offs && !head->vaddr)
|
||||
offs = (uintptr_t)find32bitBlockElf(head->memsz, mainbin, max_align);
|
||||
// prereserve the whole elf image, without populating
|
||||
size_t sz = head->memsz;
|
||||
void* raw = NULL;
|
||||
void* image = NULL;
|
||||
if(!head->vaddr) {
|
||||
sz += head->align;
|
||||
raw = mmap64((void*)offs, sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
|
||||
image = (void*)(((uintptr_t)raw+max_align)&~max_align);
|
||||
} else {
|
||||
image = raw = mmap64((void*)head->vaddr, sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
if(image!=MAP_FAILED && !head->vaddr && image!=(void*)offs) {
|
||||
printf_log(LOG_INFO, "%s: Mmap64 for (@%p 0x%zx) for elf \"%s\" returned %p(%p/0x%zx) instead\n", (((uintptr_t)image)&max_align)?"Error":"Warning", (void*)(head->vaddr?head->vaddr:offs), head->memsz, head->name, image, raw, head->align);
|
||||
offs = (uintptr_t)image;
|
||||
if(((uintptr_t)image)&max_align) {
|
||||
munmap(raw, sz);
|
||||
return 1; // that's an error, alocated memory is not aligned properly
|
||||
}
|
||||
}
|
||||
if(image==MAP_FAILED || image!=(void*)(head->vaddr?head->vaddr:offs)) {
|
||||
printf_log(LOG_NONE, "%s cannot create memory map (@%p 0x%zx) for elf \"%s\"", (image==MAP_FAILED)?"Error:":"Warning:", (void*)(head->vaddr?head->vaddr:offs), head->memsz, head->name);
|
||||
if(image==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno));
|
||||
} else {
|
||||
printf_log(LOG_NONE, " got %p\n", image);
|
||||
}
|
||||
if(image==MAP_FAILED)
|
||||
return 1;
|
||||
offs = (uintptr_t)image-head->vaddr;
|
||||
}
|
||||
printf_dump(log_level, "Pre-allocated 0x%zx byte at %p for %s\n", head->memsz, image, head->name);
|
||||
head->delta = offs;
|
||||
printf_dump(log_level, "Delta of %p (vaddr=%p) for Elf \"%s\"\n", (void*)offs, (void*)head->vaddr, head->name);
|
||||
|
||||
head->image = image;
|
||||
head->raw = raw;
|
||||
head->raw_size = sz;
|
||||
setProtection_elf((uintptr_t)raw, sz, 0);
|
||||
|
||||
head->multiblocks = (multiblock_t*)box_calloc(head->multiblock_n, sizeof(multiblock_t));
|
||||
head->tlsbase = AddTLSPartition(context, head->tlssize);
|
||||
// and now, create all individual blocks
|
||||
head->memory = (char*)0xffffffff;
|
||||
int n = 0;
|
||||
for (size_t i=0; i<head->numPHEntries; ++i) {
|
||||
if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
|
||||
head->multiblocks[n].flags = e->p_flags;
|
||||
head->multiblocks[n].offs = e->p_offset;
|
||||
head->multiblocks[n].paddr = e->p_paddr + offs;
|
||||
head->multiblocks[n].size = e->p_filesz;
|
||||
head->multiblocks[n].align = e->p_align;
|
||||
uint8_t prot = PROT_READ|PROT_WRITE|((e->p_flags & PF_X)?PROT_EXEC:0);
|
||||
// check if alignment is correct
|
||||
uintptr_t balign = head->multiblocks[n].align-1;
|
||||
if(balign<4095) balign = 4095;
|
||||
head->multiblocks[n].asize = (e->p_memsz+(e->p_paddr&balign)+4095)&~4095;
|
||||
int try_mmap = 1;
|
||||
if(e->p_paddr&balign)
|
||||
try_mmap = 0;
|
||||
if(e->p_offset&(box86_pagesize-1))
|
||||
try_mmap = 0;
|
||||
if(ALIGN(e->p_memsz)!=ALIGN(e->p_filesz))
|
||||
try_mmap = 0;
|
||||
if(!e->p_filesz)
|
||||
try_mmap = 0;
|
||||
if(e->p_align<box86_pagesize)
|
||||
try_mmap = 0;
|
||||
if(try_mmap) {
|
||||
printf_dump(log_level, "Mmaping 0x%lx(0x%lx) bytes @%p for Elf \"%s\"\n", head->multiblocks[n].size, head->multiblocks[n].asize, (void*)head->multiblocks[n].paddr, head->name);
|
||||
void* p = mmap64(
|
||||
(void*)head->multiblocks[n].paddr,
|
||||
head->multiblocks[n].size,
|
||||
prot,
|
||||
MAP_PRIVATE|MAP_FIXED, //((prot&PROT_WRITE)?MAP_SHARED:MAP_PRIVATE)|MAP_FIXED,
|
||||
head->fileno,
|
||||
e->p_offset
|
||||
);
|
||||
if(p==MAP_FAILED || p!=(void*)head->multiblocks[n].paddr) {
|
||||
try_mmap = 0;
|
||||
printf_dump(log_level, "Mapping failed, using regular mmap+read");
|
||||
} else {
|
||||
if(e->p_memsz>e->p_filesz && (prot&PROT_WRITE))
|
||||
memset((void*)((uintptr_t)p + e->p_filesz), 0, e->p_memsz-e->p_filesz);
|
||||
setProtection_elf((uintptr_t)p, head->multiblocks[n].asize, prot);
|
||||
head->multiblocks[n].p = p;
|
||||
|
||||
}
|
||||
}
|
||||
if(!try_mmap) {
|
||||
uintptr_t paddr = head->multiblocks[n].paddr&~balign;
|
||||
size_t asize = head->multiblocks[n].asize;
|
||||
void* p = MAP_FAILED;
|
||||
if(paddr==(paddr&~(box86_pagesize-1)) && (asize==ALIGN(asize))) {
|
||||
printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", asize, e->p_memsz, (void*)paddr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
|
||||
p = mmap64(
|
||||
(void*)paddr,
|
||||
asize,
|
||||
prot|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
|
||||
-1,
|
||||
0
|
||||
);
|
||||
} else {
|
||||
// difference in pagesize, so need to mmap only what needed to be...
|
||||
//check startint point
|
||||
uintptr_t new_addr = paddr;
|
||||
ssize_t new_size = asize;
|
||||
while(getProtection(new_addr) && (new_size>0)) {
|
||||
new_size -= ALIGN(new_addr) - new_addr;
|
||||
new_addr = ALIGN(new_addr);
|
||||
}
|
||||
if(new_size>0) {
|
||||
printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", ALIGN(new_size), e->p_memsz, (void*)new_addr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
|
||||
p = mmap64(
|
||||
(void*)new_addr,
|
||||
ALIGN(new_size),
|
||||
prot|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
|
||||
-1,
|
||||
0
|
||||
);
|
||||
if(p==(void*)new_addr)
|
||||
p = (void*)paddr;
|
||||
} else {
|
||||
p = (void*)paddr;
|
||||
printf_dump(log_level, "Will read 0x%zx @%p for Elf \"%s\"\n", e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
head->multiblock_offs[n] = bstart;
|
||||
head->multiblock_size[n] = bend - head->multiblock_offs[n];
|
||||
++n;
|
||||
}
|
||||
}
|
||||
head->multiblock_n = n; // might be less in fact
|
||||
for (int i=0; i<head->multiblock_n; ++i) {
|
||||
|
||||
uintptr_t sz = head->multiblock_size[i];
|
||||
if(my_context->elfsize==1) {
|
||||
if(head->multiblock_n==1)
|
||||
head->reserve = 2*1024*1024; // reserve 2Mb after bss
|
||||
sz+=head->reserve;
|
||||
}
|
||||
printf_dump(log_level, "Allocating 0x%x memory %p for Elf \"%s\"\n", sz, (void*)head->multiblock_offs[i], head->name);
|
||||
void* p = mmap((void*)head->multiblock_offs[i], sz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS /*| ((wine_preloaded)?MAP_FIXED:0)*/
|
||||
, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, "Cannot create memory map (%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
if(head->multiblock_offs[i] &&( p!=(void*)head->multiblock_offs[i])) {
|
||||
if((head->e_type!=ET_DYN)) {
|
||||
printf_log(LOG_NONE, "Error, memory map (%p 0x%zx/0x%zx) for elf \"%s\" allocated %p\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name, p);
|
||||
if(p==MAP_FAILED || p!=(void*)paddr) {
|
||||
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%zx/0x%zx) for elf \"%s\"", (void*)paddr, asize, balign, head->name);
|
||||
if(p==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno));
|
||||
} else {
|
||||
printf_log(LOG_NONE, " got %p\n", p);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Allocated memory is not at hinted %p but %p (size %p) \"%s\"\n", (void*)head->multiblock_offs[i], p, (void*)head->multiblock_size[i], head->name);
|
||||
// need to adjust vaddr!
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
if(e->p_vaddr>=head->multiblock_offs[i] && e->p_vaddr<(head->multiblock_offs[i]+head->multiblock_size[i])) {
|
||||
e->p_vaddr = e->p_vaddr - head->multiblock_offs[i] + (uintptr_t)p;
|
||||
if(!head->delta) head->delta = (intptr_t)p - (intptr_t)head->multiblock_offs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setProtection((uintptr_t)p, head->multiblock_size[i], PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
head->multiblock[i] = p;
|
||||
if(p<(void*)head->memory)
|
||||
head->memory = (char*)p;
|
||||
}
|
||||
} else {
|
||||
// vaddr is 0, load everything has a One block
|
||||
printf_dump(log_level, "Allocating 0x%zx memory %p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
|
||||
void* p = mmap((void*)offs, head->memsz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS /*| (((offs&&wine_preloaded)?MAP_FIXED:0))*/
|
||||
, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, "Cannot create memory map (%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)offs, head->memsz, head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
if(offs && (p!=(void*)offs) && (head->e_type!=ET_DYN)) {
|
||||
printf_log(LOG_NONE, "Error, memory map (%p 0x%zx/0x%zx) for elf \"%s\" allocated %p\n", (void*)offs, head->memsz, head->align, head->name, p);
|
||||
return 1;
|
||||
}
|
||||
setProtection((uintptr_t)p, head->memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
head->memory = p;
|
||||
memset(p, 0, head->memsz);
|
||||
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
|
||||
printf_dump(log_level, "Got %p (delta=%p)\n", p, (void*)head->delta);
|
||||
|
||||
head->multiblock_n = 1;
|
||||
head->multiblock_size = (uint32_t*)box_calloc(head->multiblock_n, sizeof(uint32_t));
|
||||
head->multiblock_offs = (uintptr_t*)box_calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)box_calloc(head->multiblock_n, sizeof(void*));
|
||||
head->multiblock_size[0] = head->memsz;
|
||||
head->multiblock_offs[0] = (uintptr_t)p;
|
||||
head->multiblock[0] = p;
|
||||
}
|
||||
|
||||
head->tlsbase = AddTLSPartition(context, head->tlssize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FreeElfMemory(elfheader_t* head)
|
||||
{
|
||||
if(head->multiblock_n) {
|
||||
if(head->multiblock_n==1)
|
||||
munmap(head->multiblock[0], head->multiblock_size[0]+head->reserve);
|
||||
else
|
||||
for(int i=0; i<head->multiblock_n; ++i)
|
||||
munmap(head->multiblock[i], head->multiblock_size[i]);
|
||||
#ifdef DYNAREC
|
||||
for(int i=0; i<head->multiblock_n; ++i) {
|
||||
dynarec_log(LOG_INFO, "Free DynaBlocks for %s\n", head->path);
|
||||
cleanDBFromAddressRange((uintptr_t)head->multiblock[i], head->multiblock_size[i], 1);
|
||||
freeProtection((uintptr_t)head->multiblock[i], head->multiblock_size[i]);
|
||||
}
|
||||
#endif
|
||||
box_free(head->multiblock);
|
||||
box_free(head->multiblock_size);
|
||||
box_free(head->multiblock_offs);
|
||||
}
|
||||
}
|
||||
|
||||
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
{
|
||||
for (int i=0; i<head->numPHEntries; ++i) {
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
char* dest = (char*)e->p_paddr + head->delta;
|
||||
void* p = (void*)-1;
|
||||
if(e->p_memsz==e->p_filesz && !(e->p_align&0xfff)) {
|
||||
printf_dump(LOG_NEVER, "MMap block #%zu @%p offset=%p (0x%zx/0x%zx, flags:0x%x)\n", i, dest, (void*)e->p_offset, e->p_filesz, e->p_memsz, e->p_flags);
|
||||
p = mmap(dest, e->p_filesz, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fileno(f), e->p_offset);
|
||||
}
|
||||
if(p!=dest) {
|
||||
printf_dump(LOG_NEVER, "Loading block #%d %p (0x%zx/0x%zx)\n",i, dest, e->p_filesz, e->p_memsz);
|
||||
fseeko64(f, e->p_offset, SEEK_SET);
|
||||
setProtection_elf((uintptr_t)p, asize, prot);
|
||||
head->multiblocks[n].p = p;
|
||||
if(e->p_filesz) {
|
||||
if(fread(dest, e->p_filesz, 1, f)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d (size=%zd)\n", i, e->p_filesz);
|
||||
fseeko64(head->file, head->multiblocks[n].offs, SEEK_SET);
|
||||
if(fread((void*)head->multiblocks[n].paddr, head->multiblocks[n].size, 1, head->file)!=1) {
|
||||
printf_log(LOG_NONE, "Cannot read elf block (@%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)head->multiblocks[n].offs, head->multiblocks[n].asize, balign, head->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(!(prot&PROT_WRITE) && (paddr==(paddr&(box86_pagesize-1)) && (asize==ALIGN(asize))))
|
||||
mprotect((void*)paddr, asize, prot);
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec && (e->p_flags & PF_X)) {
|
||||
printf_dump(LOG_NEVER, "Add ELF eXecutable Memory %p:%p\n", dest, (void*)e->p_memsz);
|
||||
addDBFromAddressRange((uintptr_t)dest, e->p_memsz);
|
||||
dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", head->multiblocks[n].p, (void*)head->multiblocks[n].asize);
|
||||
addDBFromAddressRange((uintptr_t)head->multiblocks[n].p, head->multiblocks[n].asize);
|
||||
}
|
||||
#endif
|
||||
|
||||
// zero'd difference between filesz and memsz
|
||||
/*if(e->p_filesz != e->p_memsz)
|
||||
memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);*/ //block is already 0'd at creation
|
||||
if((uintptr_t)head->memory>(uintptr_t)head->multiblocks[n].p)
|
||||
head->memory = (char*)head->multiblocks[n].p;
|
||||
++n;
|
||||
}
|
||||
if(head->PHEntries[i].p_type == PT_TLS) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
|
||||
printf_dump(LOG_NEVER, "Loading TLS block #%i %p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
if(e->p_filesz) {
|
||||
fseeko64(f, e->p_offset, SEEK_SET);
|
||||
if(fread(dest, e->p_filesz, 1, f)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_TLS part #%d (size=%zd)\n", i, e->p_filesz);
|
||||
fseeko64(head->file, e->p_offset, SEEK_SET);
|
||||
if(fread(dest, e->p_filesz, 1, head->file)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_TLS part #%zu (size=%zd)\n", i, e->p_filesz);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -365,9 +370,36 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);
|
||||
}
|
||||
}
|
||||
|
||||
// can close the elf file now!
|
||||
fclose(head->file);
|
||||
head->file = NULL;
|
||||
head->fileno = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FreeElfMemory(elfheader_t* head)
|
||||
{
|
||||
if(head->multiblock_n) {
|
||||
#ifdef DYNAREC
|
||||
for(int i=0; i<head->multiblock_n; ++i) {
|
||||
dynarec_log(LOG_INFO, "Free DynaBlocks %p-%p for %s\n", head->multiblocks[i].p, head->multiblocks[i].p+head->multiblocks[i].asize, head->path);
|
||||
if(box86_dynarec)
|
||||
cleanDBFromAddressRange((uintptr_t)head->multiblocks[i].p, head->multiblocks[i].asize, 1);
|
||||
freeProtection((uintptr_t)head->multiblocks[i].p, head->multiblocks[i].asize);
|
||||
}
|
||||
#endif
|
||||
box_free(head->multiblocks);
|
||||
}
|
||||
// we only need to free the overall mmap, no need to free individual part as they are inside the big one
|
||||
if(head->raw && head->raw_size) {
|
||||
dynarec_log(LOG_INFO, "Unmap elf memory %p-%p for %s\n", head->raw, head->raw+head->raw_size, head->path);
|
||||
munmap(head->raw, head->raw_size);
|
||||
}
|
||||
freeProtection((uintptr_t)head->raw, head->raw_size);
|
||||
}
|
||||
|
||||
int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verneeded)
|
||||
{
|
||||
if(!verneeded || !head)
|
||||
@@ -385,37 +417,6 @@ int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verne
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
{
|
||||
(void)context;
|
||||
for (int i=0; i<head->numPHEntries; ++i) {
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
char* dest = (char*)e->p_paddr + head->delta;
|
||||
printf_log(LOG_DEBUG, "Re-loading block #%i %p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
int ret = fseeko64(f, e->p_offset, SEEK_SET);
|
||||
if(ret==-1) {printf_log(LOG_NONE, "Fail to (re)seek PT_LOAD part #%d (offset=%zd, errno=%d/%s)\n", i, e->p_offset, errno, strerror(errno)); return 1;}
|
||||
#ifdef DYNAREC
|
||||
cleanDBFromAddressRange((uintptr_t)dest, e->p_memsz, 0);
|
||||
#endif
|
||||
uint32_t page_offset = (uintptr_t)dest & (box86_pagesize - 1);
|
||||
mprotect(dest - page_offset, e->p_memsz + page_offset, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
setProtection((uintptr_t)dest - page_offset, e->p_memsz + page_offset, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
if(e->p_filesz) {
|
||||
ssize_t r = -1;
|
||||
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
|
||||
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%d (dest=%p, size=%zd, return=%zd, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// zero'd difference between filesz and memsz
|
||||
if(e->p_filesz != e->p_memsz)
|
||||
memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);
|
||||
}
|
||||
}
|
||||
// TLS data are just a copy, no need to re-load it
|
||||
return 0;
|
||||
}
|
||||
int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t** p, size_t size, int version, const char* vername)
|
||||
{
|
||||
if(!h)
|
||||
@@ -429,14 +430,14 @@ int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t*
|
||||
int t = ELF32_R_TYPE(rel[i].r_info);
|
||||
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel[i].r_info)];
|
||||
const char* symname = SymName(h, sym);
|
||||
if(t==R_386_COPY && symname && !strcmp(symname, name) && sym->st_size==size) {
|
||||
if((t==R_386_COPY) && symname && !strcmp(symname, name) && (sym->st_size==size)) {
|
||||
int version2 = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[ELF32_R_SYM(rel[i].r_info)]:-1;
|
||||
if(version2!=-1) version2 &= 0x7fff;
|
||||
if(version && !version2) version2=-1; // match a versionned symbol against a global "local" symbol
|
||||
const char* vername2 = GetSymbolVersion(h, version2);
|
||||
if(SameVersionedSymbol(name, version, vername, symname, version2, vername2)) {
|
||||
*offs = sym->st_value + h->delta;
|
||||
*p = (uint32_t*)(rel[i].r_offset + h->delta);
|
||||
if(offs) *offs = sym->st_value + h->delta;
|
||||
if(p) *p = (uint32_t*)(rel[i].r_offset + h->delta);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -496,7 +497,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
weakdefver = old_weakdefver;
|
||||
} else {
|
||||
old_globdefver = globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(maplib, local_maplib, 0, symname);
|
||||
old_weakdefver = weakdefver = (bind==STB_WEAK)?GetMaplibDefaultVersion(maplib, local_maplib, 1, symname):NULL;
|
||||
old_weakdefver = weakdefver = (bind==STB_WEAK || !globdefver)?GetMaplibDefaultVersion(maplib, local_maplib, 1, symname):NULL;
|
||||
}
|
||||
if(bind==STB_LOCAL) {
|
||||
if(!symname || !symname[0]) {
|
||||
@@ -526,9 +527,10 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
GetGlobalWeakSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end)
|
||||
GetGlobalWeakSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
} else {
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
@@ -588,7 +590,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
}
|
||||
break;
|
||||
case R_386_GLOB_DAT:
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername, globdefver) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
if((head!=my_context->elfs[0]) && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername, globdefver) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
// set global offs / size for the symbol
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
@@ -606,14 +608,14 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
}
|
||||
*p = globoffs;
|
||||
} else {
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(local_maplib?local_maplib:maplib, symname, &globoffs, &globend, version, vername, globdefver)) {
|
||||
if((size==0 )&& GetSymbolStartEnd(GetGlobalData(maplib), symname, &globoffs, &globend, version, vername, 0, globdefver)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start"))
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start")) {
|
||||
printf_log((bind==STB_GLOBAL)?LOG_NONE:LOG_INFO, "%s: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", (bind==STB_GLOBAL)?"Error":"Warning", symname, p, *(void**)p, head->name);
|
||||
if(bind==STB_GLOBAL) ret_ok=1;
|
||||
}
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)");
|
||||
*p = offs/* + rela[i].r_addend*/; // not addend it seems
|
||||
@@ -700,8 +702,8 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
}
|
||||
if(h_tls) {
|
||||
delta = *(int32_t*)p;
|
||||
printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType(t), symname, p, delta, -h_tls->tlsbase, -(int32_t)offs, end-offs);
|
||||
*p = (uintptr_t)(-(int32_t)offs + h_tls->tlsbase);
|
||||
printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType(t), symname, p, delta, -h_tls->tlsbase, (int32_t)offs, end-offs);
|
||||
*p = (uintptr_t)((int32_t)offs - h_tls->tlsbase);
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType(t), symname, p, (int32_t)offs);
|
||||
}
|
||||
@@ -785,7 +787,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
weakdefver = old_weakdefver;
|
||||
} else {
|
||||
old_globdefver = globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(maplib, local_maplib, 0, symname);
|
||||
old_weakdefver = weakdefver = (bind==STB_WEAK)?GetMaplibDefaultVersion(maplib, local_maplib, 1, symname):NULL;
|
||||
old_weakdefver = weakdefver = (bind==STB_WEAK || !globdefver)?GetMaplibDefaultVersion(maplib, local_maplib, 1, symname):NULL;
|
||||
}
|
||||
if(bind==STB_LOCAL) {
|
||||
if(!symname || !symname[0]) {
|
||||
@@ -824,9 +826,10 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -894,10 +897,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
*p = globoffs;
|
||||
} else {
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(local_maplib?local_maplib:maplib, symname, &globoffs, &globend, version, vername, globdefver)) {
|
||||
if((size==0 )&& GetSymbolStartEnd(GetGlobalData(maplib), symname, &globoffs, &globend, version, vername, 0, globdefver)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start"))
|
||||
@@ -986,8 +987,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
if(h_tls) {
|
||||
delta = *(int32_t*)p;
|
||||
printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType(t), symname, p, delta, -h_tls->tlsbase, -(int32_t)offs, end-offs);
|
||||
*p = (uintptr_t)(-(int32_t)offs + rela[i].r_addend + h_tls->tlsbase);
|
||||
printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType(t), symname, p, delta, -h_tls->tlsbase, (int32_t)offs, end-offs);
|
||||
*p = (uintptr_t)((int32_t)offs + rela[i].r_addend - h_tls->tlsbase);
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType(t), symname, p, (int32_t)offs);
|
||||
}
|
||||
@@ -1103,7 +1104,7 @@ int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CalcStack(elfheader_t* elf, uint32_t* stacksz, uint32_t* stackalign)
|
||||
void CalcStack(elfheader_t* elf, uint32_t* stacksz, size_t* stackalign)
|
||||
{
|
||||
if(*stacksz < elf->stacksz)
|
||||
*stacksz = elf->stacksz;
|
||||
@@ -1557,8 +1558,8 @@ int IsAddressInElfSpace(const elfheader_t* h, uintptr_t addr)
|
||||
if(!h)
|
||||
return 0;
|
||||
for(int i=0; i<h->multiblock_n; ++i) {
|
||||
uintptr_t base = h->multiblock_offs[i];
|
||||
uintptr_t end = h->multiblock_offs[i] + h->multiblock_size[i] - 1;
|
||||
uintptr_t base = (uintptr_t)h->multiblocks[i].p;
|
||||
uintptr_t end = (uintptr_t)h->multiblocks[i].p + h->multiblocks[i].asize - 1;
|
||||
if(addr>=base && addr<=end)
|
||||
return 1;
|
||||
|
||||
@@ -1582,6 +1583,8 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
const char* ret = NULL;
|
||||
uintptr_t s = 0;
|
||||
uint32_t size = 0;
|
||||
if((uintptr_t)p<0x10000)
|
||||
return ret;
|
||||
#ifdef HAVE_TRACE
|
||||
if(!h) {
|
||||
if(getProtection((uintptr_t)p)&(PROT_READ)) {
|
||||
@@ -1805,7 +1808,7 @@ static int my_dl_iterate_phdr_##A(struct dl_phdr_info* a, size_t b, void* c)
|
||||
{ \
|
||||
if(!a->dlpi_name) \
|
||||
return 0; \
|
||||
if(!a->dlpi_name[0]) /*don't send informations about box86 itself*/ \
|
||||
if(!a->dlpi_name[0]) /*don't send information about box86 itself*/ \
|
||||
return 0; \
|
||||
return RunFunctionFmt(my_dl_iterate_phdr_fct_##A, "pLp", a, b, c); \
|
||||
}
|
||||
@@ -2030,6 +2033,9 @@ kh_defaultversion_t* GetWeakDefaultVersion(elfheader_t* h)
|
||||
return h?h->weakdefver:NULL;
|
||||
}
|
||||
|
||||
#ifndef STT_GNU_IFUNC
|
||||
#define STT_GNU_IFUNC 10
|
||||
#endif
|
||||
|
||||
uintptr_t pltResolver = ~(uintptr_t)0;
|
||||
EXPORT void PltResolver(x86emu_t* emu)
|
||||
@@ -2073,6 +2079,11 @@ EXPORT void PltResolver(x86emu_t* emu)
|
||||
printf_dump(LOG_DEBUG, "symbol %s from %s but elf not initialized yet, run Init now (from %s)\n", symname, ElfName(sym_elf), ElfName(h));
|
||||
RunElfInitPltResolver(sym_elf, emu);
|
||||
}
|
||||
if(sym_elf && sym && ((sym->st_info&0xf)==STT_GNU_IFUNC)) {
|
||||
// this is an IFUNC, needs to evaluate the function first!
|
||||
printf_dump(LOG_DEBUG, " Indirect function, will call the resolver now at %p\n", (void*)offs);
|
||||
offs = RunFunction(offs, 0);
|
||||
}
|
||||
offs = (uintptr_t)getAlternate((void*)offs);
|
||||
|
||||
if(p) {
|
||||
|
||||
@@ -8,7 +8,18 @@ typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
#include <elf.h>
|
||||
#include "elfloader.h"
|
||||
|
||||
struct elfheader_s {
|
||||
|
||||
typedef struct multiblock_s {
|
||||
void* p;
|
||||
uintptr_t offs;
|
||||
uintptr_t paddr;
|
||||
uintptr_t align;
|
||||
size_t size;
|
||||
size_t asize;
|
||||
uint8_t flags;
|
||||
} multiblock_t;
|
||||
|
||||
typedef struct elfheader_s {
|
||||
char* name;
|
||||
char* path; // Resolved path to file
|
||||
char* soname; // soname of the elf
|
||||
@@ -38,6 +49,9 @@ struct elfheader_s {
|
||||
uint32_t flags;
|
||||
|
||||
intptr_t delta; // should be 0
|
||||
void* image;
|
||||
void* raw; // raw pointer (might be unaligned vs image and max_align of elf)
|
||||
size_t raw_size;
|
||||
|
||||
uintptr_t entrypoint;
|
||||
uintptr_t initentry;
|
||||
@@ -92,20 +106,21 @@ struct elfheader_s {
|
||||
int malloc_hook_2; // this elf hook malloc, hacking it
|
||||
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
void** multiblock;
|
||||
uintptr_t* multiblock_offs;
|
||||
uint32_t* multiblock_size;
|
||||
multiblock_t* multiblocks;
|
||||
int multiblock_n;
|
||||
|
||||
library_t *lib;
|
||||
needed_libs_t *needed;
|
||||
|
||||
FILE* file;
|
||||
int fileno;
|
||||
|
||||
kh_mapsymbols_t *mapsymbols;
|
||||
kh_mapsymbols_t *weaksymbols;
|
||||
kh_mapsymbols_t *localsymbols;
|
||||
kh_defaultversion_t *globaldefver; // the global default version for symbols (the XXX@@vvvv of symbols)
|
||||
kh_defaultversion_t *weakdefver; // the weak default version for symbols (the XXX@@vvvv of symbols)
|
||||
};
|
||||
} elfheader_t;
|
||||
|
||||
#define R_386_NONE 0
|
||||
#define R_386_32 1
|
||||
|
||||
+19
-2
@@ -242,8 +242,10 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
if(val)
|
||||
printf_dump(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
|
||||
#ifndef ANDROID
|
||||
if(val)
|
||||
printf_dump(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
|
||||
#endif
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
@@ -469,4 +471,19 @@ const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetNeededVersionForLib(elfheader_t* h, const char* libname, const char* ver)
|
||||
{
|
||||
if(!libname || !ver)
|
||||
return 0;
|
||||
int n = GetNeededVersionCnt(h, libname);
|
||||
if(!n)
|
||||
return 0;
|
||||
for(int i=0; i<n; ++i) {
|
||||
const char* vername = GetNeededVersionString(h, libname, i);
|
||||
if(vername && !strcmp(ver, vername))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+15
-14
@@ -21,6 +21,7 @@
|
||||
#endif
|
||||
|
||||
// ModRM utilities macros
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
#define getecommon(A, T) \
|
||||
if(!(nextop&0xC0)) { \
|
||||
if((nextop&7)==4) { \
|
||||
@@ -107,7 +108,7 @@
|
||||
case 7: base = R_BX; break; \
|
||||
} \
|
||||
switch((m>>6)&3) { \
|
||||
case 0: if(m&7==6) base = F16S; break; \
|
||||
case 0: if((m&7)==6) base = F16S; break; \
|
||||
case 1: base += F8S; break; \
|
||||
case 2: base += F16S; break; \
|
||||
} \
|
||||
@@ -116,11 +117,11 @@
|
||||
|
||||
|
||||
#define geteb(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommon(A, reg32_t)
|
||||
#define testeb(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else { \
|
||||
reg32_t* ret; \
|
||||
@@ -131,19 +132,19 @@
|
||||
A = (reg32_t*)test->mem;\
|
||||
}
|
||||
#define getebo(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define geted(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon(A, reg32_t)
|
||||
#define getedo(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define tested(A, SZ, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else {\
|
||||
reg32_t* ret; \
|
||||
@@ -154,11 +155,11 @@
|
||||
A = (reg32_t*)test->mem;\
|
||||
}
|
||||
#define getem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else getecommon(A, mmx87_regs_t)
|
||||
#define testem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else {\
|
||||
mmx87_regs_t* ret; \
|
||||
@@ -169,11 +170,11 @@
|
||||
A = (mmx87_regs_t*)test->mem;\
|
||||
}
|
||||
#define getex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
} else getecommon(A, sse_regs_t)
|
||||
#define testex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
} else {\
|
||||
sse_regs_t* ret; \
|
||||
@@ -184,15 +185,15 @@
|
||||
A = (sse_regs_t*)test->mem;\
|
||||
}
|
||||
#define getew16(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon16(A, reg32_t)
|
||||
#define getew16o(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon16o(A, reg32_t, O)
|
||||
#define testtew16(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else { \
|
||||
reg32_t* ret; \
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86compstrings.h"
|
||||
|
||||
static int overrideIfDataInvalid(sse_regs_t* mem, int lmem, sse_regs_t* reg, int lreg, int j, int i, int imm8)
|
||||
{
|
||||
int valid1 = (i<lreg);
|
||||
int valid2 = (j<lmem);
|
||||
if(!valid1 && !valid2)
|
||||
switch((imm8>>2)&3) {
|
||||
case 0b00:
|
||||
case 0b01: return 0;
|
||||
case 0b10:
|
||||
case 0b11: return 1;
|
||||
}
|
||||
if(!valid1 && valid2)
|
||||
switch((imm8>>2)&3) {
|
||||
case 0b00:
|
||||
case 0b01:
|
||||
case 0b10: return 0;
|
||||
case 0b11: return 1;
|
||||
}
|
||||
if(valid1 && !valid2)
|
||||
return 0;
|
||||
switch((imm8>>2)&3) {
|
||||
case 0b01: // range
|
||||
switch (imm8&3) {
|
||||
case 0b00: // ub
|
||||
return (i&1)?((reg->ub[i]>=mem->ub[j])):((reg->ub[i]<=mem->ub[j]));
|
||||
case 0b01: // uw
|
||||
return (i&1)?((reg->uw[i]>=mem->uw[j])):((reg->uw[i]<=mem->uw[j]));
|
||||
case 0b10: // sb
|
||||
return (i&1)?((reg->sb[i]>=mem->sb[j])):((reg->sb[i]<=mem->sb[j]));
|
||||
case 0b11: // sw
|
||||
return (i&1)?((reg->sw[i]>=mem->sw[j])):((reg->sw[i]<=mem->sw[j]));
|
||||
}
|
||||
break;
|
||||
default: // the others
|
||||
switch (imm8&1) {
|
||||
case 0: // byte
|
||||
return (reg->ub[i] == mem->ub[j]);
|
||||
case 1: // word
|
||||
return (reg->uw[i] == mem->uw[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t sse42_compare_string_explicit_len(x86emu_t* emu, sse_regs_t* mem, int lmem, sse_regs_t* reg, int lreg, uint8_t imm8)
|
||||
{
|
||||
// get number of packed byte/word
|
||||
int n_packed = (imm8&1)?8:16;
|
||||
if(lreg<0) lreg = -lreg;
|
||||
if(lmem<0) lmem = -lmem;
|
||||
if(lreg>n_packed) lreg = n_packed;
|
||||
if(lmem>n_packed) lmem = n_packed;
|
||||
// aggregate to intres1
|
||||
uint32_t intres1 = 0;
|
||||
switch((imm8>>2)&3) {
|
||||
case 0b00: //Equal any
|
||||
for(int j=0; j<n_packed; ++j)
|
||||
for(int i=0; i<n_packed; ++i) {
|
||||
intres1 |= overrideIfDataInvalid(mem, lmem, reg, lreg, j, i, imm8)<<j;
|
||||
}
|
||||
break;
|
||||
case 0b01: // Range
|
||||
for(int j=0; j<n_packed; ++j)
|
||||
for(int i=0; i<n_packed; i+=2) {
|
||||
intres1 |= (overrideIfDataInvalid(mem, lmem, reg, lreg, j, i, imm8) & overrideIfDataInvalid(mem, lmem, reg, lreg, j, i+1, imm8))<<j;
|
||||
}
|
||||
break;
|
||||
case 0b10: // Equal each
|
||||
for(int i=0; i<n_packed; ++i) {
|
||||
intres1 |= overrideIfDataInvalid(mem, lmem, reg, lreg, i, i, imm8)<<i;
|
||||
}
|
||||
break;
|
||||
case 0b11: // Equal ordered
|
||||
intres1 = (1<<n_packed)-1;
|
||||
for(int j=0; j<n_packed; ++j)
|
||||
for(int i=0; i<n_packed-j; ++i) {
|
||||
#if 1
|
||||
if(!overrideIfDataInvalid(mem, lmem, reg, lreg, i+j, i, imm8)) {
|
||||
intres1 &= ~(1<<j);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
int k = i+j;
|
||||
intres1 &= (((1<<n_packed)-1)^(1<<j)) | overrideIfDataInvalid(mem, lmem, reg, lreg, k, i, imm8)<<j;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
// build intres2
|
||||
uint32_t intres2 = intres1;
|
||||
switch((imm8>>4)&3) {
|
||||
case 0b01: intres2 ^= ((1<<n_packed)-1); break;
|
||||
case 0b11: intres2 ^= ((1<<lmem)-1); break;
|
||||
}
|
||||
// and now set the flags
|
||||
RESET_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(intres2, F_CF);
|
||||
CONDITIONAL_SET_FLAG(lmem<n_packed, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(lreg<n_packed, F_SF);
|
||||
CONDITIONAL_SET_FLAG(intres2&1, F_OF);
|
||||
CONDITIONAL_SET_FLAG(((!intres2) && (lmem==n_packed)), F_AF);
|
||||
CLEAR_FLAG(F_PF);
|
||||
|
||||
return intres2;
|
||||
}
|
||||
|
||||
uint32_t sse42_compare_string_implicit_len(x86emu_t* emu, sse_regs_t* mem, sse_regs_t* reg, uint8_t imm8)
|
||||
{
|
||||
int lmem = 0;
|
||||
int lreg = 0;
|
||||
// get lmem and lreg
|
||||
if(imm8&1) {
|
||||
while(lmem<8 && mem->uw[lmem]) ++lmem;
|
||||
while(lreg<8 && reg->uw[lreg]) ++lreg;
|
||||
} else {
|
||||
while(lmem<16 && mem->ub[lmem]) ++lmem;
|
||||
while(lreg<16 && reg->ub[lreg]) ++lreg;
|
||||
}
|
||||
return sse42_compare_string_explicit_len(emu, mem, lmem, reg, lreg, imm8);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef __X86_CMPSTRINGS_H__
|
||||
#define __X86_CMPSTRINGS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "regs.h"
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
uint32_t sse42_compare_string_explicit_len(x86emu_t* emu, sse_regs_t* a, int la, sse_regs_t* b, int lb, uint8_t imm8);
|
||||
uint32_t sse42_compare_string_implicit_len(x86emu_t* emu, sse_regs_t* a, sse_regs_t* b, uint8_t imm8);
|
||||
|
||||
#endif //__X86_CMPSTRINGS_H__
|
||||
+23
-27
@@ -49,11 +49,6 @@ static uint32_t x86emu_parity_tab[8] =
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
uint32_t* GetParityTab()
|
||||
{
|
||||
return x86emu_parity_tab;
|
||||
}
|
||||
|
||||
static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
{
|
||||
emu->context = context;
|
||||
@@ -219,7 +214,7 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx));
|
||||
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
newemu->fpu_tags = emu->fpu_tags;
|
||||
newemu->cw = emu->cw;
|
||||
newemu->sw = emu->sw;
|
||||
newemu->top = emu->top;
|
||||
@@ -232,10 +227,6 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
// adapt R_ESP to new stack frame
|
||||
uintptr_t oldst = (uintptr_t)((emu->init_stack)?emu->init_stack:emu->context->stack);
|
||||
uintptr_t newst = (uintptr_t)((newemu->init_stack)?newemu->init_stack:newemu->context->stack);
|
||||
newemu->regs[_SP].dword[0] = emu->regs[_SP].dword[0] + (intptr_t)(newst - oldst);
|
||||
}
|
||||
|
||||
void CopyEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
@@ -252,7 +243,7 @@ void CopyEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
newemu->fpu_tags = emu->fpu_tags;
|
||||
newemu->cw = emu->cw;
|
||||
newemu->sw = emu->sw;
|
||||
newemu->top = emu->top;
|
||||
@@ -338,6 +329,7 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
{
|
||||
static char buff[800];
|
||||
static const char* regname[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
|
||||
static const char* segname[] = {"ES", "CS", "SS", "DS", "FS", "GS"};
|
||||
char tmp[80];
|
||||
buff[0] = '\0';
|
||||
if(trace_emm) {
|
||||
@@ -358,21 +350,27 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
}
|
||||
// start with FPU regs...
|
||||
if(emu->fpu_stack) {
|
||||
if(emu->fpu_stack<9)
|
||||
for (int i=0; i<emu->fpu_stack; i++) {
|
||||
//if(i==4) strcat(buff, "\n");
|
||||
sprintf(tmp, "ST%d=%f", i, emu->x87[(emu->top+i)&7].d);
|
||||
strcat(buff, tmp);
|
||||
int c = 10-strlen(tmp);
|
||||
if(c<1) c=1;
|
||||
while(c--) strcat(buff, " ");
|
||||
}
|
||||
else {
|
||||
sprintf(tmp, "Warning, incoherent fpu_stack=%d", emu->fpu_stack);
|
||||
int stack = emu->fpu_stack;
|
||||
if(stack>8) stack = 8;
|
||||
for (int i=0; i<stack; i++) {
|
||||
sprintf(tmp, "ST%d=%f", i, ST(i).d);
|
||||
strcat(buff, tmp);
|
||||
int c = 10-strlen(tmp);
|
||||
if(c<1) c=1;
|
||||
while(c--) strcat(buff, " ");
|
||||
if(i==3) strcat(buff, "\n");
|
||||
}
|
||||
sprintf(tmp, " C3210 = %d%d%d%d", emu->sw.f.F87_C3, emu->sw.f.F87_C2, emu->sw.f.F87_C1, emu->sw.f.F87_C0);
|
||||
strcat(buff, tmp);
|
||||
strcat(buff, "\n");
|
||||
}
|
||||
for (int i=0; i<6; ++i) {
|
||||
sprintf(tmp, "%s=0x%04x", segname[i], emu->segs[i]);
|
||||
strcat(buff, tmp);
|
||||
if(i!=_GS)
|
||||
strcat(buff, " ");
|
||||
}
|
||||
strcat(buff, "\n");
|
||||
for (int i=_AX; i<=_DI; ++i) {
|
||||
sprintf(tmp, "%s=%08x ", regname[i], emu->regs[i].dword[0]);
|
||||
strcat(buff, tmp);
|
||||
@@ -422,8 +420,6 @@ void UnimpOpcode(x86emu_t* emu)
|
||||
tid, (void*)emu->old_ip, Peek(emu, -1),
|
||||
Peek(emu, 0), Peek(emu, 1), Peek(emu, 2), Peek(emu, 3),
|
||||
Peek(emu, 4), Peek(emu, 5), Peek(emu, 6), Peek(emu, 7));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
}
|
||||
|
||||
void EmuCall(x86emu_t* emu, uintptr_t addr)
|
||||
@@ -440,9 +436,9 @@ void EmuCall(x86emu_t* emu, uintptr_t addr)
|
||||
Run(emu, 0);
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
if(emu->quitonlongjmp && emu->longjmp) {
|
||||
if(emu->quitonlongjmp==1)
|
||||
emu->longjmp = 0; // don't change anything because of the longjmp
|
||||
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
|
||||
if(emu->flags.quitonlongjmp==1)
|
||||
emu->flags.longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
R_EBX = old_ebx;
|
||||
R_EDI = old_edi;
|
||||
|
||||
@@ -34,11 +34,27 @@ typedef struct x86test_s {
|
||||
uint8_t mem[16];
|
||||
} x86test_t;
|
||||
|
||||
typedef struct emu_flags_s {
|
||||
uint32_t need_jmpbuf:1; // need a new jmpbuff for signal handling
|
||||
uint32_t quitonlongjmp:2; // quit if longjmp is called
|
||||
uint32_t quitonexit:2; // quit if exit/_exit is called
|
||||
uint32_t longjmp:1; // if quit because of longjmp
|
||||
uint32_t jmpbuf_ready:1; // the jmpbuf in the emu is ok and don't need refresh
|
||||
} emu_flags_t;
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <setjmp.h>
|
||||
#define JUMPBUFF sigjmp_buf
|
||||
#else
|
||||
#define JUMPBUFF struct __jmp_buf_tag
|
||||
#endif
|
||||
|
||||
typedef struct x86emu_s {
|
||||
// cpu
|
||||
reg32_t regs[8];
|
||||
x86flags_t eflags;
|
||||
reg32_t ip;
|
||||
uintptr_t xSPSave;
|
||||
// fpu / mmx
|
||||
x87control_t cw;
|
||||
x87flags_t sw;
|
||||
@@ -46,9 +62,9 @@ typedef struct x86emu_s {
|
||||
mmx87_regs_t mmx[8];
|
||||
uint32_t top; // top is part of sw, but it's faster to have it separatly
|
||||
int fpu_stack;
|
||||
uint32_t fpu_tags; // tags for the x87 regs, stacked, only on a 16bits anyway
|
||||
fpu_ld_t fpu_ld[8]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[8]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[8];
|
||||
// sse
|
||||
sse_regs_t xmm[8];
|
||||
mmxcontrol_t mxcsr;
|
||||
@@ -63,17 +79,17 @@ typedef struct x86emu_s {
|
||||
uintptr_t prev2_ip, prev_ip;
|
||||
#endif
|
||||
// segments
|
||||
uint32_t segs[6]; // only 32bits value?
|
||||
uint16_t segs[6];
|
||||
uint16_t dummy_seg6, dummy_seg7; // to stay aligned
|
||||
uintptr_t segs_offs[6]; // computed offset associate with segment
|
||||
uint32_t segs_serial[6]; // are seg offset clean (not 0) or does they need to be re-computed (0)? For GS, serial need to be the same as context->sel_serial
|
||||
// emu control
|
||||
int quit;
|
||||
int error;
|
||||
int fork; // quit because need to fork
|
||||
forkpty_t* forkpty_info;
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
forkpty_t* forkpty_info;
|
||||
emu_flags_t flags;
|
||||
x86test_t test; // used for dynarec testing
|
||||
// parent context
|
||||
box86context_t *context;
|
||||
@@ -86,6 +102,8 @@ typedef struct x86emu_s {
|
||||
void* stack2free; // this is the stack to free (can be NULL)
|
||||
void* init_stack; // initial stack (owned or not)
|
||||
uint32_t size_stack; // stack size (owned or not)
|
||||
JUMPBUFF* jmpbuf;
|
||||
uintptr_t old_savedsp;
|
||||
|
||||
i386_ucontext_t *uc_link; // to handle setcontext
|
||||
|
||||
|
||||
+18
-10
@@ -43,7 +43,9 @@ x86emu_t* x86emu_fork(x86emu_t* emu, int forktype)
|
||||
iFpppp_t forkpty = (iFpppp_t)emu->forkpty_info->f;
|
||||
v = forkpty(emu->forkpty_info->amaster, emu->forkpty_info->name, emu->forkpty_info->termp, emu->forkpty_info->winp);
|
||||
emu->forkpty_info = NULL;
|
||||
} else
|
||||
} else if(forktype==3)
|
||||
v = vfork();
|
||||
else
|
||||
v = fork();
|
||||
if(type == EMUTYPE_MAIN)
|
||||
thread_set_emu(emu);
|
||||
@@ -51,23 +53,19 @@ x86emu_t* x86emu_fork(x86emu_t* emu, int forktype)
|
||||
// error...
|
||||
} else if(v!=0) {
|
||||
// execute atforks parent functions
|
||||
for (int i=0; i<my_context->atfork_sz; --i)
|
||||
for (int i=0; i<my_context->atfork_sz; ++i)
|
||||
if(my_context->atforks[i].parent)
|
||||
EmuCall(emu, my_context->atforks[i].parent);
|
||||
if(forktype==3) {
|
||||
// vfork, the parent wait the end or execve of the son
|
||||
waitpid(v, NULL, WEXITED);
|
||||
}
|
||||
} else if(v==0) {
|
||||
// execute atforks child functions
|
||||
for (int i=0; i<my_context->atfork_sz; --i)
|
||||
for (int i=0; i<my_context->atfork_sz; ++i)
|
||||
if(my_context->atforks[i].child)
|
||||
EmuCall(emu, my_context->atforks[i].child);
|
||||
}
|
||||
R_EAX = v;
|
||||
return emu;
|
||||
}
|
||||
|
||||
void emit_signal(x86emu_t* emu, int sig, void* addr, int code); // in signals.c
|
||||
extern int errno;
|
||||
void x86Int3(x86emu_t* emu)
|
||||
{
|
||||
@@ -200,6 +198,8 @@ void x86Int3(x86emu_t* emu)
|
||||
perr = 3;
|
||||
} else if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "wcsncasecmp")==s) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%S\", \"%S\", %d)", tid, *(void**)(R_ESP), s, *(wchar_t**)(R_ESP+4), *(wchar_t**)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
} else if(strstr(s, "gtk_signal_connect_full")) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%p, \"%s\", %p, %p, %p, %p, %d, %d)", tid, *(void**)(R_ESP), "gtk_signal_connect_full", *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16), *(void**)(R_ESP+20), *(void**)(R_ESP+24), *(int32_t*)(R_ESP+28), *(int32_t*)(R_ESP+32));
|
||||
} else if(strstr(s, "strcmp")==s || strstr(s, "__strcmp")==s) {
|
||||
@@ -270,6 +270,8 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "glXGetProcAddress")==s) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if (!strcmp(s, "glTexImage2D")) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(0x%x, %d, 0x%x, %d, %d, %d, 0x%x, 0x%x, %p)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(int*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int*)(R_ESP+24), *(uint32_t*)(R_ESP+28), *(uint32_t*)(R_ESP+32), *(void**)(R_ESP+36));
|
||||
} else if(strstr(s, "sscanf")==s) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "vsscanf")) {
|
||||
@@ -300,6 +302,10 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(strstr(s, "__tls_get_addr")) {
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%p[%d, %d])", tid, *(void**)(R_ESP), s, pu32, pu32[0], pu32[1]);
|
||||
} else if (!strcmp(s, "FT_Outline_Get_CBox")) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%p, %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
post = 7;
|
||||
} else if (!strcmp(s, "XDrawImageString")) {
|
||||
snprintf(buff, 256, "%04d|%p: Calling %s(%p, %p, %p, %i, %i, %p\"%s\", %d)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), *(void**)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(char**)(R_ESP+24), *(char**)(R_ESP+24), *(int*)(R_ESP+28));
|
||||
} else {
|
||||
@@ -331,6 +337,8 @@ void x86Int3(x86emu_t* emu)
|
||||
break;
|
||||
case 6: snprintf(buff2, 63, "(%S)", pu32?((wchar_t*)pu32):L"nil");
|
||||
break;
|
||||
case 7: snprintf(buff2, 63, " [%d / %d / %d /%d]", pu32[0], pu32[1], pu32[2], pu32[3]);
|
||||
break;
|
||||
}
|
||||
if(perr==1 && ((int)R_EAX)<0)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
@@ -350,8 +358,8 @@ void x86Int3(x86emu_t* emu)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(0 && my_context->signals[SIGTRAP])
|
||||
raise(SIGTRAP);
|
||||
if(1 && my_context->signals[SIGTRAP])
|
||||
emit_signal(emu, SIGTRAP, (void*)R_EIP, 128);
|
||||
else
|
||||
printf_log(LOG_INFO, "%04d|Warning, ignoring unsupported Int 3 call @%p\n", GetTID(), (void*)R_EIP);
|
||||
//emu->quit = 1;
|
||||
|
||||
+19
-29
@@ -484,10 +484,8 @@ uint8_t rcl8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
/* OVERFLOW is set *IFF* cnt==1, then it is the
|
||||
xor of CF and the most significant bit. Blecck. */
|
||||
/* parenthesized this expression since it appears to
|
||||
be causing OF to be misset */
|
||||
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
|
||||
F_OF);
|
||||
if(cnt == 1)
|
||||
CONDITIONAL_SET_FLAG((cf ^ (res >> 7)) & 0x1, F_OF);
|
||||
|
||||
}
|
||||
return (uint8_t)res;
|
||||
@@ -513,8 +511,8 @@ uint16_t rcl16(x86emu_t *emu, uint16_t d, uint8_t s)
|
||||
res |= 1 << (cnt - 1);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
|
||||
F_OF);
|
||||
if(cnt == 1)
|
||||
CONDITIONAL_SET_FLAG((cf ^ (res >> 15)) & 0x1, F_OF);
|
||||
}
|
||||
return (uint16_t)res;
|
||||
}
|
||||
@@ -539,8 +537,8 @@ uint32_t rcl32(x86emu_t *emu, uint32_t d, uint8_t s)
|
||||
res |= 1 << (cnt - 1);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
|
||||
F_OF);
|
||||
if(cnt == 1)
|
||||
CONDITIONAL_SET_FLAG((cf ^ (res >> 31)) & 0x1, F_OF);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -592,6 +590,11 @@ uint8_t rcr8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
(i.e. packed bit array or unpacked.)
|
||||
*/
|
||||
ocf = ACCESS_FLAG(F_CF) != 0;
|
||||
/* OVERFLOW is set *IFF* cnt==1, then it is the
|
||||
xor of CF and the most significant bit. Blecck. */
|
||||
/* parenthesized... */
|
||||
CONDITIONAL_SET_FLAG((ocf ^ (d >> 7)) & 0x1,
|
||||
F_OF);
|
||||
} else
|
||||
cf = (d >> (cnt - 1)) & 0x1;
|
||||
|
||||
@@ -620,13 +623,6 @@ uint8_t rcr8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
}
|
||||
/* set the new carry flag, based on the variable "cf" */
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
/* OVERFLOW is set *IFF* cnt==1, then it is the
|
||||
xor of CF and the most significant bit. Blecck. */
|
||||
/* parenthesized... */
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
|
||||
F_OF);
|
||||
}
|
||||
}
|
||||
return (uint8_t)res;
|
||||
}
|
||||
@@ -648,6 +644,8 @@ uint16_t rcr16(x86emu_t *emu, uint16_t d, uint8_t s)
|
||||
if (cnt == 1) {
|
||||
cf = d & 0x1;
|
||||
ocf = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG((ocf ^ (d >> 15)) & 0x1,
|
||||
F_OF);
|
||||
} else
|
||||
cf = (d >> (cnt - 1)) & 0x1;
|
||||
mask = (1 << (16 - cnt)) - 1;
|
||||
@@ -657,10 +655,6 @@ uint16_t rcr16(x86emu_t *emu, uint16_t d, uint8_t s)
|
||||
res |= 1 << (16 - cnt);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
|
||||
F_OF);
|
||||
}
|
||||
}
|
||||
return (uint16_t)res;
|
||||
}
|
||||
@@ -682,6 +676,8 @@ uint32_t rcr32(x86emu_t *emu, uint32_t d, uint8_t s)
|
||||
if (cnt == 1) {
|
||||
cf = d & 0x1;
|
||||
ocf = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG((ocf ^ (d >> 31)) & 0x1,
|
||||
F_OF);
|
||||
} else
|
||||
cf = (d >> (cnt - 1)) & 0x1;
|
||||
mask = (1 << (32 - cnt)) - 1;
|
||||
@@ -692,10 +688,6 @@ uint32_t rcr32(x86emu_t *emu, uint32_t d, uint8_t s)
|
||||
res |= 1 << (32 - cnt);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
|
||||
F_OF);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -885,8 +877,7 @@ uint16_t shld16 (x86emu_t *emu, uint16_t d, uint16_t fill, uint8_t s)
|
||||
res = d;
|
||||
}
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
|
||||
(ACCESS_FLAG(F_CF) != 0)), F_OF);
|
||||
CONDITIONAL_SET_FLAG(((res ^ d) >> 15)&1, F_OF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
@@ -927,8 +918,7 @@ uint32_t shld32 (x86emu_t *emu, uint32_t d, uint32_t fill, uint8_t s)
|
||||
res = d;
|
||||
}
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
|
||||
(ACCESS_FLAG(F_CF) != 0)), F_OF);
|
||||
CONDITIONAL_SET_FLAG(((res ^ d) >> 31)&1, F_OF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
@@ -959,7 +949,7 @@ uint16_t shrd16 (x86emu_t *emu, uint16_t d, uint16_t fill, uint8_t s)
|
||||
}
|
||||
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(((res ^ d) >> 15)&1, F_OF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
@@ -1005,7 +995,7 @@ uint32_t shrd32 (x86emu_t *emu, uint32_t d, uint32_t fill, uint8_t s)
|
||||
res = d;
|
||||
}
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(((res ^ d) >> 31)&1, F_OF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
|
||||
+81
-30
@@ -61,6 +61,7 @@ int Run(x86emu_t *emu, int step)
|
||||
uintptr_t addr = R_EIP;
|
||||
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int unimp = 0;
|
||||
int tf_next = 0;
|
||||
|
||||
if(emu->quit)
|
||||
return 0;
|
||||
@@ -93,12 +94,14 @@ x86emurun:
|
||||
opcode = F8;
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
while((opcode==0xF2) || (opcode==0xF3) || (opcode==0x3E)) {
|
||||
switch (opcode) {
|
||||
case 0xF2: rep = 1; break;
|
||||
case 0xF3: rep = 2; break;
|
||||
case 0x3E: /* ignored*/ break;
|
||||
}
|
||||
opcode = F8;
|
||||
}
|
||||
while((opcode==0x3E)) //Branch Taken Hint ignored
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
@@ -428,7 +431,7 @@ x86emurun:
|
||||
case 0x6F: /* OUTSD */
|
||||
#ifndef TEST_INTERPRETER
|
||||
// this is a privilege opcode
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
STEP;
|
||||
#endif
|
||||
break;
|
||||
@@ -568,7 +571,7 @@ x86emurun:
|
||||
nextop = F8;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
GET_EB;
|
||||
if((nextop&0xC0)==0xC0) { // reg / reg: no lock
|
||||
if(MODREG) { // reg / reg: no lock
|
||||
tmp8u = GB;
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
@@ -594,7 +597,7 @@ x86emurun:
|
||||
nextop = F8;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
GET_ED;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
@@ -644,7 +647,7 @@ x86emurun:
|
||||
case 0x8C: /* MOV Ed, Seg */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
ED->dword[0] = emu->segs[((nextop&0x38)>>3)];
|
||||
else
|
||||
ED->word[0] = emu->segs[((nextop&0x38)>>3)];
|
||||
@@ -664,7 +667,7 @@ x86emurun:
|
||||
break;
|
||||
case 0x8F: /* POP Ed */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
emu->regs[(nextop&7)].dword[0] = Pop(emu);
|
||||
} else {
|
||||
tmp32u = Pop(emu); // this order allows handling POP [ESP] and variant
|
||||
@@ -702,17 +705,12 @@ x86emurun:
|
||||
Push(emu, emu->eflags.x32);
|
||||
break;
|
||||
case 0x9D: /* POPF */
|
||||
if(ACCESS_FLAG(F_TF) && !tf_next)
|
||||
--tf_next;
|
||||
emu->eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
RESET_FLAGS(emu);
|
||||
#ifndef TEST_INTERPRETER
|
||||
if(ACCESS_FLAG(F_TF)) {
|
||||
R_EIP = addr;
|
||||
emit_signal(emu, SIGTRAP, (void*)addr, 1);
|
||||
if(emu->quit) goto fini;
|
||||
CLEAR_FLAG(F_TF);
|
||||
STEP;
|
||||
}
|
||||
#endif
|
||||
if(ACCESS_FLAG(F_TF))
|
||||
++tf_next;
|
||||
break;
|
||||
case 0x9E: /* SAHF */
|
||||
tmp8u = emu->regs[_AX].byte[1];
|
||||
@@ -845,6 +843,7 @@ x86emurun:
|
||||
}
|
||||
if(R_ECX) cmp32(emu, tmp32u2, tmp32u3);
|
||||
R_ECX = tmp32u;
|
||||
break;
|
||||
case 2:
|
||||
tmp32u2 = 0;
|
||||
tmp32u3 = 0;
|
||||
@@ -860,6 +859,7 @@ x86emurun:
|
||||
}
|
||||
if(R_ECX) cmp32(emu, tmp32u2, tmp32u3);
|
||||
R_ECX = tmp32u;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xA8: /* TEST AL, Ib */
|
||||
@@ -1042,6 +1042,12 @@ x86emurun:
|
||||
break;
|
||||
case 0xC4: /* LES Gd,Ed */
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
UnimpOpcode(emu);
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
}
|
||||
GET_ED;
|
||||
emu->segs[_ES] = *(__uint16_t*)(((char*)ED)+4);
|
||||
emu->segs_serial[_ES] = 0;
|
||||
@@ -1049,6 +1055,12 @@ x86emurun:
|
||||
break;
|
||||
case 0xC5: /* LDS Gd,Ed */
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
UnimpOpcode(emu);
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
}
|
||||
GET_ED;
|
||||
emu->segs[_DS] = *(__uint16_t*)(((char*)ED)+4);
|
||||
emu->segs_serial[_DS] = 0;
|
||||
@@ -1083,7 +1095,15 @@ x86emurun:
|
||||
R_ESP = R_EBP;
|
||||
R_EBP = Pop(emu);
|
||||
break;
|
||||
|
||||
case 0xCA: /* FAR RETN */
|
||||
tmp16u = F16;
|
||||
addr = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu); // no check, no use....
|
||||
emu->segs_serial[_CS] = 0;
|
||||
R_ESP += tmp16u;
|
||||
// need to check status of CS register!
|
||||
STEP2;
|
||||
break;
|
||||
case 0xCB: /* FAR RET */
|
||||
addr = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu); // no check, no use....
|
||||
@@ -1116,7 +1136,7 @@ x86emurun:
|
||||
printf_log(LOG_DEBUG, "INT 2D called\n");
|
||||
} else {
|
||||
#ifndef TEST_INTERPRETER
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
#endif
|
||||
@@ -1126,8 +1146,9 @@ x86emurun:
|
||||
case 0xCE: /* INTO */
|
||||
emu->old_ip = R_EIP;
|
||||
#ifndef TEST_INTERPRETER
|
||||
emit_signal(emu, SIGFPE, (void*)R_EIP, FPE_INTOVF);
|
||||
if(emu->quit) goto fini;
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_OF))
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
STEP;
|
||||
#endif
|
||||
break;
|
||||
@@ -1339,7 +1360,7 @@ x86emurun:
|
||||
case 0xE7: /* OUT Ib, EAX */
|
||||
#ifndef TEST_INTERPRETER
|
||||
// this is a privilege opcode
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
STEP;
|
||||
#endif
|
||||
break;
|
||||
@@ -1347,6 +1368,7 @@ x86emurun:
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, addr);
|
||||
addr += tmp32s;
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
STEP2;
|
||||
break;
|
||||
case 0xE9: /* JMP Id */
|
||||
@@ -1367,7 +1389,7 @@ x86emurun:
|
||||
case 0xEF: /* OUT DX, EAX */
|
||||
#ifndef TEST_INTERPRETER
|
||||
// this is a privilege opcode
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
STEP;
|
||||
#endif
|
||||
break;
|
||||
@@ -1394,7 +1416,7 @@ x86emurun:
|
||||
case 0xF4: /* HLT */
|
||||
#ifndef TEST_INTERPRETER
|
||||
// this is a privilege opcode
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
STEP;
|
||||
#endif
|
||||
break;
|
||||
@@ -1425,9 +1447,13 @@ x86emurun:
|
||||
imul8(emu, EB->byte[0]);
|
||||
break;
|
||||
case 6: /* DIV Eb */
|
||||
if(!EB->byte[0])
|
||||
emit_div0(emu, (void*)R_EIP, 0);
|
||||
div8(emu, EB->byte[0]);
|
||||
break;
|
||||
case 7: /* IDIV Eb */
|
||||
if(!EB->byte[0])
|
||||
emit_div0(emu, (void*)R_EIP, 0);
|
||||
idiv8(emu, EB->byte[0]);
|
||||
break;
|
||||
}
|
||||
@@ -1454,9 +1480,13 @@ x86emurun:
|
||||
imul32_eax(emu, ED->dword[0]);
|
||||
break;
|
||||
case 6: /* DIV Ed */
|
||||
if(!ED->dword[0])
|
||||
emit_div0(emu, (void*)R_EIP, 0);
|
||||
div32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 7: /* IDIV Ed */
|
||||
if(!ED->dword[0])
|
||||
emit_div0(emu, (void*)R_EIP, 0);
|
||||
idiv32(emu, ED->dword[0]);
|
||||
break;
|
||||
}
|
||||
@@ -1474,7 +1504,7 @@ x86emurun:
|
||||
case 0xFB: /* STI */
|
||||
#ifndef TEST_INTERPRETER
|
||||
// this is a privilege opcode
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 128);
|
||||
STEP;
|
||||
#endif
|
||||
break;
|
||||
@@ -1530,7 +1560,7 @@ x86emurun:
|
||||
GET_ED_;
|
||||
Push(emu, R_CS);
|
||||
Push(emu, addr);
|
||||
addr = ED->dword[0];
|
||||
addr = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
R_CS = (ED+1)->word[0];
|
||||
goto fini; // in case there is a change of CS
|
||||
}
|
||||
@@ -1550,7 +1580,7 @@ x86emurun:
|
||||
goto fini;
|
||||
} else {
|
||||
GET_ED_;
|
||||
addr = ED->dword[0];
|
||||
addr = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
R_CS = (ED+1)->word[0];
|
||||
STEP2;
|
||||
}
|
||||
@@ -1574,15 +1604,36 @@ x86emurun:
|
||||
unimp = 1;
|
||||
goto fini;
|
||||
}
|
||||
#ifndef TEST_INTERPRETER
|
||||
if(ACCESS_FLAG(F_TF)) {
|
||||
if(tf_next) {
|
||||
tf_next = 0;
|
||||
} else {
|
||||
R_EIP = addr;
|
||||
emit_signal(emu, SIGTRAP, (void*)addr, 1);
|
||||
if(emu->quit) goto fini;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
R_EIP = addr;
|
||||
}
|
||||
|
||||
fini:
|
||||
#ifndef TEST_INTERPRETER
|
||||
// check the TRACE flag before going to out, in case it's a step by step scenario
|
||||
if(!emu->quit && !emu->fork && !emu->uc_link && ACCESS_FLAG(F_TF)) {
|
||||
R_EIP = addr;
|
||||
emit_signal(emu, SIGTRAP, (void*)addr, 1);
|
||||
if(emu->quit) goto fini;
|
||||
}
|
||||
#endif
|
||||
#ifndef TEST_INTERPRETER
|
||||
printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_EIP, (void*)R_ESP, unimp, emu->fork, emu->uc_link, emu->quit);
|
||||
if(unimp) {
|
||||
emu->quit = 1;
|
||||
UnimpOpcode(emu);
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
}
|
||||
// fork handling
|
||||
if(emu->fork) {
|
||||
@@ -1596,7 +1647,7 @@ fini:
|
||||
goto x86emurun;
|
||||
}
|
||||
// setcontext handling
|
||||
else if(emu->uc_link) {
|
||||
else if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
addr = R_EIP;
|
||||
|
||||
+58
-26
@@ -53,6 +53,10 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t *emu = test->emu;
|
||||
#endif
|
||||
#ifdef TERMUX
|
||||
extern int isinff(float);
|
||||
extern int isnanf(float);
|
||||
#endif
|
||||
opcode = F8;
|
||||
|
||||
@@ -64,13 +68,13 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
case 0: /* SLDT Ew */
|
||||
GET_EW;
|
||||
EW->word[0] = 0;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
EW->word[1] = 0;
|
||||
break;
|
||||
case 1: /* STR Ew */
|
||||
GET_EW;
|
||||
EW->word[0] = 0x7f; // dummy return
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
EW->word[1] = 0;
|
||||
break;
|
||||
case 4: //VERR
|
||||
@@ -85,28 +89,47 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x01: /* XGETBV, SGDT, etc... */
|
||||
// this is a privilege opcode...
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* SGDT Ed */
|
||||
GET_ED;
|
||||
ED->word[0] = 0x7f; // dummy return...
|
||||
ED->word[1] = 0x000c;
|
||||
ED->word[2] = 0xd000;
|
||||
GET_ED;
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
#ifndef TEST_INTERPRETER
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* SIDT Ed */
|
||||
GET_ED;
|
||||
ED->word[0] = 0xfff; // dummy return, like "disabled"
|
||||
ED->word[1] = 0;
|
||||
ED->word[2] = 0;
|
||||
break;
|
||||
case 4: /* SMSW Ew */
|
||||
GET_ED;
|
||||
// dummy for now... Do I need to track CR0 state?
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7: /* SMSW Ew */
|
||||
ED->word[0] = (1<<0) | (1<<4); // only PE and ET set...
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* SGDT Ed */
|
||||
ED->word[0] = 0x7f; // dummy return...
|
||||
ED->word[1] = 0x000c;
|
||||
ED->word[2] = 0xd000;
|
||||
break;
|
||||
case 1: /* SIDT Ed */
|
||||
ED->word[0] = 0xfff; // dummy return, like "disabled"
|
||||
ED->word[1] = 0;
|
||||
ED->word[2] = 0;
|
||||
break;
|
||||
case 4: /* SMSW Ew */
|
||||
// dummy for now... Do I need to track CR0 state?
|
||||
ED->word[0] = (1<<0) | (1<<4); // only PE and ET set...
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -145,7 +168,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if((nextop&0xC0)==0xC0) /* MOVHLPS Gx,Ex */
|
||||
if(MODREG) /* MOVHLPS Gx,Ex */
|
||||
GX.q[0] = EX->q[1];
|
||||
else
|
||||
GX.q[0] = EX->q[0]; /* MOVLPS Gx,Ex */
|
||||
@@ -183,7 +206,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
case 0x18: /* PREFETCHh Ed */
|
||||
nextop = F8;
|
||||
GET_ED_;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //PREFETCHnta
|
||||
@@ -206,6 +229,15 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
nextop = F8;
|
||||
GET_ED_;
|
||||
break;
|
||||
case 0x20: /* MOV REG, crX */
|
||||
case 0x21: /* MOV REG, drX */
|
||||
case 0x22: /* MOV cxR, REG */
|
||||
case 0x23: /* MOV drX, REG */
|
||||
// this is a privilege opcode...
|
||||
#ifndef TEST_INTERPRETER
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x28: /* MOVAPS Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -238,7 +270,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
GM.sd[1] = 0x80000000;
|
||||
else
|
||||
GM.sd[1] = EX->f[1];
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>=(float)0x80000000U || EX->f[1]<-(float)0x80000000U)
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>=(float)0x80000000U || EX->f[0]<-(float)0x80000000U)
|
||||
GM.sd[0] = 0x80000000;
|
||||
else
|
||||
GM.sd[0] = EX->f[0];
|
||||
@@ -1205,7 +1237,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
CLEAR_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
break;
|
||||
case 0xBC: /* BSF Ed,Gd */
|
||||
case 0xBC: /* BSF Gd, Ed */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
@@ -1219,7 +1251,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
SET_FLAG(F_ZF);
|
||||
}
|
||||
break;
|
||||
case 0xBD: /* BSR Ed,Gd */
|
||||
case 0xBD: /* BSR Gd, Ed */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
@@ -1384,7 +1416,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
|
||||
case 0xD7: /* PMOVMSKB Gd,Em */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GET_EM;
|
||||
GD.dword[0] = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
@@ -1500,7 +1532,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
|
||||
case 0xE7: /* MOVNTQ Em,Gm */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
return 0;
|
||||
GET_EM;
|
||||
EM->q = GM.q;
|
||||
@@ -1613,7 +1645,7 @@ uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
break;
|
||||
case 0xF7: /* MASKMOVQ Gm, Em */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GET_EM;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(EM->ub[i]&0x80) ((uint8_t*)(R_EDI))[i] = GM.ub[i];
|
||||
|
||||
+60
-9
@@ -12,6 +12,7 @@
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
@@ -75,7 +76,12 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
GD.dword[0] = adc32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x21: /* AND Ed,Gd */
|
||||
case 0x20: /* AND Seg:Eb,Gb */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
EB->byte[0] = and8(emu, EB->byte[0], GB);
|
||||
break;
|
||||
case 0x21: /* AND Seg:Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = and32(emu, ED->dword[0], GD.dword[0]);
|
||||
@@ -165,13 +171,18 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
return addr-1;
|
||||
|
||||
case 0x64: /* FS: */
|
||||
// so just ignore that GS: prefix then
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test64(test, _FS, addr-1); // put FS back
|
||||
#else
|
||||
return Run64(emu, _FS, addr-1); // put FS back
|
||||
#endif
|
||||
|
||||
case 0x65: /* GS: */
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test64(test, _GS, addr);
|
||||
#else
|
||||
return Run64(emu, _GS, addr);
|
||||
#endif
|
||||
break;
|
||||
case 0x66:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test6466(test, tlsdata, addr);
|
||||
@@ -250,7 +261,7 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
nextop = F8;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
GET_ED_OFFS(tlsdata);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
@@ -268,16 +279,20 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
}
|
||||
#else
|
||||
GET_ED_OFFS(tlsdata);
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
if(!MODREG)
|
||||
pthread_mutex_lock(&emu->context->mutex_lock); // XCHG always LOCK (but when accessing memory only)
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
if(!MODREG)
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x88: /* MOV Seg:Eb,Gb */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
EB->byte[0] = GB;
|
||||
break;
|
||||
case 0x89: /* MOV Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
@@ -309,6 +324,8 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = Pop(emu);
|
||||
break;
|
||||
case 0x90: /* NOP */
|
||||
break;
|
||||
|
||||
case 0x9C: /* PUSHFD */
|
||||
// Segment override if for memory loc, no stack segment
|
||||
@@ -400,6 +417,40 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
return addr-1; // ignore FS: to execute regular opcode
|
||||
break;
|
||||
|
||||
case 0xF7: /* GRP3 Ed(,Id) */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1: /* TEST Ed,Id */
|
||||
tmp32u = F32;
|
||||
test32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
case 2: /* NOT Ed */
|
||||
ED->dword[0] = not32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 3: /* NEG Ed */
|
||||
ED->dword[0] = neg32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 4: /* MUL EAX,Ed */
|
||||
mul32_eax(emu, ED->dword[0]);
|
||||
break;
|
||||
case 5: /* IMUL EAX,Ed */
|
||||
imul32_eax(emu, ED->dword[0]);
|
||||
break;
|
||||
case 6: /* DIV Ed */
|
||||
if(!ED->dword[0])
|
||||
emit_div0(emu, (void*)R_EIP, 0);
|
||||
div32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 7: /* IDIV Ed */
|
||||
if(!ED->dword[0])
|
||||
emit_div0(emu, (void*)R_EIP, 0);
|
||||
idiv32(emu, ED->dword[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
@@ -424,7 +475,7 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
} else {
|
||||
Push16(emu, R_CS);
|
||||
Push(emu, addr);
|
||||
addr = ED->dword[0];
|
||||
addr = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
@@ -438,7 +489,7 @@ uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
} else {
|
||||
addr = ED->dword[0];
|
||||
addr = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -48,6 +48,12 @@ uintptr_t Run6466(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr)
|
||||
GW.word[0] = EW->word[0];
|
||||
break;
|
||||
|
||||
case 0x8D: /* LEA Gw,M */
|
||||
nextop = F8;
|
||||
GET_ED_; // segment doesn't enter in the computation
|
||||
GW.word[0] = (uint16_t)(uint32_t)ED;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+21
-7
@@ -99,11 +99,21 @@ uintptr_t Run66(x86emu_t *emu, int rep, uintptr_t addr)
|
||||
break;
|
||||
|
||||
case 0x0F: /* 66 0f prefix */
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test660F(test, addr);
|
||||
#else
|
||||
return Run660F(emu, addr);
|
||||
#endif
|
||||
switch(rep) {
|
||||
case 2: return 0;
|
||||
case 1:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test66F20F(test, addr);
|
||||
#else
|
||||
return Run66F20F(emu, addr);
|
||||
#endif
|
||||
default:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test660F(test, addr);
|
||||
#else
|
||||
return Run660F(emu, addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
case 0x1E: /* PUSH DS */
|
||||
Push16(emu, emu->segs[_DS]);
|
||||
@@ -274,7 +284,11 @@ uintptr_t Run66(x86emu_t *emu, int rep, uintptr_t addr)
|
||||
GET_EW;
|
||||
EW->word[0] = emu->segs[(nextop&0x38)>>3];
|
||||
break;
|
||||
|
||||
case 0x8D: /* LEA Gw,M */
|
||||
nextop = F8;
|
||||
GET_ED_;
|
||||
GW.word[0] = (uint16_t)(uint32_t)ED;
|
||||
break;
|
||||
case 0x8E: /* MOV Seg,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
@@ -574,4 +588,4 @@ uintptr_t Run66(x86emu_t *emu, int rep, uintptr_t addr)
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
+477
-7
@@ -15,6 +15,28 @@
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
#include "x86compstrings.h"
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if((b & 1) == 1)
|
||||
retval ^= a;
|
||||
|
||||
if((a & 0x80)) {
|
||||
a <<= 1;
|
||||
a ^= 0x1b;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test660F(x86test_t *test, uintptr_t addr)
|
||||
@@ -33,14 +55,63 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
int32_t tmp32s;
|
||||
sse_regs_t *opex, eax1, *opx2;
|
||||
mmx87_regs_t *opem;
|
||||
float tmpf;
|
||||
double tmpd;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
#endif
|
||||
// AES opcodes constants
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A F K P E J O D I N C H M B G L
|
||||
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
const uint8_t subbytes[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
};
|
||||
// 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,
|
||||
};
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
#ifdef TERMUX
|
||||
extern int isinff(float);
|
||||
extern int isnanf(float);
|
||||
#endif
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
@@ -403,6 +474,15 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* PBLENDVB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(emu->xmm[0].ub[i]&0x80)
|
||||
GX.ub[i] = EX->ub[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x14: /* BLENDVPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -411,6 +491,14 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
GX.ud[i] = EX->ud[i];
|
||||
}
|
||||
break;
|
||||
case 0x15: /* BLENDVPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<2; ++i) {
|
||||
if(emu->xmm[0].q[i]&0x8000000000000000LL)
|
||||
GX.q[i] = EX->q[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x17: // PTEST GX, EX
|
||||
nextop = F8;
|
||||
@@ -418,6 +506,10 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!((GX.q[0]&EX->q[0])|(GX.q[1]&EX->q[1])), F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!(((~GX.q[0])&EX->q[0])|((~GX.q[1])&EX->q[1])), F_CF);
|
||||
CLEAR_FLAG(F_AF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
CLEAR_FLAG(F_SF);
|
||||
CLEAR_FLAG(F_PF);
|
||||
break;
|
||||
|
||||
case 0x1C: /* PABSB Gx, Ex */
|
||||
@@ -479,6 +571,36 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
GX.sq[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x28: /* PMULDQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.sq[1] = ((int64_t)GX.sd[2])*(int64_t)EX->sd[2];
|
||||
GX.sq[0] = ((int64_t)GX.sd[0])*(int64_t)EX->sd[0];
|
||||
break;
|
||||
case 0x29: /* PCMPEQQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = (GX.sq[i]==EX->sq[i])?-1LL:0LL;
|
||||
break;
|
||||
case 0x2A: /* MOVNTDQA Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.q[0] = EX->q[0];
|
||||
GX.q[1] = EX->q[1];
|
||||
break;
|
||||
case 0x2B: /* PACKUSDW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.uw[i] = (GX.sd[i]<0)?0:((GX.sd[i]>65535)?65535:GX.sd[i]);
|
||||
if(&GX==EX)
|
||||
GX.q[1] = GX.q[0];
|
||||
else
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.uw[i+4] = (EX->sd[i]<0)?0:((EX->sd[i]>65535)?65535:EX->sd[i]);
|
||||
break;
|
||||
|
||||
case 0x30: /* PMOVZXBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -516,6 +638,19 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
GX.q[i] = EX->ud[i];
|
||||
break;
|
||||
|
||||
case 0x37: /* PCMPGTQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = (GX.sq[i]>EX->sq[i])?-1LL:0LL;
|
||||
break;
|
||||
case 0x38: /* PMINSB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(GX.sb[i]>EX->sb[i])
|
||||
GX.sb[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x39: /* PMINSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -523,7 +658,27 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
if(GX.sd[i]>EX->sd[i])
|
||||
GX.sd[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x3A: /* PMINUW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(GX.uw[i]>EX->uw[i])
|
||||
GX.uw[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x3B: /* PMINUD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX.ud[i]>EX->ud[i])
|
||||
GX.ud[i] = EX->ud[i];
|
||||
break;
|
||||
case 0x3C: /* PMAXSB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(GX.sb[i]<EX->sb[i])
|
||||
GX.sb[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x3D: /* PMAXSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -531,7 +686,20 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
if(GX.sd[i]<EX->sd[i])
|
||||
GX.sd[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x3E: /* PMAXUW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(GX.uw[i]<EX->uw[i])
|
||||
GX.uw[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x3F: /* PMAXUD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX.ud[i]<EX->ud[i])
|
||||
GX.ud[i] = EX->ud[i];
|
||||
break;
|
||||
case 0x40: /* PMULLD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -539,13 +707,136 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
GX.sd[i] *= EX->sd[i];
|
||||
}
|
||||
break;
|
||||
case 0x41: /* PHMINPOSUW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp16u = EX->uw[0];
|
||||
tmp16s = 0;
|
||||
for(int i=1; i<8; ++i) {
|
||||
if(EX->uw[i]<tmp16u) {
|
||||
tmp16u = EX->uw[i];
|
||||
tmp16s = i;
|
||||
}
|
||||
}
|
||||
GX.q[1] = 0;
|
||||
GX.uw[0] = tmp16u;
|
||||
GX.uw[1] = tmp16s;
|
||||
GX.ud[1] = 0;
|
||||
break;
|
||||
|
||||
case 0xDB: /* AESIMC Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
//STATE ← InvMixColumns( STATE );
|
||||
if (EX == &GX) {
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = EX->ub[i];
|
||||
for(int j=0; j<4; ++j) {
|
||||
GX.ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
GX.ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
GX.ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
GX.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]);
|
||||
}
|
||||
} else {
|
||||
for(int j=0; j<4; ++j) {
|
||||
GX.ub[0+j*4] = ff_mult(0x0E, EX->ub[0+j*4]) ^ ff_mult(0x0B, EX->ub[1+j*4]) ^ ff_mult(0x0D, EX->ub[2+j*4]) ^ ff_mult(0x09, EX->ub[3+j*4]);
|
||||
GX.ub[1+j*4] = ff_mult(0x09, EX->ub[0+j*4]) ^ ff_mult(0x0E, EX->ub[1+j*4]) ^ ff_mult(0x0B, EX->ub[2+j*4]) ^ ff_mult(0x0D, EX->ub[3+j*4]);
|
||||
GX.ub[2+j*4] = ff_mult(0x0D, EX->ub[0+j*4]) ^ ff_mult(0x09, EX->ub[1+j*4]) ^ ff_mult(0x0E, EX->ub[2+j*4]) ^ ff_mult(0x0B, EX->ub[3+j*4]);
|
||||
GX.ub[3+j*4] = ff_mult(0x0B, EX->ub[0+j*4]) ^ ff_mult(0x0D, EX->ub[1+j*4]) ^ ff_mult(0x09, EX->ub[2+j*4]) ^ ff_mult(0x0E, EX->ub[3+j*4]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xDC: /* AESENC Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
//STATE ← SRC1;
|
||||
//RoundKey ← SRC2;
|
||||
//STATE ← ShiftRows( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = GX.ub[shiftrows[i]];
|
||||
//STATE ← SubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = subbytes[eax1.ub[i]];
|
||||
//STATE ← MixColumns( STATE );
|
||||
for(int j=0; j<4; ++j) {
|
||||
GX.ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
GX.ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
GX.ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
GX.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]);
|
||||
}
|
||||
//DEST[127:0] ← STATE XOR RoundKey;
|
||||
GX.q[0] ^= EX->q[0];
|
||||
GX.q[1] ^= EX->q[1];
|
||||
break;
|
||||
case 0xDD: /* AESENCLAST Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
//STATE ← SRC1;
|
||||
//RoundKey ← SRC2;
|
||||
//STATE ← ShiftRows( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = GX.ub[shiftrows[i]];
|
||||
//STATE ← SubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
GX.ub[i] = subbytes[eax1.ub[i]];
|
||||
//DEST[127:0] ← STATE XOR RoundKey;
|
||||
GX.q[0] ^= EX->q[0];
|
||||
GX.q[1] ^= EX->q[1];
|
||||
break;
|
||||
case 0xDE: /* AESDEC Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
//STATE ← SRC1;
|
||||
//RoundKey ← SRC2;
|
||||
//STATE ← InvShiftRows( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = GX.ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = invsubbytes[eax1.ub[i]];
|
||||
//STATE ← InvMixColumns( STATE );
|
||||
for(int j=0; j<4; ++j) {
|
||||
GX.ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
GX.ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
GX.ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
GX.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]);
|
||||
}
|
||||
//DEST[127:0] ← STATE XOR RoundKey;
|
||||
GX.q[0] ^= EX->q[0];
|
||||
GX.q[1] ^= EX->q[1];
|
||||
break;
|
||||
case 0xDF: /* AESDECLAST Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
//STATE ← SRC1;
|
||||
//RoundKey ← SRC2;
|
||||
//STATE ← InvShiftRows( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
eax1.ub[i] = GX.ub[invshiftrows[i]];
|
||||
//STATE ← InvSubBytes( STATE );
|
||||
for(int i=0; i<16; ++i)
|
||||
GX.ub[i] = invsubbytes[eax1.ub[i]];
|
||||
//DEST[127:0] ← STATE XOR RoundKey;
|
||||
GX.q[0] ^= EX->q[0];
|
||||
GX.q[1] ^= EX->q[1];
|
||||
break;
|
||||
|
||||
case 0xF0: /* MOVBE Gw, Ew */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GD.word[0] = __builtin_bswap16(ED->word[0]);
|
||||
break;
|
||||
case 0xF1: /* MOVBE Ew, Gw */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
ED->word[0] = __builtin_bswap16(GD.word[0]);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3A: // these are some SSE3 opcodes
|
||||
case 0x3A: // these are some SSE3 & SSE4.x opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x08: // roundps GX, EX, u8
|
||||
@@ -644,7 +935,24 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0C: /* PBLENDPS Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
for (int i=0; i<4; ++i) {
|
||||
if(tmp8u&(1<<i))
|
||||
GX.ud[i] = EX->ud[i];
|
||||
}
|
||||
break;
|
||||
case 0x0D: /* PBLENDPD Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
for (int i=0; i<2; ++i) {
|
||||
if(tmp8u&(1<<i))
|
||||
GX.q[i] = EX->q[i];
|
||||
}
|
||||
break;
|
||||
case 0x0E: /* PBLENDW Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -669,12 +977,36 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x14: // PEXTRB ED, GX, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if(MODREG)
|
||||
ED->dword[0] = GX.ub[tmp8u&0x0f];
|
||||
else
|
||||
ED->byte[0] = GX.ub[tmp8u&0x0f];
|
||||
break;
|
||||
case 0x15: // PEXTRW Ew,Gx,Ib
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if(MODREG)
|
||||
ED->dword[0] = GX.uw[tmp8u&7]; // 16bits extract, 0 extended
|
||||
else
|
||||
ED->word[0] = GX.uw[tmp8u&7];
|
||||
break;
|
||||
case 0x16: // PEXTRD ED, GX, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
ED->dword[0] = GX.ud[tmp8u&3];
|
||||
break;
|
||||
case 0x17: // EXTRACTPS ED, GX, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
ED->dword[0] = GX.ud[tmp8u&3];
|
||||
break;
|
||||
|
||||
case 0x20: // PINSRB GX, Ed, Ib
|
||||
nextop = F8;
|
||||
@@ -686,7 +1018,7 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)==0xC0) tmp8s = (tmp8u>>6)&3; else tmp8s = 0;
|
||||
if(MODREG) tmp8s = (tmp8u>>6)&3; else tmp8s = 0;
|
||||
GX.ud[(tmp8u>>4)&3] = EX->ud[tmp8s];
|
||||
for(int i=0; i<4; ++i)
|
||||
if(tmp8u&(1<<i))
|
||||
@@ -699,6 +1031,144 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
GX.ud[tmp8u&0x3] = ED->dword[0];
|
||||
break;
|
||||
|
||||
case 0x40: /* DPPS Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
tmpf = 0.0f;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(tmp8u&(1<<(i+4)))
|
||||
tmpf += GX.f[i]*EX->f[i];
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.f[i] = (tmp8u&(1<<i))?tmpf:0.0f;
|
||||
break;
|
||||
case 0x41: /* DPPD Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
tmpd = 0.0;
|
||||
if(tmp8u&(1<<(4+0)))
|
||||
tmpd += GX.d[0]*EX->d[0];
|
||||
if(tmp8u&(1<<(4+1)))
|
||||
tmpd += GX.d[1]*EX->d[1];
|
||||
GX.d[0] = (tmp8u&(1<<(0)))?tmpd:0.0;
|
||||
GX.d[1] = (tmp8u&(1<<(1)))?tmpd:0.0;
|
||||
break;
|
||||
case 0x42: /* MPSADBW Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
{
|
||||
int src = tmp8u&3;
|
||||
int dst = (tmp8u>>2)&1;
|
||||
int b[11];
|
||||
for (int i=0; i<11; ++i)
|
||||
b[i] = GX.ub[dst*4+i];
|
||||
for(int i=0; i<8; ++i) {
|
||||
int tmp = abs(b[i+0]-EX->ub[src*4+0]);
|
||||
tmp += abs(b[i+1]-EX->ub[src*4+1]);
|
||||
tmp += abs(b[i+2]-EX->ub[src*4+2]);
|
||||
tmp += abs(b[i+3]-EX->ub[src*4+3]);
|
||||
GX.uw[i] = tmp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x44: /* PCLMULQDQ Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
{
|
||||
int g = (tmp8u&1)?1:0;
|
||||
int e = (tmp8u&0b10000)?1:0;
|
||||
uint64_t result[2] = { 0 };
|
||||
for (int i=0; i<64; ++i)
|
||||
if(GX.q[g]&(1LL<<i)) {
|
||||
result[0] ^= (EX->q[e]<<i);
|
||||
if(i)
|
||||
result[1] ^= (EX->q[e]>>(64-i));
|
||||
}
|
||||
|
||||
GX.q[0] = result[0];
|
||||
GX.q[1] = result[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x60: /* PCMPESTRM */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
tmp32u = sse42_compare_string_explicit_len(emu, EX, R_EDX, &GX, R_EAX, tmp8u);
|
||||
if(tmp8u&0b1000000) {
|
||||
switch(tmp8u&1) {
|
||||
case 0: for(int i=0; i<16; ++i) emu->xmm[0].ub[i] = ((tmp32u>>i)&1)?0xff:0x00; break;
|
||||
case 1: for(int i=0; i<8; ++i) emu->xmm[0].uw[i] = ((tmp32u>>i)&1)?0xffff:0x0000; break;
|
||||
}
|
||||
} else {
|
||||
emu->xmm[0].q[1] = emu->xmm[0].q[0] = 0;
|
||||
emu->xmm[0].uw[0] = tmp32u;
|
||||
}
|
||||
break;
|
||||
case 0x61: /* PCMPESTRI */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
tmp32u = sse42_compare_string_explicit_len(emu, EX, R_EDX, &GX, R_EAX, tmp8u);
|
||||
if(!tmp32u)
|
||||
R_ECX = (tmp8u&1)?8:16;
|
||||
else if(tmp8u&0b1000000)
|
||||
R_ECX = 31-__builtin_clz(tmp32u);
|
||||
else
|
||||
R_ECX = __builtin_ffs(tmp32u) - 1;
|
||||
break;
|
||||
case 0x62: /* PCMPISTRM */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
tmp32u = sse42_compare_string_implicit_len(emu, EX, &GX, tmp8u);
|
||||
if(tmp8u&0b1000000) {
|
||||
switch(tmp8u&1) {
|
||||
case 0: for(int i=0; i<16; ++i) emu->xmm[0].ub[i] = ((tmp32u>>i)&1)?0xff:0x00; break;
|
||||
case 1: for(int i=0; i<8; ++i) emu->xmm[0].uw[i] = ((tmp32u>>i)&1)?0xffff:0x0000; break;
|
||||
}
|
||||
} else {
|
||||
emu->xmm[0].q[1] = emu->xmm[0].q[0] = 0;
|
||||
emu->xmm[0].uw[0] = tmp32u;
|
||||
}
|
||||
break;
|
||||
case 0x63: /* PCMPISTRI */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
tmp32u = sse42_compare_string_implicit_len(emu, EX, &GX, tmp8u);
|
||||
if(!tmp32u)
|
||||
R_ECX = (tmp8u&1)?8:16;
|
||||
else if(tmp8u&0b1000000)
|
||||
R_ECX = 31-__builtin_clz(tmp32u);
|
||||
else
|
||||
R_ECX = __builtin_ffs(tmp32u) - 1;
|
||||
break;
|
||||
|
||||
case 0xDF: // AESKEYGENASSIST Gx, Ex, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp32u = F8;
|
||||
for (int i = 4; i < 8; ++i)
|
||||
GX.ub[i] = subbytes[EX->ub[i]];
|
||||
for (int i = 12; i < 16; ++i)
|
||||
GX.ub[i] = subbytes[EX->ub[i]];
|
||||
GX.ud[0] = GX.ud[1];
|
||||
tmp8u = GX.ub[4];
|
||||
GX.ud[1] = GX.ud[1] >> 8;
|
||||
GX.ub[7] = tmp8u;
|
||||
GX.ud[1] ^= tmp32u;
|
||||
GX.ud[2] = GX.ud[3];
|
||||
tmp8u = GX.ub[12];
|
||||
GX.ud[3] = GX.ud[3] >> 8;
|
||||
GX.ub[15] = tmp8u;
|
||||
GX.ud[3] ^= tmp32u;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1520,12 +1990,12 @@ uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
EX->q[0] = GX.q[0];
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
EX->q[1] = 0;
|
||||
break;
|
||||
case 0xD7: /* PMOVMSKB Gd,Ex */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GET_EX;
|
||||
GD.dword[0] = 0;
|
||||
for (int i=0; i<16; ++i)
|
||||
|
||||
@@ -29,8 +29,8 @@ uintptr_t Run66D9(x86emu_t *emu, uintptr_t addr)
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
|
||||
@@ -29,8 +29,8 @@ uintptr_t Run66DD(x86emu_t *emu, uintptr_t addr)
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
#include "x86compstrings.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test66F20F(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run66F20F(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
sse_regs_t *opex, eax1, *opx2;
|
||||
mmx87_regs_t *opem;
|
||||
float tmpf;
|
||||
double tmpd;
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x38: // SSE 4.x
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF1: // CRC32 Gd, Ew
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
for(int j=0; j<2; ++j) {
|
||||
GD.dword[0] ^= EW->byte[j];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (GD.dword[0] & 1)
|
||||
GD.dword[0] = (GD.dword[0] >> 1) ^ 0x82f63b78;
|
||||
else
|
||||
GD.dword[0] = (GD.dword[0] >> 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "x86trace.h"
|
||||
#endif
|
||||
#include "x86tls.h"
|
||||
#include "x86emu.h"
|
||||
|
||||
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
||||
@@ -48,7 +49,7 @@ void EXPORT my___libc_init(x86emu_t* emu, void* raw_args __unused, void (*onexit
|
||||
emu->quit = 1; // finished!
|
||||
}
|
||||
#else
|
||||
int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
|
||||
int32_t EXPORT my___libc_start_main(x86emu_t* emu, int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
|
||||
{
|
||||
(void)argc; (void)ubp_av; (void)fini; (void)rtld_fini; (void)stack_end;
|
||||
// let's cheat and set all args...
|
||||
@@ -58,11 +59,16 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
if(init) {
|
||||
PushExit(emu);
|
||||
R_EIP=(uint32_t)*init;
|
||||
printf_log(LOG_DEBUG, "Calling init(%p) from __libc_start_main\n", *init);
|
||||
printf_dump(LOG_DEBUG, "Calling init(%p) from __libc_start_main\n", *init);
|
||||
DynaRun(emu);
|
||||
if(emu->error) // any error, don't bother with more
|
||||
return 0;
|
||||
emu->quit = 0;
|
||||
} else {
|
||||
if(my_context->elfs[0]) {
|
||||
printf_dump(LOG_DEBUG, "Calling init from main elf\n");
|
||||
RunElfInit(my_context->elfs[0], emu);
|
||||
}
|
||||
}
|
||||
MarkElfInitDone(my_context->elfs[0]);
|
||||
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main);
|
||||
@@ -456,6 +462,8 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
if(emu->op2==1)
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
} else {
|
||||
if (emu->op1&0x80) {
|
||||
@@ -479,6 +487,8 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
if(emu->op2==1)
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
} else {
|
||||
if (emu->op1&0x8000) {
|
||||
@@ -501,6 +511,8 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
if(emu->op2==1)
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
break;
|
||||
case d_shr8:
|
||||
@@ -514,7 +526,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
}
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x80, F_OF);
|
||||
}
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (emu->op2-1)) & 0x1, F_CF);
|
||||
@@ -534,7 +546,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
}
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x8000, F_OF);
|
||||
}
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
@@ -553,7 +565,35 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
}
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x80000000, F_OF);
|
||||
}
|
||||
break;
|
||||
case d_shrd32:
|
||||
cnt = emu->op2;
|
||||
if (cnt > 0) {
|
||||
cc = emu->op1 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 ^ emu->res) & 0x80000000, F_OF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case d_shld32:
|
||||
cnt = emu->op2;
|
||||
if (cnt > 0) {
|
||||
cc = emu->op1 & (1 << (32 - cnt));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 ^ emu->res) & 0x80000000, F_OF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case d_sub8:
|
||||
@@ -772,7 +812,10 @@ uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg)
|
||||
|
||||
const char* getAddrFunctionName(uintptr_t addr)
|
||||
{
|
||||
static char ret[1000];
|
||||
static char rets[8][1000];
|
||||
static int idx = 0;
|
||||
char* ret = rets[idx];
|
||||
idx = (idx+1)&7;
|
||||
uint32_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
elfheader_t* elf = FindElfAddress(my_context, addr);
|
||||
@@ -880,8 +923,13 @@ void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
if(peek==0xC3 || peek==0xC2) {
|
||||
printf_log(LOG_NONE, " => %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(*(uintptr_t*)(R_ESP), "=> ");
|
||||
} else if(peek==0x55) {
|
||||
} else if(peek==0x55 || peek==0x57 || peek==0x53) {
|
||||
printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(*(uintptr_t*)(R_ESP), "top:");
|
||||
printFunctionAddr(ip, "here: ");
|
||||
} else if(peek==0x83 && PK(1)==0xEC) {
|
||||
printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(*(uintptr_t*)(R_ESP), "top:");
|
||||
printFunctionAddr(ip, "here: ");
|
||||
} else if(peek==0xE8) { // Call
|
||||
uintptr_t nextaddr = ip + 5 + PK32(1);
|
||||
|
||||
@@ -212,6 +212,7 @@ uintptr_t Run6466(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Run6467(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Run66(x86emu_t *emu, int rep, uintptr_t addr);
|
||||
uintptr_t Run660F(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run66F20F(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run6664(x86emu_t *emu, int seg, uintptr_t addr);
|
||||
uintptr_t Run66D9(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run66DD(x86emu_t *emu, uintptr_t addr);
|
||||
@@ -241,6 +242,7 @@ uintptr_t Test6466(x86test_t *test, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Test6467(x86test_t *test, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Test66(x86test_t *test, int rep, uintptr_t addr);
|
||||
uintptr_t Test660F(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test66F20F(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test6664(x86test_t *test, int seg, uintptr_t addr);
|
||||
uintptr_t Test66D9(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test66DD(x86test_t *test, uintptr_t addr);
|
||||
|
||||
+6
-1
@@ -1,3 +1,4 @@
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x87emu_setround.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
@@ -32,6 +34,7 @@ uintptr_t RunD8(x86emu_t *emu, uintptr_t addr)
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
int oldround = fpu_setround(emu);
|
||||
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
@@ -192,9 +195,11 @@ uintptr_t RunD8(x86emu_t *emu, uintptr_t addr)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fesetround(oldround);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
fesetround(oldround);
|
||||
return addr;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
+63
-13
@@ -1,4 +1,5 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -12,6 +13,7 @@
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x87emu_setround.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
@@ -33,6 +35,7 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
int oldround;
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
@@ -110,7 +113,13 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
break;
|
||||
|
||||
case 0xF0: /* F2XM1 */
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
if (ST0.d == 0)
|
||||
break;
|
||||
// Using the expm1 instead of exp2(ST0)-1 can avoid losing precision much,
|
||||
// expecially when ST0 is close to zero (which loses the precise when -1).
|
||||
// printf("%a, %a\n", LN2 * ST0.d, expm1(LN2 * ST0.d));
|
||||
ST0.d = expm1(LN2 * ST0.d);
|
||||
// = 2^ST0 - 1 + error. (in math)
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF1: /* FYL2X */
|
||||
@@ -119,21 +128,36 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF2: /* FPTAN */
|
||||
oldround = fpu_setround(emu);
|
||||
ST0.d = tan(ST0.d);
|
||||
fesetround(oldround);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = 1.0;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF3: /* FPATAN */
|
||||
oldround = fpu_setround(emu);
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
fesetround(oldround);
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF4: /* FXTRACT */
|
||||
ST0.d = frexp(ST0.d, &tmp32s);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = tmp32s;
|
||||
if(isnan(ST1.d)) {
|
||||
ST0.d = ST1.d;
|
||||
} else if(isinf(ST1.d)) {
|
||||
ST0.d = ST1.d;
|
||||
ST1.d = INFINITY;
|
||||
} else if(ST1.d==0.0) {
|
||||
ST0.d = ST1.d;
|
||||
ST1.d = -INFINITY;
|
||||
} else {
|
||||
// LD80bits doesn't have implicit "1" bit, so need to adjust for that
|
||||
ST0.d = frexp(ST1.d, &tmp32s)*2;
|
||||
ST1.d = tmp32s-1;
|
||||
}
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
|
||||
@@ -184,20 +208,30 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
emu->top=(emu->top-1)&7; // this will probably break a few things
|
||||
break;
|
||||
case 0xF7: /* FINCSTP */
|
||||
emu->top=(emu->top+1)&7; // this will probably break a few things
|
||||
if(emu->fpu_tags&0b11)
|
||||
fpu_do_pop(emu);
|
||||
else
|
||||
emu->top=(emu->top+1)&7; // this will probably break a few things
|
||||
break;
|
||||
case 0xF9: /* FYL2XP1 */
|
||||
ST(1).d *= log2(ST0.d + 1.0);
|
||||
// Using the log1p instead of log2(ST0+1) can avoid losing precision much,
|
||||
// expecially when ST0 is close to zero (which loses the precise when +1).
|
||||
ST(1).d = (ST(1).d * log1p(ST0.d)) / M_LN2;
|
||||
// = ST1 * log2(ST0 + 1) + error. (in math)
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFA: /* FSQRT */
|
||||
oldround = fpu_setround(emu);
|
||||
ST0.d = sqrt(ST0.d);
|
||||
fesetround(oldround);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFB: /* FSINCOS */
|
||||
fpu_do_push(emu);
|
||||
oldround = fpu_setround(emu);
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
fesetround(oldround);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
@@ -206,18 +240,30 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFD: /* FSCALE */
|
||||
// this could probably be done by just altering the exponant part of the float...
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
if (ST1.d > INT32_MAX)
|
||||
tmp32s = INT32_MAX;
|
||||
else if (ST1.d < INT32_MIN)
|
||||
tmp32s = INT32_MIN;
|
||||
else
|
||||
tmp32s = ST1.d;
|
||||
if(ST0.d!=0.0) {
|
||||
oldround = fpu_setround(emu);
|
||||
ST0.d = ldexp(ST0.d, tmp32s);
|
||||
fesetround(oldround);
|
||||
}
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFE: /* FSIN */
|
||||
oldround = fpu_setround(emu);
|
||||
ST0.d = sin(ST0.d);
|
||||
fesetround(oldround);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFF: /* FCOS */
|
||||
oldround = fpu_setround(emu);
|
||||
ST0.d = cos(ST0.d);
|
||||
fesetround(oldround);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
@@ -256,18 +302,22 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
break;
|
||||
case 2: /* FST Ed, ST0 */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
if(!(((uintptr_t)ED)&3)) {
|
||||
oldround = fpu_setround(emu);
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
fesetround(oldround);
|
||||
} else {
|
||||
f = ST0.d;
|
||||
memcpy(ED, &f, sizeof(float));
|
||||
}
|
||||
break;
|
||||
case 3: /* FSTP Ed, ST0 */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
if(!(((uintptr_t)ED)&3)) {
|
||||
oldround = fpu_setround(emu);
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
fesetround(oldround);
|
||||
} else {
|
||||
f = ST0.d;
|
||||
memcpy(ED, &f, sizeof(float));
|
||||
}
|
||||
@@ -303,5 +353,5 @@ uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
return addr;
|
||||
}
|
||||
+5
-2
@@ -1,3 +1,4 @@
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x87emu_setround.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
@@ -24,7 +26,6 @@ uintptr_t RunDA(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
float f;
|
||||
reg32_t *oped;
|
||||
@@ -101,7 +102,8 @@ uintptr_t RunDA(x86emu_t *emu, uintptr_t addr)
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
return 0;
|
||||
default:
|
||||
default:;
|
||||
int oldround = fpu_setround(emu);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ed int */
|
||||
GET_ED;
|
||||
@@ -137,6 +139,7 @@ uintptr_t RunDA(x86emu_t *emu, uintptr_t addr)
|
||||
ST0.d = (double)ED->sdword[0] / ST0.d;
|
||||
break;
|
||||
}
|
||||
fesetround(oldround);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
+3
-3
@@ -172,10 +172,10 @@ uintptr_t RunDB(x86emu_t *emu, uintptr_t addr)
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
GET_EDT;
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, ED);
|
||||
else
|
||||
if(STld(0).uref && (ST0.q==STld(0).uref))
|
||||
memcpy(ED, &STld(0).ld, 10);
|
||||
else
|
||||
D2LD(&ST0.d, ED);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x87emu_setround.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
@@ -32,6 +34,7 @@ uintptr_t RunDC(x86emu_t *emu, uintptr_t addr)
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
int oldround = fpu_setround(emu);
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -184,8 +187,10 @@ uintptr_t RunDC(x86emu_t *emu, uintptr_t addr)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fesetround(oldround);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fesetround(oldround);
|
||||
return addr;
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x87emu_setround.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
@@ -32,6 +33,7 @@ uintptr_t RunDE(x86emu_t *emu, uintptr_t addr)
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
int oldround = fpu_setround(emu);
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0: /* FADDP STx, ST0 */
|
||||
@@ -158,8 +160,10 @@ uintptr_t RunDE(x86emu_t *emu, uintptr_t addr)
|
||||
ST0.d = (double)EW->sword[0] / ST0.d;
|
||||
break;
|
||||
default:
|
||||
fesetround(oldround);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fesetround(oldround);
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+33
-9
@@ -554,16 +554,40 @@ uintptr_t RunF0(x86emu_t *emu, uintptr_t addr)
|
||||
case 0x86: /* XCHG Eb,Gb */
|
||||
case 0x87: /* XCHG Ed,Gd */
|
||||
return addr-1; // let the normal XCHG execute, it have integrated LOCK
|
||||
case 0x90: // This is xchg reg, reg, so let's ignore the LOCK prefix...
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
return addr-1;
|
||||
|
||||
case 0xFE: /* GRP 5 Eb */
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp8u = arm_lock_read_b(EB);
|
||||
} while(arm_lock_write_b(EB, inc8(emu, tmp8u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
EB->byte[0] = inc8(emu, EB->byte[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp8u = arm_lock_read_b(EB);
|
||||
} while(arm_lock_write_d(EB, dec8(emu, tmp8u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
EB->byte[0] = dec8(emu, EB->byte[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0xFE 0x%02X 0x%02X\n", nextop, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
|
||||
@@ -147,7 +147,7 @@ uintptr_t RunF066(x86emu_t *emu, uintptr_t addr)
|
||||
} while(arm_lock_write_h(ED, inc16(emu, tmp16u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
ED->word[0] = inc16(emu, ED->word[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
@@ -168,7 +168,7 @@ uintptr_t RunF066(x86emu_t *emu, uintptr_t addr)
|
||||
} while(arm_lock_write_h(ED, dec16(emu, tmp16u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
ED->word[0] = dec16(emu, ED->word[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -103,6 +103,42 @@ uintptr_t RunF20F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38: // more opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF0: // CRC32 Gd, Eb
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
GD.dword[0] ^= EB->byte[0];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (GD.dword[0] & 1)
|
||||
GD.dword[0] = (GD.dword[0] >> 1) ^ 0x82f63b78;
|
||||
else
|
||||
GD.dword[0] = (GD.dword[0] >> 1);
|
||||
}
|
||||
break;
|
||||
case 0xF1: // CRC32 Gd, Ed
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
for(int j=0; j<4; ++j) {
|
||||
GD.dword[0] ^= ED->byte[j];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (GD.dword[0] & 1)
|
||||
GD.dword[0] = (GD.dword[0] >> 1) ^ 0x82f63b78;
|
||||
else
|
||||
GD.dword[0] = (GD.dword[0] >> 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x51: /* SQRTSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
|
||||
@@ -42,6 +42,11 @@ uintptr_t RunF30F(x86emu_t *emu, uintptr_t addr)
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
#ifdef TERMUX
|
||||
extern int isinff(float);
|
||||
extern int isnanf(float);
|
||||
#endif
|
||||
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
@@ -215,6 +220,20 @@ uintptr_t RunF30F(x86emu_t *emu, uintptr_t addr)
|
||||
memcpy(EX, &GX, 16); // unaligned...
|
||||
break;
|
||||
|
||||
case 0xB8: /* POPCNT Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GD.dword[0] = __builtin_popcount(ED->dword[0]);
|
||||
RESET_FLAGS(emu);
|
||||
CLEAR_FLAG(F_OF);
|
||||
CLEAR_FLAG(F_SF);
|
||||
CLEAR_FLAG(F_ZF);
|
||||
CLEAR_FLAG(F_AF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_PF);
|
||||
CONDITIONAL_SET_FLAG(GD.dword[0]==0, F_ZF);
|
||||
break;
|
||||
|
||||
case 0xBC: /* TZCNT Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
|
||||
+321
-298
@@ -107,6 +107,7 @@ int my_socketcall(x86emu_t* emu, int n, unsigned long *args) {
|
||||
printf_log(LOG_DEBUG, "BOX86 Error on Syscall 102: Unknown Soket command %d\n", n);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -115,190 +116,189 @@ int my_socketcall(x86emu_t* emu, int n, unsigned long *args) {
|
||||
#define O_NONBLOCK 04000
|
||||
#endif
|
||||
int my_fcntl(x86emu_t* emu, int fd, int cmd, ... /* arg */ );
|
||||
long my_ptrace(x86emu_t* emu, int request, pid_t pid, void* addr, uint32_t* data);
|
||||
|
||||
// Syscall table for x86 can be found here: http://shell-storm.org/shellcode/files/syscalls.html
|
||||
typedef struct scwrap_s {
|
||||
uint32_t x86s;
|
||||
int nats;
|
||||
int nbpars;
|
||||
} scwrap_t;
|
||||
|
||||
scwrap_t syscallwrap[] = {
|
||||
{ 2, __NR_fork, 1 }, // should wrap this one, because of the struct pt_regs (the only arg)?
|
||||
//{ 3, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc
|
||||
//{ 4, __NR_write, 3 }, // same
|
||||
//{ 5, __NR_open, 3 }, // flags need transformation
|
||||
//{ 6, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc
|
||||
[2] ={ __NR_fork, 1 }, // should wrap this one, because of the struct pt_regs (the only arg)?
|
||||
//[3] ={ __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc
|
||||
//[4] ={ __NR_write, 3 }, // same
|
||||
//[5] ={ __NR_open, 3 }, // flags need transformation
|
||||
//[6] ={ __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc
|
||||
#ifdef __NR_waitpid
|
||||
{ 7, __NR_waitpid, 3 },
|
||||
[7] ={ __NR_waitpid, 3 },
|
||||
#endif
|
||||
{ 10, __NR_unlink, 1 },
|
||||
{ 12, __NR_chdir, 1 },
|
||||
[10] { __NR_unlink, 1 },
|
||||
[12] { __NR_chdir, 1 },
|
||||
#ifdef __NR_time
|
||||
{ 13, __NR_time, 1 },
|
||||
[13] { __NR_time, 1 },
|
||||
#endif
|
||||
{ 15, __NR_chmod, 2 },
|
||||
{ 19, __NR_lseek, 3 },
|
||||
{ 20, __NR_getpid, 0 },
|
||||
{ 24, __NR_getuid, 0 },
|
||||
[15] { __NR_chmod, 2 },
|
||||
[19] { __NR_lseek, 3 },
|
||||
[20] { __NR_getpid, 0 },
|
||||
[24] { __NR_getuid, 0 },
|
||||
//[26] ={__NR_ptrace, 4},
|
||||
#ifdef __NR_alarm
|
||||
{ 27, __NR_alarm, 1 },
|
||||
[27] { __NR_alarm, 1 },
|
||||
#endif
|
||||
{ 33, __NR_access, 2 },
|
||||
{ 37, __NR_kill, 2 },
|
||||
{ 38, __NR_rename, 2 },
|
||||
{ 39, __NR_mkdir, 2 },
|
||||
{ 40, __NR_rmdir, 1 },
|
||||
{ 41, __NR_dup, 1 },
|
||||
{ 42, __NR_pipe, 1 },
|
||||
//{ 45, __NR_brk, 1 },
|
||||
{ 47, __NR_getgid, 0 },
|
||||
{ 49, __NR_geteuid, 0 },
|
||||
{ 50, __NR_getegid, 0 },
|
||||
{ 54, __NR_ioctl, 3 }, // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
|
||||
//{ 55, __NR_fcntl, 3 }, // wrapped to allow filter of F_SETFD
|
||||
{ 60, __NR_umask, 1 },
|
||||
{ 63, __NR_dup2, 2 },
|
||||
{ 64, __NR_getppid, 0 },
|
||||
{ 66, __NR_setsid, 0 },
|
||||
//{ 67, __NR_sigaction, 3 },
|
||||
{ 75, __NR_setrlimit, 2 },
|
||||
[33] { __NR_access, 2 },
|
||||
[37] { __NR_kill, 2 },
|
||||
[38] { __NR_rename, 2 },
|
||||
[39] { __NR_mkdir, 2 },
|
||||
[40] { __NR_rmdir, 1 },
|
||||
[41] { __NR_dup, 1 },
|
||||
[42] { __NR_pipe, 1 },
|
||||
//[45] { __NR_brk, 1 },
|
||||
[47] { __NR_getgid, 0 },
|
||||
[49] { __NR_geteuid, 0 },
|
||||
[50] { __NR_getegid, 0 },
|
||||
[54] { __NR_ioctl, 3 }, // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
|
||||
//[55] { __NR_fcntl, 3 }, // wrapped to allow filter of F_SETFD
|
||||
[60] { __NR_umask, 1 },
|
||||
[63] { __NR_dup2, 2 },
|
||||
[64] { __NR_getppid, 0 },
|
||||
[66] { __NR_setsid, 0 },
|
||||
//[67] { __NR_sigaction, 3 },
|
||||
[75] { __NR_setrlimit, 2 },
|
||||
#ifdef __NR_getrlimit
|
||||
{ 76, __NR_getrlimit, 2 },
|
||||
[76] { __NR_getrlimit, 2 },
|
||||
#endif
|
||||
{ 77, __NR_getrusage, 2 },
|
||||
{ 78, __NR_gettimeofday, 2 },
|
||||
{ 80, __NR_getgroups, 2 },
|
||||
{ 83, __NR_symlink, 2 },
|
||||
[77] { __NR_getrusage, 2 },
|
||||
[78] { __NR_gettimeofday, 2 },
|
||||
[80] { __NR_getgroups, 2 },
|
||||
[83] { __NR_symlink, 2 },
|
||||
#ifdef __NR_select
|
||||
{ 82, __NR_select, 5 },
|
||||
[82] { __NR_select, 5 },
|
||||
#endif
|
||||
{ 85, __NR_readlink, 3 },
|
||||
//{ 91, __NR_munmap, 2 },
|
||||
{ 94, __NR_fchmod, 2 },
|
||||
{ 99, __NR_statfs, 2 },
|
||||
[85] { __NR_readlink, 3 },
|
||||
//[91] { __NR_munmap, 2 },
|
||||
[94] { __NR_fchmod, 2 },
|
||||
[99] { __NR_statfs, 2 },
|
||||
#ifdef __NR_socketcall
|
||||
{ 102, __NR_socketcall, 2 },
|
||||
[102] { __NR_socketcall, 2 },
|
||||
#endif
|
||||
{ 104, __NR_setitimer, 3 },
|
||||
{ 105, __NR_getitimer, 2 },
|
||||
[104] { __NR_setitimer, 3 },
|
||||
[105] { __NR_getitimer, 2 },
|
||||
#ifdef __NR_newstat
|
||||
{ 106, __NR_newstat, 2 },
|
||||
[106] { __NR_newstat, 2 },
|
||||
#else
|
||||
{ 106, __NR_stat, 2 },
|
||||
[106] { __NR_stat, 2 },
|
||||
#endif
|
||||
#ifdef __NR_newlstat
|
||||
{ 107, __NR_newlstat, 2 },
|
||||
[107] { __NR_newlstat, 2 },
|
||||
#else
|
||||
{ 107, __NR_lstat, 2 },
|
||||
[107] { __NR_lstat, 2 },
|
||||
#endif
|
||||
#ifdef __NR_newfstat
|
||||
{ 108, __NR_newfstat, 2 },
|
||||
[108] { __NR_newfstat, 2 },
|
||||
#else
|
||||
{ 108, __NR_fstat, 2 },
|
||||
[108] { __NR_fstat, 2 },
|
||||
#endif
|
||||
#ifdef __NR_olduname
|
||||
{ 109, __NR_olduname, 1 },
|
||||
[109] { __NR_olduname, 1 },
|
||||
#endif
|
||||
#ifdef __NR_iopl
|
||||
{ 110, __NR_iopl, 1 },
|
||||
[110] { __NR_iopl, 1 },
|
||||
#endif
|
||||
{ 114, __NR_wait4, 4 }, //TODO: check struct rusage alignment
|
||||
[114] { __NR_wait4, 4 }, //TODO: check struct rusage alignment
|
||||
#ifdef __NR_ipc
|
||||
{ 117, __NR_ipc, 6 },
|
||||
[117] { __NR_ipc, 6 },
|
||||
#endif
|
||||
//{ 119, __NR_sigreturn, 0},
|
||||
//{ 120, __NR_clone, 5 }, // need works
|
||||
//{ 122, __NR_uname, 1 },
|
||||
//{ 123, __NR_modify_ldt },
|
||||
//{ 125, __NR_mprotect, 3 },
|
||||
{ 126, __NR_sigprocmask, 3 },
|
||||
{ 136, __NR_personality, 1 },
|
||||
{ 140, __NR__llseek, 5 },
|
||||
{ 141, __NR_getdents, 3 },
|
||||
{ 142, __NR__newselect, 5 },
|
||||
{ 143, __NR_flock, 2 },
|
||||
{ 144, __NR_msync, 3 },
|
||||
{ 145, __NR_readv, 3 },
|
||||
{ 146, __NR_writev, 3 },
|
||||
{ 148, __NR_fdatasync, 1 },
|
||||
{ 149, __NR__sysctl, 1 }, // need wrapping?
|
||||
{ 156, __NR_sched_setscheduler, 3 },
|
||||
{ 157, __NR_sched_getscheduler, 1 },
|
||||
{ 158, __NR_sched_yield, 0 },
|
||||
{ 162, __NR_nanosleep, 2 },
|
||||
{ 164, __NR_setresuid, 3 },
|
||||
//{ 168, __NR_poll, 3 }, // wrapped to allow SA_RESTART wrapping by libc
|
||||
{ 172, __NR_prctl, 5 },
|
||||
//{ 173, __NR_rt_sigreturn, 0 },
|
||||
{ 175, __NR_rt_sigprocmask, 4 },
|
||||
{ 179, __NR_rt_sigsuspend, 2 },
|
||||
{ 183, __NR_getcwd, 2 },
|
||||
{ 184, __NR_capget, 2},
|
||||
{ 185, __NR_capset, 2},
|
||||
{ 186, __NR_sigaltstack, 2 }, // neeed wrap or something?
|
||||
{ 191, __NR_ugetrlimit, 2 },
|
||||
// { 192, __NR_mmap2, 6},
|
||||
//{ 195, __NR_stat64, 2 }, // need proprer wrap because of structure size change
|
||||
//{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
|
||||
//{ 197, __NR_fstat64, 2 }, // need proprer wrap because of structure size change
|
||||
//[119] { __NR_sigreturn, 0},
|
||||
//[120] { __NR_clone, 5 }, // need works
|
||||
//[122] { __NR_uname, 1 },
|
||||
//[123] { __NR_modify_ldt },
|
||||
//[125] { __NR_mprotect, 3 },
|
||||
[126] { __NR_sigprocmask, 3 },
|
||||
[136] { __NR_personality, 1 },
|
||||
[140] { __NR__llseek, 5 },
|
||||
[141] { __NR_getdents, 3 },
|
||||
[142] { __NR__newselect, 5 },
|
||||
[143] { __NR_flock, 2 },
|
||||
[144] { __NR_msync, 3 },
|
||||
[145] { __NR_readv, 3 },
|
||||
[146] { __NR_writev, 3 },
|
||||
[148] { __NR_fdatasync, 1 },
|
||||
[149] { __NR__sysctl, 1 }, // need wrapping?
|
||||
[156] { __NR_sched_setscheduler, 3 },
|
||||
[157] { __NR_sched_getscheduler, 1 },
|
||||
[158] { __NR_sched_yield, 0 },
|
||||
[162] { __NR_nanosleep, 2 },
|
||||
[164] { __NR_setresuid, 3 },
|
||||
//[168] { __NR_poll, 3 }, // wrapped to allow SA_RESTART wrapping by libc
|
||||
[172] { __NR_prctl, 5 },
|
||||
//[173] { __NR_rt_sigreturn, 0 },
|
||||
[175] { __NR_rt_sigprocmask, 4 },
|
||||
[179] { __NR_rt_sigsuspend, 2 },
|
||||
[183] { __NR_getcwd, 2 },
|
||||
[184] { __NR_capget, 2},
|
||||
[185] { __NR_capset, 2},
|
||||
[186] { __NR_sigaltstack, 2 }, // neeed wrap or something?
|
||||
[191] { __NR_ugetrlimit, 2 },
|
||||
// [192] { __NR_mmap2, 6},
|
||||
//[195] { __NR_stat64, 2 }, // need proprer wrap because of structure size change
|
||||
//[196] { __NR_lstat64, 2 }, // need proprer wrap because of structure size change
|
||||
//[197] { __NR_fstat64, 2 }, // need proprer wrap because of structure size change
|
||||
#ifndef POWERPCLE
|
||||
{ 199, __NR_getuid32, 0 },
|
||||
{ 200, __NR_getgid32, 0 },
|
||||
{ 201, __NR_geteuid32, 0 },
|
||||
{ 202, __NR_getegid32, 0 },
|
||||
{ 208, __NR_setresuid32, 3 },
|
||||
{ 209, __NR_getresuid32, 3 },
|
||||
{ 210, __NR_setresgid32, 3 },
|
||||
{ 211, __NR_getresgid32, 3 },
|
||||
[199] { __NR_getuid32, 0 },
|
||||
[200] { __NR_getgid32, 0 },
|
||||
[201] { __NR_geteuid32, 0 },
|
||||
[202] { __NR_getegid32, 0 },
|
||||
[208] { __NR_setresuid32, 3 },
|
||||
[209] { __NR_getresuid32, 3 },
|
||||
[210] { __NR_setresgid32, 3 },
|
||||
[211] { __NR_getresgid32, 3 },
|
||||
#else
|
||||
// PowerPC uses the same syscalls for 32/64 bit processes.
|
||||
{ 199, __NR_getuid, 0 },
|
||||
{ 200, __NR_getgid, 0 },
|
||||
{ 201, __NR_geteuid, 0 },
|
||||
{ 202, __NR_getegid, 0 },
|
||||
{ 208, __NR_setresuid, 3 },
|
||||
{ 209, __NR_getresuid, 3 },
|
||||
{ 210, __NR_setresgid, 3 },
|
||||
{ 211, __NR_getresgid, 3 },
|
||||
[199] { __NR_getuid, 0 },
|
||||
[200] { __NR_getgid, 0 },
|
||||
[201] { __NR_geteuid, 0 },
|
||||
[202] { __NR_getegid, 0 },
|
||||
[208] { __NR_setresuid, 3 },
|
||||
[209] { __NR_getresuid, 3 },
|
||||
[210] { __NR_setresgid, 3 },
|
||||
[211] { __NR_getresgid, 3 },
|
||||
#endif
|
||||
{ 220, __NR_getdents64, 3 },
|
||||
//{ 221, __NR_fcntl64, 3 },
|
||||
{ 224, __NR_gettid, 0 },
|
||||
{ 240, __NR_futex, 6 },
|
||||
{ 241, __NR_sched_setaffinity, 3 },
|
||||
{ 242, __NR_sched_getaffinity, 3 },
|
||||
{ 252, __NR_exit_group, 1 },
|
||||
[220] { __NR_getdents64, 3 },
|
||||
//[221] { __NR_fcntl64, 3 },
|
||||
[224] { __NR_gettid, 0 },
|
||||
[240] { __NR_futex, 6 },
|
||||
[241] { __NR_sched_setaffinity, 3 },
|
||||
[242] { __NR_sched_getaffinity, 3 },
|
||||
[252] { __NR_exit_group, 1 },
|
||||
#ifdef NOALIGN
|
||||
{ 254, __NR_epoll_create, 1 },
|
||||
{ 255, __NR_epoll_ctl, 4 },
|
||||
{ 256, __NR_epoll_wait, 4 },
|
||||
[254] { __NR_epoll_create, 1 },
|
||||
[255] { __NR_epoll_ctl, 4 },
|
||||
[256] { __NR_epoll_wait, 4 },
|
||||
#endif
|
||||
{ 265, __NR_clock_gettime, 2 },
|
||||
{ 266, __NR_clock_getres, 2 },
|
||||
//{ 270, __NR_tgkill, 3 },
|
||||
{ 271, __NR_utimes, 2 },
|
||||
{ 291, __NR_inotify_init, 0},
|
||||
{ 292, __NR_inotify_add_watch, 3},
|
||||
{ 293, __NR_inotify_rm_watch, 2},
|
||||
{ 311, __NR_set_robust_list, 2 },
|
||||
{ 312, __NR_get_robust_list, 4 },
|
||||
{ 318, __NR_getcpu, 3},
|
||||
{ 328, __NR_eventfd2, 2},
|
||||
[265] { __NR_clock_gettime, 2 },
|
||||
[266] { __NR_clock_getres, 2 },
|
||||
//[270] { __NR_tgkill, 3 },
|
||||
[271] { __NR_utimes, 2 },
|
||||
[291] { __NR_inotify_init, 0},
|
||||
[292] { __NR_inotify_add_watch, 3},
|
||||
[293] { __NR_inotify_rm_watch, 2},
|
||||
[311] { __NR_set_robust_list, 2 },
|
||||
[312] { __NR_get_robust_list, 4 },
|
||||
[318] { __NR_getcpu, 3},
|
||||
[328] { __NR_eventfd2, 2},
|
||||
#ifdef NOALIGN
|
||||
{ 329, __NR_epoll_create1, 1 },
|
||||
[329] { __NR_epoll_create1, 1 },
|
||||
#endif
|
||||
{ 331, __NR_pipe2, 2},
|
||||
{ 332, __NR_inotify_init1, 1},
|
||||
[331] { __NR_pipe2, 2},
|
||||
[332] { __NR_inotify_init1, 1},
|
||||
#ifdef __NR_getrandom
|
||||
{ 355, __NR_getrandom, 3 },
|
||||
[355] { __NR_getrandom, 3 },
|
||||
#endif
|
||||
#ifdef __NR_memfd_create
|
||||
{ 356, __NR_memfd_create, 2},
|
||||
#endif
|
||||
#ifdef __NR_futex_waitv
|
||||
{ 449, __NR_futex_waitv, 5},
|
||||
[356] { __NR_memfd_create, 2},
|
||||
#endif
|
||||
//[449] { __NR_futex_waitv, 5},
|
||||
};
|
||||
|
||||
struct mmap_arg_struct {
|
||||
@@ -413,27 +413,25 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
printf_log(LOG_DEBUG, "%p: Calling syscall 0x%02X (%d) %p %p %p %p %p", (void*)R_EIP, s, s, (void*)R_EBX, (void*)R_ECX, (void*)R_EDX, (void*)R_ESI, (void*)R_EDI);
|
||||
// check wrapper first
|
||||
int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
|
||||
for (int i=0; i<cnt; i++) {
|
||||
if(syscallwrap[i].x86s == s) {
|
||||
int sc = syscallwrap[i].nats;
|
||||
switch(syscallwrap[i].nbpars) {
|
||||
case 0: *(int32_t*)&R_EAX = syscall(sc); break;
|
||||
case 1: *(int32_t*)&R_EAX = syscall(sc, R_EBX); break;
|
||||
case 2: if(s==33) {printf_log(LOG_DEBUG, " => sys_access(\"%s\", %d)\n", (char*)R_EBX, R_ECX);}; *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX); break;
|
||||
case 3: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
|
||||
case 4: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
|
||||
case 5: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
|
||||
case 6: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars);
|
||||
emu->quit = 1;
|
||||
return;
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
|
||||
return;
|
||||
if(s<cnt && syscallwrap[s].nats) {
|
||||
int sc = syscallwrap[s].nats;
|
||||
switch(syscallwrap[s].nbpars) {
|
||||
case 0: S_EAX = syscall(sc); break;
|
||||
case 1: S_EAX = syscall(sc, R_EBX); break;
|
||||
case 2: if(s==33) {printf_log(LOG_DEBUG, " => sys_access(\"%s\", %d)\n", (char*)R_EBX, R_ECX);}; S_EAX = syscall(sc, R_EBX, R_ECX); break;
|
||||
case 3: S_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
|
||||
case 4: S_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
|
||||
case 5: S_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
|
||||
case 6: S_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[s].nbpars);
|
||||
emu->quit = 1;
|
||||
return;
|
||||
}
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
|
||||
return;
|
||||
}
|
||||
switch (s) {
|
||||
case 1: // sys_exit
|
||||
@@ -443,32 +441,32 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the thread now
|
||||
break;
|
||||
case 3: // sys_read
|
||||
R_EAX = (uint32_t)read((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = read(S_EBX, (void*)R_ECX, (size_t)R_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 4: // sys_write
|
||||
R_EAX = (uint32_t)write((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = write(S_EBX, (void*)R_ECX, (size_t)R_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 5: // sys_open
|
||||
if(s==5) {printf_log(LOG_DEBUG, " => sys_open(\"%s\", %d, %d)", (char*)R_EBX, of_convert(R_ECX), R_EDX);};
|
||||
//R_EAX = (uint32_t)open((void*)R_EBX, of_convert(R_ECX), R_EDX);
|
||||
R_EAX = (uint32_t)my_open(emu, (void*)R_EBX, of_convert(R_ECX), R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
//S_EAX = open((void*)R_EBX, of_convert(R_ECX), R_EDX);
|
||||
S_EAX = my_open(emu, (void*)R_EBX, of_convert(R_ECX), R_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 6: // sys_close
|
||||
R_EAX = (uint32_t)close((int)R_EBX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = close(S_EBX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef __NR_waitpid
|
||||
case 7: //sys_waitpid
|
||||
R_EAX = waitpid((pid_t)R_EBX, (int*)R_ECX, (int)R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
R_EAX = waitpid((pid_t)R_EBX, (int*)R_ECX, S_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 11: // sys_execve
|
||||
@@ -479,55 +477,60 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
printf_log(LOG_DEBUG, " => sys_execve(\"%s\", %p(\"%s\", \"%s\", \"%s\"...), %p)\n", prog, argv, (argv && argv[0])?argv[0]:"nil", (argv && argv[0] && argv[1])?argv[1]:"nil", (argv && argv[0] && argv[1] && argv[2])?argv[2]:"nil", envv);
|
||||
R_EAX = my_execve(emu, (const char*)R_EBX, (void*)R_ECX, (void*)R_EDX);
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef __NR_time
|
||||
case 13: // sys_time (it's deprecated and remove on ARM EABI it seems)
|
||||
R_EAX = time(NULL);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 26: // sys_ptrace
|
||||
S_EAX = my_ptrace(emu, R_EBX, R_ECX, (void*)R_EDX, (void*)R_ESI);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef __NR_alarm
|
||||
case 27:
|
||||
R_EAX = alarm(R_EBX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 45: // sys_brk
|
||||
R_EAX = (uintptr_t)ElfSetBrk((void*)R_EBX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 54: // sys_ioctl
|
||||
R_EAX = (uint32_t)ioctl((int)R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = ioctl(S_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 55: // sys_fcntl
|
||||
R_EAX = (uint32_t)my_fcntl(emu, (int)R_EBX, (int)R_ECX, R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = my_fcntl(emu, S_EBX, S_ECX, R_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 67: // sys_sigaction
|
||||
R_EAX = (uint32_t)my_syscall_sigaction(emu, R_EBX, (x86_sigaction_restorer_t*)R_ECX, (x86_sigaction_restorer_t*)R_EDX, R_ESI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = my_syscall_sigaction(emu, R_EBX, (x86_sigaction_restorer_t*)R_ECX, (x86_sigaction_restorer_t*)R_EDX, R_ESI);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef __NR_getrlimit
|
||||
case 76: // sys_getrlimit... this is the old version, using the new one. Maybe some tranform is needed?
|
||||
R_EAX = getrlimit(R_EBX, (void*)R_ECX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_select
|
||||
case 82: // select
|
||||
R_EAX = select(R_EBX, (fd_set*)R_ECX, (fd_set*)R_EDX, (fd_set*)R_ESI, (struct timeval*)R_EDI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 90: // old_mmap
|
||||
@@ -535,19 +538,19 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
struct mmap_arg_struct *st = (struct mmap_arg_struct*)R_EBX;
|
||||
R_EAX = (uintptr_t)my_mmap(emu, (void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 91: // munmap
|
||||
R_EAX = my_munmap(emu, (void*)R_EBX, (unsigned long)R_ECX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef __NR_socketcall
|
||||
case 102:
|
||||
R_EAX = my_socketcall(emu, R_EBX, (unsigned long *)R_ECX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_olduname
|
||||
@@ -563,8 +566,8 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
memcpy(old->version, un.version, 9);
|
||||
strcpy(old->machine, "i686");
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -575,9 +578,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
#endif
|
||||
#ifndef __NR_ipc
|
||||
case 117: // ipc
|
||||
R_EAX = (uint32_t)my_ipc(R_EBX, (int)R_ECX, (int)R_EDX, (int)R_ESI, (void*)R_EDI, (long)R_EBP);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = my_ipc(R_EBX, S_ECX, S_EDX, S_ESI, (void*)R_EDI, (long)R_EBP);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 119: // sys_sigreturn
|
||||
@@ -585,17 +588,19 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
break;
|
||||
case 120: // clone
|
||||
// x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
|
||||
printf_log(LOG_DEBUG, "clone syscall flags=0x%x, stack=%p, parent_tid=%d,tls=%p, child_tid=%d\n", R_EBX, (void*)R_ECX, R_EDX, (void*)R_ESI, R_EDI);
|
||||
// so flags=R_EBX, stack=R_ECX, parent_tid=R_EDX, tls=R_ESI, child_tid=R_EDI
|
||||
if((R_EBX&~0xff)==0x4100) {
|
||||
// this is a case of vfork...
|
||||
R_EAX = my_vfork(emu);
|
||||
if(R_EAX==0xffffffff)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1)
|
||||
S_EAX = -errno;
|
||||
} else {
|
||||
if(R_ECX)
|
||||
{
|
||||
void* stack_base = (void*)R_ECX;
|
||||
int stack_size = 0;
|
||||
uintptr_t sp = R_ECX;
|
||||
if(!R_ECX) {
|
||||
// allocate a new stack...
|
||||
int currstack = 0;
|
||||
@@ -604,18 +609,19 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
stack_size = (currstack)?emu->size_stack:(1024*1024);
|
||||
stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
|
||||
// copy value from old stack to new stack
|
||||
if(currstack)
|
||||
if(currstack) {
|
||||
memcpy(stack_base, emu->init_stack, stack_size);
|
||||
else {
|
||||
sp = (uintptr_t)emu->init_stack + R_ESP - (uintptr_t)stack_base;
|
||||
} else {
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base+stack_size-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
sp = (uintptr_t)stack_base+stack_size-size_to_copy;
|
||||
}
|
||||
}
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (R_ECX)?0:1);
|
||||
SetupX86Emu(newemu);
|
||||
CloneEmu(newemu, emu);
|
||||
Push32(newemu, 0);
|
||||
PushExit(newemu);
|
||||
newemu->regs[_SP].dword[0] = sp; // setupnew stack pointer
|
||||
void* mystack = NULL;
|
||||
if(my_context->stack_clone_used) {
|
||||
mystack = box_malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it
|
||||
@@ -626,12 +632,12 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
my_context->stack_clone_used = 1;
|
||||
}
|
||||
long ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), R_EBX, newemu, R_EDX, R_ESI, R_EDI);
|
||||
R_EAX = (uint32_t)ret;
|
||||
S_EAX = ret;
|
||||
}
|
||||
else
|
||||
R_EAX = (uint32_t)syscall(__NR_clone, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = syscall(__NR_clone, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
}
|
||||
break;
|
||||
case 122: // uname
|
||||
@@ -647,23 +653,23 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
strcpy(old->machine, "i686");
|
||||
}
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 123: // SYS_modify_ldt
|
||||
R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)R_ECX, R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 125: // mprotect
|
||||
R_EAX = my_mprotect(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 168: // sys_poll
|
||||
R_EAX = (uint32_t)poll((void*)R_EBX, R_ECX, (int)R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = poll((void*)R_EBX, R_ECX, S_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 173: // sys_rt_sigreturn
|
||||
emu->quit = 1; // we should be inside a DynaCall in a sigaction callback....
|
||||
@@ -671,109 +677,117 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
case 174: // sys_rt_sigaction
|
||||
//printf_log(LOG_NONE, "Warning, Ignoring sys_rt_sigaction(0x%02X, %p, %p)\n", R_EBX, (void*)R_ECX, (void*)R_EDX);
|
||||
R_EAX = my_syscall_sigaction(emu, R_EBX, (void*)R_ECX, (void*)R_EDX, R_ESI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 190: // vfork
|
||||
{
|
||||
int r = my_vfork(emu);
|
||||
R_EAX = r;
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 192: // mmap2
|
||||
R_EAX = (uint32_t)my_mmap64(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX, R_ESI, R_EDI, R_EBP);
|
||||
S_EAX = (intptr_t)my_mmap64(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX, R_ESI, R_EDI, R_EBP);
|
||||
break;
|
||||
case 195: // stat64
|
||||
{
|
||||
struct stat64 st;
|
||||
unsigned int r = syscall(__NR_stat64, R_EBX, &st);
|
||||
UnalignStat64(&st, (void*)R_ECX);
|
||||
UnalignSysStat64(&st, (void*)R_ECX);
|
||||
|
||||
R_EAX = r;
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 196: // lstat64
|
||||
{
|
||||
struct stat64 st;
|
||||
unsigned int r = syscall(__NR_lstat64, R_EBX, &st);
|
||||
UnalignStat64(&st, (void*)R_ECX);
|
||||
UnalignSysStat64(&st, (void*)R_ECX);
|
||||
|
||||
R_EAX = r;
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 197: // fstat64
|
||||
{
|
||||
struct stat64 st;
|
||||
unsigned int r = syscall(__NR_fstat64, R_EBX, &st);
|
||||
UnalignStat64(&st, (void*)R_ECX);
|
||||
UnalignSysStat64(&st, (void*)R_ECX);
|
||||
|
||||
R_EAX = r;
|
||||
}
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 221: // sys_fcntl64
|
||||
R_EAX = (uint32_t)my_fcntl(emu, (int)R_EBX, (int)R_ECX, R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
S_EAX = my_fcntl(emu, S_EBX, S_ECX, R_EDX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 243: // set_thread_area
|
||||
R_EAX = my_set_thread_area((thread_area_t*)R_EBX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef NOALIGN
|
||||
case 254: // epoll_create
|
||||
R_EAX = my_epoll_create(emu, (int)R_EBX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
R_EAX = my_epoll_create(emu, S_EBX);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 255: // epoll_ctl
|
||||
R_EAX = my_epoll_ctl(emu, (int)R_EBX, (int)R_ECX, (int)R_EDX, (void*)R_ESI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
R_EAX = my_epoll_ctl(emu, S_EBX, S_ECX, S_EDX, (void*)R_ESI);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
case 256: // epoll_wait
|
||||
R_EAX = my_epoll_wait(emu, (int)R_EBX, (void*)R_ECX, (int)R_EDX, (int)R_ESI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
R_EAX = my_epoll_wait(emu, S_EBX, (void*)R_ECX, S_EDX, S_ESI);
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 270: // tgkill
|
||||
R_EAX = syscall(__NR_tgkill, R_EBX, R_ECX, R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#ifndef NOALIGN
|
||||
case 329: // epoll_create1
|
||||
R_EAX = my_epoll_create1(emu, of_convert(R_EBX));
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_getrandom
|
||||
case 355: // getrandom
|
||||
R_EAX = my_getrandom(emu, (void*)R_EBX, R_ECX, R_EDX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_memfd_create
|
||||
case 356: // memfd_create
|
||||
R_EAX = my_memfd_create(emu, (void*)R_EBX, R_ECX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
if(S_EAX==-1 && errno>0)
|
||||
S_EAX = -errno;
|
||||
break;
|
||||
#endif
|
||||
case 449:
|
||||
#ifdef __NR_futex_waitv
|
||||
if(box86_futex_waitv)
|
||||
S_EAX = syscall(__NR_futex_waitv, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
else
|
||||
#endif
|
||||
S_EAX = -ENOSYS;
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_INFO, "Warning: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
|
||||
R_EAX = (uint32_t)-ENOSYS;
|
||||
S_EAX = -ENOSYS;
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
|
||||
@@ -784,62 +798,60 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
#define u32(n) *(uint32_t*)stack(n)
|
||||
#define p(n) *(void**)stack(n)
|
||||
|
||||
uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
long EXPORT my_syscall(x86emu_t *emu)
|
||||
{
|
||||
static uint32_t warned = 0;
|
||||
uint32_t s = u32(0);
|
||||
printf_log(LOG_DEBUG, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_EIP, s, s, (void*)u32(4), (void*)u32(8), (void*)u32(12), (void*)u32(16), (void*)u32(20));
|
||||
// check wrapper first
|
||||
int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
|
||||
for (int i=0; i<cnt; i++) {
|
||||
if(syscallwrap[i].x86s == s) {
|
||||
int sc = syscallwrap[i].nats;
|
||||
switch(syscallwrap[i].nbpars) {
|
||||
case 0: return syscall(sc);
|
||||
case 1: return syscall(sc, u32(4));
|
||||
case 2: return syscall(sc, u32(4), u32(8));
|
||||
case 3: return syscall(sc, u32(4), u32(8), u32(12));
|
||||
case 4: return syscall(sc, u32(4), u32(8), u32(12), u32(16));
|
||||
case 5: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20));
|
||||
case 6: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20), u32(24));
|
||||
default:
|
||||
printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars);
|
||||
emu->quit = 1;
|
||||
return 0;
|
||||
}
|
||||
if(s<cnt && syscallwrap[s].nats) {
|
||||
int sc = syscallwrap[s].nats;
|
||||
switch(syscallwrap[s].nbpars) {
|
||||
case 0: return syscall(sc);
|
||||
case 1: return syscall(sc, u32(4));
|
||||
case 2: return syscall(sc, u32(4), u32(8));
|
||||
case 3: return syscall(sc, u32(4), u32(8), u32(12));
|
||||
case 4: return syscall(sc, u32(4), u32(8), u32(12), u32(16));
|
||||
case 5: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20));
|
||||
case 6: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20), u32(24));
|
||||
default:
|
||||
printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[s].nbpars);
|
||||
emu->quit = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
switch (s) {
|
||||
case 1: // __NR_exit
|
||||
emu->quit = 1;
|
||||
return u32(4); // faking the syscall here, we don't want to really terminate the program now
|
||||
return i32(4); // faking the syscall here, we don't want to really terminate the program now
|
||||
case 3: // sys_read
|
||||
return (uint32_t)read(i32(4), p(8), u32(12));
|
||||
return read(i32(4), p(8), u32(12));
|
||||
case 4: // sys_write
|
||||
return (uint32_t)write(i32(4), p(8), u32(12));
|
||||
return write(i32(4), p(8), u32(12));
|
||||
case 5: // sys_open
|
||||
return my_open(emu, p(4), of_convert(u32(8)), u32(12));
|
||||
case 6: // sys_close
|
||||
return (uint32_t)close(i32(4));
|
||||
return close(i32(4));
|
||||
case 11: // execve
|
||||
return (uint32_t)my_execve(emu, p(4), p(8), p(12));
|
||||
return my_execve(emu, p(4), p(8), p(12));
|
||||
#ifndef __NR_alarm
|
||||
case 27:
|
||||
return alarm(R_EBX);
|
||||
#endif
|
||||
case 45: // brk
|
||||
return (uintptr_t)ElfSetBrk(p(4));
|
||||
return (intptr_t)ElfSetBrk(p(4));
|
||||
case 67: // sys_sigaction
|
||||
return my_syscall_sigaction(emu, u32(4), (x86_sigaction_restorer_t*)p(8), (x86_sigaction_restorer_t*)p(12), u32(16));
|
||||
case 91: // munmap
|
||||
return (uint32_t)my_munmap(emu, p(4), u32(8));
|
||||
return my_munmap(emu, p(4), u32(8));
|
||||
#ifndef __NR_socketcall
|
||||
case 102:
|
||||
return my_socketcall(emu, i32(4), (unsigned long *)p(8));
|
||||
#endif
|
||||
#ifndef __NR_ipc
|
||||
case 117: // ipc
|
||||
return (uint32_t)my_ipc(u32(4), i32(8), i32(12), i32(16), p(20), i32(24));
|
||||
return my_ipc(u32(4), i32(8), i32(12), i32(16), p(20), i32(24));
|
||||
#endif
|
||||
case 120: // clone
|
||||
// x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
|
||||
@@ -848,6 +860,7 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
{
|
||||
void* stack_base = p(8);
|
||||
int stack_size = 0;
|
||||
uintptr_t sp = u32(8);
|
||||
if(!stack_base) {
|
||||
// allocate a new stack...
|
||||
int currstack = 0;
|
||||
@@ -856,18 +869,19 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
stack_size = (currstack)?emu->size_stack:(1024*1024);
|
||||
stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
|
||||
// copy value from old stack to new stack
|
||||
if(currstack)
|
||||
if(currstack) {
|
||||
memcpy(stack_base, emu->init_stack, stack_size);
|
||||
else {
|
||||
sp = (uintptr_t)emu->init_stack + R_ESP - (uintptr_t)stack_base;
|
||||
} else {
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base+stack_size-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
sp = (uintptr_t)stack_base+stack_size-size_to_copy;
|
||||
}
|
||||
}
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (p(8))?0:1);
|
||||
SetupX86Emu(newemu);
|
||||
CloneEmu(newemu, emu);
|
||||
Push32(newemu, 0);
|
||||
PushExit(newemu);
|
||||
newemu->regs[_SP].dword[0] = sp;
|
||||
void* mystack = NULL;
|
||||
if(my_context->stack_clone_used) {
|
||||
mystack = box_malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it
|
||||
@@ -879,19 +893,19 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
}
|
||||
// x86_64 raw clone is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls);
|
||||
long ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), u32(4), newemu, p(12), p(16), p(20));
|
||||
return (uint32_t)ret;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return (uint32_t)syscall(__NR_clone, u32(4), p(8), p(12), p(16), p(20));
|
||||
return syscall(__NR_clone, u32(4), p(8), p(12), p(16), p(20));
|
||||
break;
|
||||
case 123: // SYS_modify_ldt
|
||||
return my_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
|
||||
case 125: // mprotect
|
||||
return (uint32_t)my_mprotect(emu, p(4), u32(8), i32(12));
|
||||
return my_mprotect(emu, p(4), u32(8), i32(12));
|
||||
case 174: // sys_rt_sigaction
|
||||
return (uint32_t)my_syscall_sigaction(emu, i32(4), p(8), p(12), i32(16));
|
||||
return my_syscall_sigaction(emu, i32(4), p(8), p(12), i32(16));
|
||||
case 192: // mmap2
|
||||
return (uint32_t)my_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
|
||||
return (intptr_t)my_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
|
||||
case 243: // set_thread_area
|
||||
return my_set_thread_area((thread_area_t*)p(4));
|
||||
#ifndef NOALIGN
|
||||
@@ -918,12 +932,22 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
#endif
|
||||
#ifndef __NR_getrandom
|
||||
case 355: // getrandom
|
||||
return (uint32_t)my_getrandom(emu, p(4), u32(8), u32(12));
|
||||
return my_getrandom(emu, p(4), u32(8), u32(12));
|
||||
#endif
|
||||
#ifndef __NR_memfd_create
|
||||
case 356: // memfd_create
|
||||
return (uint32_t)my_memfd_create(emu, (void*)R_EBX, R_ECX);
|
||||
return my_memfd_create(emu, p(4), u32(8));
|
||||
#endif
|
||||
case 449:
|
||||
#ifdef __NR_futex_waitv
|
||||
if(box86_futex_waitv)
|
||||
return syscall(__NR_futex_waitv, u32(4), u32(8), u32(12), u32(16), u32(20));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
default:
|
||||
if(!(warned&(1<<s))) {
|
||||
printf_log(LOG_INFO, "Warning: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
@@ -932,5 +956,4 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+4
-4
@@ -75,16 +75,16 @@ void x86test_check(x86emu_t* ref, uintptr_t ip)
|
||||
for(int i=0; i<ref->fpu_stack; ++i) {
|
||||
if(ref->x87[(ref->top+i)&7].d != emu->x87[(emu->top+i)&7].d) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "ST%d: %g | %g\n", i, ref->x87[(ref->top+i)&7].d, emu->x87[(emu->top+i)&7].d);
|
||||
printf_log(LOG_NONE, "ST%d: %g (%a) | %g (%a)\n", i, ref->x87[(ref->top+i)&7].d, ref->x87[(ref->top+i)&7].d, emu->x87[(emu->top+i)&7].d, emu->x87[(emu->top+i)&7].d);
|
||||
}
|
||||
}
|
||||
}
|
||||
//memcpy(ref->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
//memcpy(ref->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
/*if(ref->p_regs != emu->p_regs) {
|
||||
if(ref->fpu_tags != emu->fpu_tags) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 PREG: %x | %x\n", ref->p_regs, emu->p_regs);
|
||||
}*/
|
||||
printf_log(LOG_NONE, "X87 TAGS: %x | %x\n", ref->fpu_tags, emu->fpu_tags);
|
||||
}
|
||||
if(ref->cw.x16 != emu->cw.x16) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 CW: %x | %x\n", ref->cw.x16, emu->cw.x16);
|
||||
|
||||
+5
-3
@@ -217,7 +217,9 @@ void* resizeTLSData(box86context_t *context, void* oldptr)
|
||||
mutex_lock(&context->mutex_tls);
|
||||
tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr;
|
||||
if(sizeTLSData(oldata->tlssize)!=sizeTLSData(context->tlssize) || (oldata->n_elfs/0xff)!=(context->elfsize/0xff)) {
|
||||
printf_log(LOG_INFO, "Warning, resizing of TLS occured! size: %d->%d / n_elfs: %d->%d\n", sizeTLSData(oldata->tlssize), sizeTLSData(context->tlssize), 1+(oldata->n_elfs/0xff), 1+(context->elfsize/0xff));
|
||||
if(sizeTLSData(oldata->tlssize)) {
|
||||
printf_log(LOG_INFO, "Warning, resizing of TLS occured! size: %d->%d / n_elfs: %d->%d\n", sizeTLSData(oldata->tlssize), sizeTLSData(context->tlssize), 1+(oldata->n_elfs/0xff), 1+(context->elfsize/0xff));
|
||||
}
|
||||
tlsdatasize_t *data = setupTLSData(context);
|
||||
// copy the relevent old part, in case something changed
|
||||
memcpy((void*)((uintptr_t)data->data-oldata->tlssize), (void*)((uintptr_t)oldata->data-oldata->tlssize), oldata->tlssize);
|
||||
@@ -239,8 +241,8 @@ void* resizeTLSData(box86context_t *context, void* oldptr)
|
||||
for (int i=oldata->n_elfs; i<context->elfsize; ++i) {
|
||||
// set pointer
|
||||
dtp = (uintptr_t)ptr + GetTLSBase(context->elfs[i]);
|
||||
*(uint64_t*)((uintptr_t)ptr+POS_TLS+i*8) = dtp;
|
||||
*(uint64_t*)((uintptr_t)ptr+POS_TLS+i*8+4) = i; // index
|
||||
*(uint32_t*)((uintptr_t)ptr+POS_TLS+i*8) = dtp;
|
||||
*(uint32_t*)((uintptr_t)ptr+POS_TLS+i*8+4) = i; // index
|
||||
}
|
||||
oldata->n_elfs = context->elfsize;
|
||||
}
|
||||
|
||||
+49
-64
@@ -1,3 +1,4 @@
|
||||
#include <fenv.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -17,8 +18,7 @@ void reset_fpu(x86emu_t* emu)
|
||||
emu->sw.x16 = 0x0000;
|
||||
emu->top = 0;
|
||||
emu->fpu_stack = 0;
|
||||
for(int i=0; i<8; ++i)
|
||||
emu->p_regs[i].tag = 0b11; // STx is empty
|
||||
emu->fpu_tags = TAGS_EMPTY;
|
||||
}
|
||||
|
||||
void fpu_fbst(x86emu_t* emu, uint8_t* d) {
|
||||
@@ -77,53 +77,45 @@ void LD2D(void* ld, void* d)
|
||||
*(uint64_t*)d = *(uint64_t*)ld;
|
||||
return;
|
||||
}
|
||||
FPU_t result;
|
||||
FPU_t result;
|
||||
#pragma pack(push, 1)
|
||||
struct {
|
||||
FPU_t f;
|
||||
int16_t b;
|
||||
} val;
|
||||
struct {
|
||||
FPU_t f;
|
||||
int16_t b;
|
||||
} val;
|
||||
#pragma pack(pop)
|
||||
#if 1
|
||||
memcpy(&val, ld, 10);
|
||||
#else
|
||||
val.f.ud[0] = *(uint32_t*)ld;
|
||||
val.f.ud[0] = *(uint32_t*)ld;
|
||||
val.f.ud[1] = *(uint32_t*)(char*)(ld+4);
|
||||
val.b = *(int16_t*)((char*)ld+8);
|
||||
val.b = *(int16_t*)((char*)ld+8);
|
||||
#endif
|
||||
int32_t exp64 = (((uint32_t)(val.b&0x7fff) - BIAS80) + BIAS64);
|
||||
int32_t exp64final = exp64&0x7ff;
|
||||
// do specific value first (0, infinite...)
|
||||
// bit 63 is "integer part"
|
||||
// bit 62 is sign
|
||||
if((uint32_t)(val.b&0x7fff)==0x7fff) {
|
||||
// infinity and nans
|
||||
int t = 0; //nan
|
||||
switch((val.f.ud[1]>>30)) {
|
||||
case 0: if((val.f.ud[1]&(1<<29))==0) t = 1;
|
||||
break;
|
||||
case 2: if((val.f.ud[1]&(1<<29))==0) t = 1;
|
||||
break;
|
||||
}
|
||||
int t = (val.f.q&0x7fffffffffffffffLL)?0:1;
|
||||
if(t) { // infinite
|
||||
result.d = HUGE_VAL;
|
||||
} else { // NaN
|
||||
result.ud[1] = 0x7ff << 20;
|
||||
result.ud[1] = (val.b>>4) << 20;
|
||||
result.ud[0] = 0;
|
||||
} else { // NaN
|
||||
result.ud[1] = (val.b>>4) << 20 | ((val.f.q>>(63-20))&0x000fffff);
|
||||
result.ud[0] = (val.f.q>>(63-56))&0xffffffff;
|
||||
if(!(result.q&0x000fffffffffffffLL))
|
||||
result.q |= 1;
|
||||
}
|
||||
if(val.b&0x8000)
|
||||
result.ud[1] |= 0x80000000;
|
||||
*(uint64_t*)d = result.q;
|
||||
return;
|
||||
}
|
||||
int32_t exp64 = (((uint32_t)(val.b&0x7fff) - BIAS80) + BIAS64);
|
||||
int32_t exp64final = exp64&0x7ff;
|
||||
if(((uint32_t)(val.b&0x7fff)==0) || (exp64<-1074)) {
|
||||
//if(val.f.ll==0)
|
||||
//if(val.f.q==0)
|
||||
// zero
|
||||
//if(val.f.ll!=0)
|
||||
//if(val.f.q!=0)
|
||||
// denormal, but that's to small value for double
|
||||
uint64_t r = 0;
|
||||
if(val.b&0x8000)
|
||||
r |= 0x8000000000000000LL;
|
||||
uint64_t r = (val.b&0x8000)?0x8000000000000000LL:0LL;
|
||||
*(uint64_t*)d = r;
|
||||
return;
|
||||
}
|
||||
@@ -149,12 +141,12 @@ void LD2D(void* ld, void* d)
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t mant64 = (val.f.q >> 11) & 0xfffffffffffffLL;
|
||||
uint32_t sign = (val.b&0x8000)?1:0;
|
||||
uint64_t mant64 = (val.f.q >> 11) & 0xfffffffffffffL;
|
||||
uint32_t sign = (val.b&0x8000)?1:0;
|
||||
result.q = mant64;
|
||||
result.ud[1] |= (sign <<31)|((exp64final&0x7ff) << 20);
|
||||
result.ud[1] |= (sign <<31)|((exp64final&0x7ff) << 20);
|
||||
|
||||
*(uint64_t*)d = result.q;
|
||||
*(uint64_t*)d = result.q;
|
||||
}
|
||||
|
||||
// double (64bits) -> long double (80bits)
|
||||
@@ -165,40 +157,37 @@ void D2LD(void* d, void* ld)
|
||||
return;
|
||||
}
|
||||
#pragma pack(push, 1)
|
||||
struct {
|
||||
FPU_t f;
|
||||
int16_t b;
|
||||
} val;
|
||||
struct {
|
||||
FPU_t f;
|
||||
int16_t b;
|
||||
} val;
|
||||
#pragma pack(pop)
|
||||
FPU_t s;
|
||||
s.q = *(uint64_t*)d; // use memcpy to avoid risk of Bus Error?
|
||||
// do special value first
|
||||
if((s.q&0x7fffffffffffffffLL)==0) {
|
||||
if((s.q&0x7fffffffffffffffL)==0) {
|
||||
// zero...
|
||||
val.f.q = 0;
|
||||
if(s.ud[1]&0x8000)
|
||||
val.b = 0x8000;
|
||||
else
|
||||
val.b = 0;
|
||||
val.b = (s.ud[1]&0x80000000)?0x8000:0;
|
||||
memcpy(ld, &val, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t sign80 = (s.ud[1]&0x80000000)?1:0;
|
||||
int32_t exp80 = s.ud[1]&0x7ff00000;
|
||||
int32_t exp80final = (exp80>>20);
|
||||
int64_t mant80 = s.sq&0x000fffffffffffffLL;
|
||||
int64_t mant80final = (mant80 << 11);
|
||||
int32_t sign80 = (s.ud[1]&0x80000000)?1:0;
|
||||
int32_t exp80 = s.ud[1]&0x7ff00000;
|
||||
int32_t exp80final = (exp80>>20);
|
||||
uint64_t mant80 = s.q&0x000fffffffffffffL;
|
||||
uint64_t mant80final = (mant80 << 11);
|
||||
if(exp80final==0x7ff) {
|
||||
// NaN and Infinite
|
||||
exp80final = 0x7fff;
|
||||
if(mant80==0x0)
|
||||
mant80final = 0x8000000000000000LL; //infinity
|
||||
mant80final = 0x8000000000000000L; //infinity
|
||||
else
|
||||
mant80final = 0xc000000000000000LL; //(quiet)NaN
|
||||
mant80final |= 0x8000000000000000L; //(quiet)NaN
|
||||
} else {
|
||||
if(exp80!=0){
|
||||
mant80final |= 0x8000000000000000LL;
|
||||
mant80final |= 0x8000000000000000L;
|
||||
exp80final += (BIAS80 - BIAS64);
|
||||
} else if(mant80final!=0) {
|
||||
// denormals -> normal
|
||||
@@ -208,8 +197,8 @@ void D2LD(void* d, void* ld)
|
||||
mant80final<<=one;
|
||||
}
|
||||
}
|
||||
val.b = ((int16_t)(sign80)<<15)| (int16_t)(exp80final);
|
||||
val.f.sq = mant80final;
|
||||
val.b = ((int16_t)(sign80)<<15)| (int16_t)(exp80final);
|
||||
val.f.q = mant80final;
|
||||
memcpy(ld, &val, 10);
|
||||
/*memcpy(ld, &f.ll, 8);
|
||||
memcpy((char*)ld + 8, &val.b, 2);*/
|
||||
@@ -248,9 +237,7 @@ void fpu_loadenv(x86emu_t* emu, char* p, int b16)
|
||||
p+=(b16)?2:4;
|
||||
// tagword: 2bits*8
|
||||
// tags... (only full = 0b11 / free = 0b00)
|
||||
uint16_t tags = *(uint16_t*)p;
|
||||
for(int i=0; i<8; ++i)
|
||||
emu->p_regs[i].tag = (tags>>(i*2))&0b11;
|
||||
emu->fpu_tags = *(uint16_t*)p;
|
||||
// intruction pointer: 16bits
|
||||
// data (operand) pointer: 16bits
|
||||
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
|
||||
@@ -267,10 +254,7 @@ void fpu_savenv(x86emu_t* emu, char* p, int b16)
|
||||
if(!b16) {*(uint16_t*)p = 0; p+=2;}
|
||||
// tagword: 2bits*8
|
||||
// tags...
|
||||
uint16_t tags = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
tags |= (emu->p_regs[i].tag)<<(i*2);
|
||||
*(uint16_t*)p = tags;
|
||||
*(uint16_t*)p = emu->fpu_tags;
|
||||
// other stuff are not pushed....
|
||||
}
|
||||
|
||||
@@ -300,7 +284,7 @@ void fpu_fxsave(x86emu_t* emu, void* ed)
|
||||
int top = emu->top&7;
|
||||
int stack = 8-top;
|
||||
if(top==0) // check if stack is full or empty, based on tag[0]
|
||||
stack = (emu->p_regs[0].tag)?8:0;
|
||||
stack = (emu->fpu_tags)?8:0;
|
||||
emu->sw.f.F87_TOP = top;
|
||||
p->ControlWord = emu->cw.x16;
|
||||
p->StatusWord = emu->sw.x16;
|
||||
@@ -308,7 +292,7 @@ void fpu_fxsave(x86emu_t* emu, void* ed)
|
||||
p->MxCsr_Mask = 0;
|
||||
uint8_t tags = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
tags |= (emu->p_regs[i].tag==0b11)?0:(1<<(i*2));
|
||||
tags |= (((emu->fpu_tags>>(i*2))&0b11)?0:1)<<i;
|
||||
p->TagWord = tags;
|
||||
p->ErrorOpcode = 0;
|
||||
p->ErrorOffset = 0;
|
||||
@@ -330,13 +314,14 @@ void fpu_fxrstor(x86emu_t* emu, void* ed)
|
||||
emu->mxcsr.x32 = p->MxCsr;
|
||||
emu->top = emu->sw.f.F87_TOP;
|
||||
uint8_t tags = p->TagWord;
|
||||
emu->fpu_tags = 0;
|
||||
for(int i=0; i<8; ++i)
|
||||
emu->p_regs[i].tag = ((tags>>(i*2))&0b1)?0:0b11;
|
||||
emu->fpu_tags |= (((tags>>i)&0b1)?0:0b11)<<(i*2);
|
||||
// copy back MMX regs...
|
||||
int top = emu->top&7;
|
||||
int stack = 8-top;
|
||||
if(top==0) // check if stack is full or empty, based on tag[0]
|
||||
stack = (emu->p_regs[0].tag)?8:0;
|
||||
stack = (emu->fpu_tags)?0:8;
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy((i<stack)?&ST(i):&emu->mmx[i], &p->FloatRegisters[i].q[0], sizeof(mmx87_regs_t));
|
||||
// copy SSE regs
|
||||
@@ -345,7 +330,7 @@ void fpu_fxrstor(x86emu_t* emu, void* ed)
|
||||
|
||||
void fpu_fxam(x86emu_t* emu) {
|
||||
emu->sw.f.F87_C1 = (ST0.ud[1]&0x80000000)?1:0;
|
||||
if(emu->p_regs[emu->top].tag == 0b11) {
|
||||
if((emu->fpu_stack<=0) || (emu->fpu_tags&0b11)) {
|
||||
//Empty
|
||||
emu->sw.f.F87_C3 = 1;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
|
||||
@@ -14,6 +14,8 @@ typedef struct x86emu_s x86emu_t;
|
||||
#define LN2 0.69314718055994531
|
||||
#define LG2 0.3010299956639812
|
||||
|
||||
#define TAGS_EMPTY 0b1111111111111111
|
||||
|
||||
#define ST0 emu->x87[emu->top]
|
||||
#define ST1 emu->x87[(emu->top+1)&7]
|
||||
#define ST(a) emu->x87[(emu->top+(a))&7]
|
||||
@@ -36,7 +38,8 @@ static inline void fpu_do_push(x86emu_t* emu)
|
||||
return;
|
||||
}
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
emu->p_regs[newtop].tag = 0; // full
|
||||
emu->fpu_tags<<=2; // st0 full
|
||||
emu->fpu_tags &= TAGS_EMPTY;
|
||||
emu->top = newtop;
|
||||
}
|
||||
|
||||
@@ -51,17 +54,24 @@ static inline void fpu_do_pop(x86emu_t* emu)
|
||||
if(emu->fpu_stack>0)
|
||||
--emu->fpu_stack;
|
||||
|
||||
emu->p_regs[curtop].tag = 0b11; // empty
|
||||
emu->fpu_tags>>=2;
|
||||
emu->fpu_tags |= 0b1100000000000000; // top empty
|
||||
emu->top = (emu->top+1)&7;
|
||||
// check tags
|
||||
/*while((emu->fpu_tags&0b11) && emu->fpu_stack) {
|
||||
--emu->fpu_stack;
|
||||
emu->top = (emu->top+1)&7;
|
||||
emu->fpu_tags>>=2;
|
||||
emu->fpu_tags |= 0b1100000000000000; // top empty
|
||||
}*/
|
||||
}
|
||||
|
||||
static inline void fpu_do_free(x86emu_t* emu, int i)
|
||||
{
|
||||
emu->p_regs[(emu->top+i)&7].tag = 0b11; // empty
|
||||
emu->fpu_tags |= 0b11 << (i); // empty
|
||||
// check if all empty
|
||||
for(int i=0; i<8; ++i)
|
||||
if(emu->p_regs[i].tag != 0b11)
|
||||
return;
|
||||
if(emu->fpu_tags != TAGS_EMPTY)
|
||||
return;
|
||||
emu->fpu_stack = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef __SETROUND_H__
|
||||
#define __SETROUND_H__
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#include <fenv.h>
|
||||
#include <stdint.h>
|
||||
#include "x86emu.h"
|
||||
#include "x86emu_private.h"
|
||||
// set the rounding mode to the emulator's one, and return the old one
|
||||
static inline int fpu_setround(x86emu_t* emu) {
|
||||
int ret = fegetround();
|
||||
int rounding_direction;
|
||||
switch (emu->cw.f.C87_RD) {
|
||||
case ROUND_Nearest:
|
||||
rounding_direction = FE_TONEAREST;
|
||||
break;
|
||||
case ROUND_Down:
|
||||
rounding_direction = FE_DOWNWARD;
|
||||
break;
|
||||
case ROUND_Up:
|
||||
rounding_direction = FE_UPWARD;
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
rounding_direction = FE_TOWARDZERO;
|
||||
break;
|
||||
}
|
||||
fesetround(rounding_direction);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
Loaded 100 of 297 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user