mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-09 04:09:45 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41749db028 | ||
|
|
e30f302de9 | ||
|
|
d119ed10b9 | ||
|
|
9281289a1b | ||
|
|
1683c0c679 | ||
|
|
88a8b9569d | ||
|
|
18aaa03381 | ||
|
|
aa3474d06e | ||
|
|
0accab638f | ||
|
|
29b52bc12e | ||
|
|
5840cd3402 | ||
|
|
926ff0f4f8 | ||
|
|
13689e7eac | ||
|
|
e4ed4ad3a8 | ||
|
|
1e6037019e | ||
|
|
da083aaab4 | ||
|
|
7a7853d434 | ||
|
|
eebe12ca27 | ||
|
|
7aaade8780 | ||
|
|
cb185d4d44 | ||
|
|
3f691dc4f0 | ||
|
|
d4c33f71eb | ||
|
|
ad106a07ea | ||
|
|
2ad3a0a7f5 | ||
|
|
dc461d4de6 | ||
|
|
d1a9b50dfe | ||
|
|
9a0da8d011 | ||
|
|
2d7e3877e7 | ||
|
|
0248ae0a96 | ||
|
|
9fd27f3b2c | ||
|
|
4152fcc934 | ||
|
|
53c887a06a | ||
|
|
316e10baa0 | ||
|
|
8a71c6bc4a | ||
|
|
9b806de7b0 | ||
|
|
a14dadc228 | ||
|
|
ca850b3d30 | ||
|
|
c01dbbea0e | ||
|
|
b883307881 | ||
|
|
ab9bcb1e0b | ||
|
|
3dc22ff0b8 | ||
|
|
5e382e12ad | ||
|
|
103e55ff97 | ||
|
|
6140b3eee8 | ||
|
|
09574a69e9 | ||
|
|
c53f961e12 | ||
|
|
a1d370fc04 | ||
|
|
471b679d3f | ||
|
|
e60caa8648 | ||
|
|
ccfc8a8d30 | ||
|
|
6a7b7bec6a | ||
|
|
0926c48aea | ||
|
|
d10a9e40ed | ||
|
|
4df12ee5ea | ||
|
|
433294fb40 | ||
|
|
298fe50dd1 | ||
|
|
1717fffe8f | ||
|
|
41521913d5 | ||
|
|
e75ca5d2ff | ||
|
|
0d2081ed30 | ||
|
|
d6abdc2a55 | ||
|
|
0a0cf77461 | ||
|
|
a5c438068c | ||
|
|
d2c8839a69 | ||
|
|
21b560a3b9 | ||
|
|
b1d8de62d4 | ||
|
|
1e41857d37 | ||
|
|
63920e95d3 | ||
|
|
7856b2b7ee | ||
|
|
5daf34ba29 | ||
|
|
e513cbeaaa | ||
|
|
c782ba2429 | ||
|
|
50dae3f5d8 | ||
|
|
d3e6551b40 | ||
|
|
0e1d1a788d | ||
|
|
dfafce7f05 | ||
|
|
eb7381457a | ||
|
|
2f8baf9559 | ||
|
|
34cb03c7df | ||
|
|
d76ecb8a38 | ||
|
|
943c2a0bd9 | ||
|
|
a7552c8bb8 | ||
|
|
8cd78041a2 | ||
|
|
3fe3499ec2 | ||
|
|
70c49f67c4 | ||
|
|
308c316dbf | ||
|
|
c660b3a9aa | ||
|
|
642bb357d3 | ||
|
|
4978177584 | ||
|
|
ae8a69a840 | ||
|
|
383c2be9fc | ||
|
|
1cc4653672 | ||
|
|
6b6daba17a | ||
|
|
d8eb090a7a | ||
|
|
eb2e96f13b | ||
|
|
41201cbb96 | ||
|
|
151115ed10 | ||
|
|
7d4154e0d4 | ||
|
|
7a470daa26 | ||
|
|
a4e40d06ac | ||
|
|
875efd2a42 | ||
|
|
9ee0ac92c3 | ||
|
|
c7f554bebb | ||
|
|
6fe8d71e61 | ||
|
|
f6f24bce25 | ||
|
|
8b81151ec1 | ||
|
|
55033ed25e | ||
|
|
a829a60341 | ||
|
|
0a25e78964 | ||
|
|
dec1acdfb1 | ||
|
|
4f0970138b | ||
|
|
4707997aec | ||
|
|
ae5a4b5f4f | ||
|
|
5187b55a2e | ||
|
|
60078852bd | ||
|
|
580bacaf93 | ||
|
|
eb1ab920cf | ||
|
|
6c0aabd36e | ||
|
|
a3d2443b70 | ||
|
|
313ca172a5 | ||
|
|
ceb4e53f15 | ||
|
|
4510b4997a | ||
|
|
12cc43bd7c | ||
|
|
21069c107a | ||
|
|
93032afe0f | ||
|
|
f422fe13f4 | ||
|
|
ed551d1eb3 | ||
|
|
58cd4119a6 | ||
|
|
c8147ce3d4 | ||
|
|
00df171604 | ||
|
|
50ca38d4d0 | ||
|
|
e31e5c1a5b | ||
|
|
c80356a90a | ||
|
|
4909b039c0 | ||
|
|
dc8ee2718b | ||
|
|
8118f4ad18 | ||
|
|
de422a0d93 | ||
|
|
cbffa01014 | ||
|
|
f8688c33a0 | ||
|
|
6e0e56b85e | ||
|
|
7e81522ed4 | ||
|
|
0c8a76fceb | ||
|
|
35273abff7 | ||
|
|
6c1f3ea4bf | ||
|
|
5e261e0d7f | ||
|
|
53553ece6f | ||
|
|
33d47ff1c8 | ||
|
|
16b8657a47 | ||
|
|
264c834c2c | ||
|
|
28b05465ea | ||
|
|
b903e57ef9 | ||
|
|
d5ffba47a2 | ||
|
|
34b99bfede | ||
|
|
4f5aac8f50 | ||
|
|
fe53eeb010 | ||
|
|
67b6f69926 | ||
|
|
6bf62a3d4e | ||
|
|
54b911550f | ||
|
|
31a988877a | ||
|
|
88642d81c0 | ||
|
|
135e8d98e9 | ||
|
|
bd5c8fd403 | ||
|
|
3b112793aa | ||
|
|
2fc8d9ae4f | ||
|
|
afe63f02fa | ||
|
|
6aa744dff9 | ||
|
|
095b04d31c | ||
|
|
6136fe0c8b | ||
|
|
e2f3752018 | ||
|
|
5d0fdf01f3 | ||
|
|
cb4b6bc76d | ||
|
|
bb0f57b5ab | ||
|
|
c23981b97f | ||
|
|
c005fc6754 | ||
|
|
8d24048c26 | ||
|
|
ac1ae9f9db | ||
|
|
53e8a40e1b | ||
|
|
a7d803bc82 | ||
|
|
944ae100fa | ||
|
|
b68fd36476 | ||
|
|
74d530d65e | ||
|
|
b5cf71c7af | ||
|
|
8d663f80bd | ||
|
|
77257e2532 | ||
|
|
44d6719107 | ||
|
|
05ddaa6356 | ||
|
|
d8a6b6528a | ||
|
|
478c781822 | ||
|
|
93039252f2 | ||
|
|
3efc3ebe25 | ||
|
|
1f5824a55b | ||
|
|
d364c2f53e | ||
|
|
7d0bc98e3e | ||
|
|
85e0b26a53 | ||
|
|
c3f21c8af2 | ||
|
|
8bd2148ae4 | ||
|
|
2c74cef483 | ||
|
|
3a1911f5cd | ||
|
|
d871886ec5 | ||
|
|
146a2e8aae | ||
|
|
727784d90a | ||
|
|
67647bc51e | ||
|
|
3ce9d84669 | ||
|
|
af6ed6c296 | ||
|
|
3f65c0593f | ||
|
|
98e7941371 | ||
|
|
3fb5eb3ec9 | ||
|
|
497c748955 | ||
|
|
230247af17 | ||
|
|
bbea40833b | ||
|
|
146ca6a9c9 | ||
|
|
fb7e8c730c | ||
|
|
e5135ae67b | ||
|
|
f1b524460e | ||
|
|
9c9c910fa8 | ||
|
|
63330cbb84 | ||
|
|
5c6816f8ab | ||
|
|
4c0366e340 | ||
|
|
38e2e4e16a | ||
|
|
430b24c0f3 | ||
|
|
b22b187ce0 | ||
|
|
cc32d6cb98 | ||
|
|
66332ae9e2 | ||
|
|
b6dd3acfea | ||
|
|
b655e89af0 | ||
|
|
2879cf51cd | ||
|
|
725dabea88 | ||
|
|
35f133cacd | ||
|
|
b0e4f2c696 | ||
|
|
65c423917e | ||
|
|
f128af26ec | ||
|
|
1bf955baa8 | ||
|
|
cee2ff2641 | ||
|
|
819cd6c3e2 | ||
|
|
67da32857a | ||
|
|
6796145fa9 | ||
|
|
fea1bcc123 | ||
|
|
b6125b8063 | ||
|
|
ad397bb1b6 | ||
|
|
dc333f052d | ||
|
|
a77e120fc2 | ||
|
|
07166e591e | ||
|
|
a1aac43a4e | ||
|
|
cc69471576 | ||
|
|
ed8e01ea0c | ||
|
|
4fb847196c | ||
|
|
40ee2cb868 | ||
|
|
8d0b2edba2 | ||
|
|
3b6e10a1f9 | ||
|
|
4d4a849c9b | ||
|
|
58f94fe9ec | ||
|
|
ebff6f995a | ||
|
|
5a8a4bb25b | ||
|
|
6d8e781c72 | ||
|
|
834374d0f2 | ||
|
|
f0d17b1f86 | ||
|
|
5478879a37 | ||
|
|
4e2f50eee7 | ||
|
|
c47e25bef3 | ||
|
|
b5203b97bb | ||
|
|
a7ac9a0aa8 | ||
|
|
0540efa171 | ||
|
|
b3b274acf7 | ||
|
|
944ffcb788 | ||
|
|
865baf0d5f | ||
|
|
8b555503c1 | ||
|
|
11bb6bb2aa | ||
|
|
63864adbda | ||
|
|
0d89989c20 | ||
|
|
59d4821bdc | ||
|
|
24ecba3e9e | ||
|
|
d9f9b86996 | ||
|
|
c27febf172 | ||
|
|
d18af9daf8 | ||
|
|
4813a35eec | ||
|
|
5bd33084dd | ||
|
|
939c54792f | ||
|
|
28f6f58dd7 | ||
|
|
27fd1d11b8 | ||
|
|
39355d3bd6 | ||
|
|
1582b486db | ||
|
|
e4d58dd9cb | ||
|
|
f417d640e0 | ||
|
|
f79e16f48d | ||
|
|
365daab33c | ||
|
|
62fceaaa3c | ||
|
|
5af78fb18a | ||
|
|
2dae632d24 | ||
|
|
680e460ecd | ||
|
|
07e715bb6d | ||
|
|
e255bc0874 | ||
|
|
0d0129e7c3 | ||
|
|
3ca24bd45c | ||
|
|
a627363afa | ||
|
|
bcf6ca9e52 | ||
|
|
561579a7d6 |
No files matched your search
@@ -0,0 +1,100 @@
|
||||
### Manual build Box86 with Github Action
|
||||
name: Custom build Box86
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
platform:
|
||||
description: 'Target platform name'
|
||||
required: true
|
||||
default: 'GENERIC_ARM'
|
||||
type: choice
|
||||
options:
|
||||
- I386
|
||||
- GENERIC_ARM
|
||||
- A64
|
||||
- GAMESHELL
|
||||
- ODROID
|
||||
- PANDORA
|
||||
- PHYTIUM
|
||||
- PYRA
|
||||
- RK3288
|
||||
- RK3399
|
||||
- RPI4
|
||||
- RPI4ARM64
|
||||
- SD845
|
||||
build_type:
|
||||
description: 'Build type'
|
||||
required: true
|
||||
default: 'RelWithDebInfo'
|
||||
type: choice
|
||||
options:
|
||||
- RelWithDebInfo
|
||||
- Release
|
||||
- Debug
|
||||
- MinSizeRel
|
||||
dynarec:
|
||||
description: 'Enable dynarec'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
trace:
|
||||
description: 'Enable trace'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box86 Repository"
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ github.event.inputs.platform }} != 'I386' && ${{ github.event.inputs.platform }} != 'GENERIC_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ github.event.inputs.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
else
|
||||
if [[ ${{ github.event.inputs.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
else
|
||||
echo "BOX86_PLATFORM_MARCRO=-DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ github.event.inputs.build_type }}"
|
||||
echo "Dynarec Enabled: ${{ github.event.inputs.dynarec }}"
|
||||
echo "Trace Enabled: ${{ github.event.inputs.trace }}"
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }}\
|
||||
-DARM_DYNAREC:BOOL=${{ github.event.inputs.dynarec }}\
|
||||
-DHAVE_TRACE:BOOL=${{ github.event.inputs.trace }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box86-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
### Auto build Box86 and release its binary with Github Action
|
||||
name: Build and Release Box86
|
||||
|
||||
on:
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
push:
|
||||
@@ -10,16 +10,16 @@ on:
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
pull_request:
|
||||
pull_request:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
|
||||
jobs:
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM]
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM, ANDROID]
|
||||
type: [Release, Trace]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
@@ -40,15 +40,22 @@ jobs:
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ matrix.platform }} != 'I386' && ${{ matrix.platform }} != 'OTHER_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
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
|
||||
else
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
ls /bin/*gcc*
|
||||
else
|
||||
echo BOX86_PLATFORM_MARCRO="-DARM_DYNAREC=ON -DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
@@ -63,26 +70,36 @@ jobs:
|
||||
echo BOX86_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
|
||||
echo BOX86_HAVE_TRACE=1 >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ env.BOX86_BUILD_TYPE }}"
|
||||
echo "Trace Enabled: ${{ env.BOX86_HAVE_TRACE }}"
|
||||
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }} -DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }} -DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }}\
|
||||
${{ env.BOX86_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
|
||||
- name: "Test Box86"
|
||||
if: ${{ matrix.platform == 'I386' }}
|
||||
run: |
|
||||
cd build
|
||||
ctest -j$(nproc)
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box86-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
|
||||
+74
-36
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
|
||||
option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
|
||||
@@ -9,6 +9,7 @@ option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch a
|
||||
option(GOA_CLONE "Set to ON if targeting GO Advance clones, like RG351p/v, Gameforce Chi, RGB10..." ${GOA_CLONE})
|
||||
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(ODROIDN2 "Set to ON if targeting an Odroid-N2 device" ${ODROIDN2})
|
||||
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})
|
||||
@@ -21,7 +22,7 @@ option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR ODROIDN2 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
@@ -51,7 +52,13 @@ else()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
|
||||
if(RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
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 RPI4ARM64 OR PHYTIUM OR SD845 OR A64))
|
||||
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)
|
||||
@@ -123,10 +130,16 @@ elseif(RK3399)
|
||||
add_definitions(-DRK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ODROIDN2)
|
||||
add_definitions(-DODROIDN2)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+simd+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")
|
||||
@@ -157,6 +170,7 @@ endif()
|
||||
|
||||
if(NOALIGN)
|
||||
add_definitions(-DNOALIGN)
|
||||
add_definitions(-pipe -march=core2 -msse2)
|
||||
endif()
|
||||
|
||||
if(HAVE_TRACE)
|
||||
@@ -358,6 +372,8 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgmp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgcrypt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtk3.c"
|
||||
@@ -370,6 +386,12 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgconf2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstvideo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgsttag.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstbase.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstapp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
|
||||
@@ -409,8 +431,17 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsoftokn3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfreebl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsecret1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedmimalloc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedselinux.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibcairogobject.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibvkd3d.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgomp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcap.c"
|
||||
)
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
@@ -495,6 +526,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_df.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f0.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_660f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_66f0.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f20f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f30f.c"
|
||||
)
|
||||
@@ -552,7 +584,7 @@ if(ARM_DYNAREC)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} dynarec m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread)
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread resolv)
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
@@ -572,9 +604,10 @@ add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} m dl)
|
||||
target_link_libraries(${BOX86} c m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
#target_link_libraries(${BOX86} c m dl rt pthread resolv)
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec)
|
||||
@@ -593,11 +626,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "armhf" _armhf)
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION bin)
|
||||
@@ -606,6 +634,7 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
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/)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
@@ -649,105 +678,114 @@ set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVIS
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
if(NOT LD80BITS)
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
|
||||
add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME ucomiss COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile.txt
|
||||
add_test(NAME sse COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTNAN=0")
|
||||
|
||||
add_test(NAME longjumpInSignals COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile.txt
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME idiv COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile20.txt
|
||||
-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")
|
||||
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.txt
|
||||
-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()
|
||||
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
box86 (0.2.6) unstable; urgency=low
|
||||
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
* Many small fixes and improvement to get steam and SteamPlay working (along with box64)
|
||||
* Added some workaround for program calling uname to mimic x86 system
|
||||
* Added some more Vulkan extensions
|
||||
* Added some granularity to mmap64, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* - better handling of SSE/x87 registers
|
||||
* - optimisation to limit float/double conversion
|
||||
* - better handling of "internal" jump inside a dynablock
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
11
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
Source: box86
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Ryan Fortner <[email protected]>
|
||||
Build-Depends: cmake, debhelper (>=11~)
|
||||
Standards-Version: 4.1.4
|
||||
Homepage: https://github.com/ptitSeb/box86
|
||||
|
||||
Package: box86
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
Format-Specification: http://dep.debian.net/deps/dep5/
|
||||
|
||||
Files: *
|
||||
Copyright: © 2022 Sebastien Chevalier
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
|
||||
.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
box86: no-manual-page
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.5 --exclude=libstdc++.so.6
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
Bug-Database: https://github.com/ptitSeb/box86/issues
|
||||
Bug-Submit: https://github.com/ptitSeb/box86/issues/new
|
||||
Repository: https://github.com/ptitSeb/box86.git
|
||||
Repository-Browse: https://github.com/ptitSeb/box86
|
||||
Security-Contact: [email protected]
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
version=3
|
||||
@@ -1,3 +1,25 @@
|
||||
v0.2.6
|
||||
======
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
* Many small fixes and improvement to get steam and SteamPlay working (along with box64)
|
||||
* Added some workaround for program calling uname to mimic x86 system
|
||||
* Added some more Vulkan extensions
|
||||
* Added some granularity to mmap64, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* better handling of SSE/x87 registers
|
||||
* optimisation to limit float/double conversion
|
||||
* better handling of "internal" jump inside a dynablock
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
|
||||
v0.2.4
|
||||
======
|
||||
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
|
||||
|
||||
+10
-3
@@ -47,7 +47,7 @@ sudo systemctl restart systemd-binfmt
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most RK3399 device run 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 RK3399 device run 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 also use `sudo apt install libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other similar file not found at link.
|
||||
|
||||
#### for Tinker Board (1/1S) or RK3288
|
||||
|
||||
@@ -57,7 +57,7 @@ As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environme
|
||||
|
||||
`mkdir build; cd build; cmake .. -DA64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most Allwinner A64 device run 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 Allwinner A64 device run 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 also use `sudo apt install libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other similar file not found at link.
|
||||
|
||||
#### for Snapdragon 845
|
||||
|
||||
@@ -69,7 +69,7 @@ As most Snapdragon 845 device run AARCH64 OS, in most cases you'll need an `armh
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian/ubuntu, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian/ubuntu, install it with `sudo apt install gcc-arm-linux-gnueabihf`. Also, on armbian, you may need to also use `sudo apt install libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other similar file not found at link.
|
||||
|
||||
#### for Other ARM Linux platforms
|
||||
|
||||
@@ -118,3 +118,10 @@ They are very basic and don't test much for now.
|
||||
Note about devices with Tegra X1 and newer.
|
||||
|
||||
Nvidia don't provide armhf libraries for their GPU drivers at this moment so there is no special variable to compile it for them as it would be missleading for many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. As instalation of Mesa can break Nvidia driver, safest option is usage of chroot.
|
||||
|
||||
----
|
||||
|
||||
Debian Packaging
|
||||
----
|
||||
Box86 can also be packaged into a .deb file with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`.
|
||||
|
||||
+23
-19
@@ -1,22 +1,18 @@
|
||||
# box86
|
||||
|
||||

|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[](https://app.travis-ci.com/ptitSeb/box86)
|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
[View changelog](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Report an error](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environment).
|
||||
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at those bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary. (Most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android).)
|
||||
|
||||
@@ -29,13 +25,21 @@ To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
|
||||
|
||||
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
----
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
----
|
||||
|
||||
Here are 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
You can find many more Box86 video on Youtube in the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) Channels
|
||||
You can find many more Box86 videos on the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube channels.
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
Compatibility list is here: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
@@ -87,10 +91,10 @@ Notes about Steam
|
||||
|
||||
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works:
|
||||
- First problem is Steam crashing after the sign-in window, if you encounter this issue, you may need to add libappindicator. To install it on Debian, run `sudo apt install libappindicator1`.
|
||||
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm intalled. To install it on Debian, run `sudo apt install libnm0`.
|
||||
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm installed. To install it on Debian, run `sudo apt install libnm0`.
|
||||
- Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode". This is because some Steam components used in the browser view are only 64-bit now. So go in the "View" menu and switch to "Small view", else the list will stay empty. Alternatively, Steam can be started in small mode directly by using `+open steam://open/minigameslist` command line arguments.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
|
||||
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
|
||||
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aforementioned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
|
||||
|
||||
Steam for Windows installs fine but doesn't work yet.
|
||||
|
||||
@@ -107,19 +111,19 @@ Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those mod
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box86 already wrap vulikan. If your system has a 32bits vulkan driver, box86 will use it when needed. Note that vulkan wrapping has not been tested much, due to the limited vulkan support on the hardware I currently own. Profile 1.0 and 1.1, whith some extension, should be OK. 1.2 is not really wrapped. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardxware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
Box86 already wrap Vulkan. If your system has a 32bits Vulkan driver, box86 will use it when needed. Note that Vulkan wrapping has not been tested much, due to the limited Vulkan support on the hardware I currently own. Profile 1.0 and 1.1, with some extension, should be OK. 1.2 is not really wrapped. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
|
||||
----
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box86 developpement.
|
||||
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
|
||||
* 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 continous 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)
|
||||
* 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.
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||

|
||||
|
||||
Linux用户空间的x86应用模拟器
|
||||
|
||||
[更新历史](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [报告错误](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
使用Box86可以在ARM或其他非x86架构的Linux操作系统上运行x86 Linux程序(例如游戏),请注意,主机系统需要是**32位小端**的。
|
||||
|
||||
你需要一个**32位**的子系统来运行Box86,因为Box86在纯64位系统上无法使用,同时你也需要一个**32位**的Linux编译工具链来编译Box86,例如**arm-linux-gnueabihf-gcc**, 否则你将无法编译Box86 (一般的64位ARM编译工具链如 aarch64-linux-gnu-gcc 不支持"-marm"编译选项,会编译失败并报错)。
|
||||
|
||||
因为Box86使用了一些“系统”库的原生版本,例如libc、libm、SDL和OpenGL,所以在很多情况下性能很不错,也可以方便地与其他应用集成使用。点击[此处](https://box86.org/index.php/2021/06/game-performances/)查看Benchmark示例。
|
||||
|
||||
大多数x86游戏都用到了OpenGL,所以在ARM平台上类似于[gl4es](https://github.com/ptitSeb/gl4es)的解决方案通常是必要的。(许多ARM平台仅提供OpenGL ES支持,又或者他们的OpenGL实现很不可靠(例如Android上的OpenGL)。)
|
||||
|
||||
Box86为ARM平台集成了DynaRec(动态重编译器),比仅使用解释器提升5到10倍性能。关于Dynarec如何工作的更多信息,可以在[这里](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/)找到。
|
||||
|
||||
许多游戏已可在不做多少改动的情况下直接运行,例如:《粘粘世界》(WorldOfGoo)、《航空大亨豪华版》(Airline Tycoon Deluxe)、《超越光速》(FTL)等、基于GameMaker的游戏(《传说之下》(UNDERTALE)等)。
|
||||
|
||||
如果你想开发Box86,最好安装ccache,以缓存编译结果。
|
||||
如果你需要启用Trace跟踪(例如输出寄存器值与各条被执行的x86指令),你也需要安装[Zydis](https://github.com/zyantific/zydis)。
|
||||
|
||||
一些x86内部操作码使用“Realmode X86 Emulator Library”的部分内容,请参阅[x86primop.c](../src/emu/x86primop.c)了解版权详情
|
||||
|
||||
----
|
||||
|
||||
编译与安装
|
||||
----
|
||||
> [Box86编译指南](COMPILE.md)
|
||||
>
|
||||
> [Box86 Wine安装指南](X86WINE.md)
|
||||
|
||||
一些示例视频
|
||||
----
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
在这几个Youtube频道可以找到更多Box86的相关视频
|
||||
|
||||
[MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
|
||||
|
||||
[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
|
||||
|
||||
[The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
|
||||
程序兼容性列表: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
感谢制作Logo和图标的grayduck!
|
||||
|
||||
注意:
|
||||
不要把本项目和[86box](https://github.com/86Box/86Box)搞混了,后者是一个"**全量**"的x86 PC模拟器。
|
||||
|
||||
----
|
||||
|
||||
使用方法
|
||||
----
|
||||
|
||||
有若干环境变量可以设置Box86的行为。
|
||||
|
||||
点击[这里](USAGE.md)了解所有的环境变量和它们的作用。
|
||||
|
||||
请注意:Box86的Dynarec提供了一种包含"内存保护"和段错误信号处理程序的机制来处理JIT代码。简单来说,如果你想用GDB来调试一个使用JIT代码的运行程序(比如mono/Unity3D),就会触发很多“正常”的段错误。建议在GDB中使用类似于`handle SIGSEGV nostop`的命令,来防止在每个段错误时都停止程序运行,如果你想捕获段错误,可以在`signals.c`中的`my_memprotectionhandler`中放置一个断点。
|
||||
|
||||
----
|
||||
|
||||
关于64位平台的注意事项
|
||||
----
|
||||
|
||||
Box86的工作原理是直接将函数调用从x86_转换到主机系统,主机系统(Box86运行的系统)需要有32位的库。Box86并不包括任何64位<->32位的转换。所以如果你需要在64位平台上运行Box86,那么你需要建立一个32位的库环境,并以32位ARM为目标系统编译Box86(例如使用arm-linux-gnueabihf-gcc工具链交叉编译或直接在armhf chroot环境中编译运行)。
|
||||
|
||||
如果你需要运行64位应用,请考虑使用[Box64](https://github.com/ptitSeb/box64),它可以在64位平台上运行x86_64程序,但请再一次注意运行x86程序需要Box86与32位库环境(就像在x86_64的Linux上运行x86程序需要x86 multiarch库一样)。
|
||||
|
||||
----
|
||||
|
||||
关于Unity游戏的注意事项
|
||||
----
|
||||
|
||||
当前对于Unity游戏的模拟仍不完善。Unity使用Mono,但它所使用的信号机制还没有被完美模拟。理论上可以使用原生Mono库(在[这里](https://github.com/Unity-Technologies/mono)可以找到),但Mono的封装比较麻烦,现在还没完成,所以我们使用了模拟的Mono库,目前Mono的JIT动态编译代码已由"内存保护"(Protected memory)机制实现,应该能正常运行。
|
||||
|
||||
同时,一些Unity3D游戏需要OpenGL 3+,目前在大部分Arm开发板上提供OpenGL 3+是很困难的。
|
||||
|
||||
所以,并不是所有的Unity游戏都能运行,尤其是那些需要提供很高的OpenGL配置(3.2+)的游戏更有可能不行,但除此之外应该问题不大,而且能运行的游戏的性能应该不错。
|
||||
|
||||
提示:如果游戏开始后在显示任何东西之前退出,在Raspberry Pi4上使用`MESA_GL_VERSION_OVERRIDE=3.2`,在Panfrost上使用`PAN_MESA_DEBUG=gl3`来使用更高的配置文件。
|
||||
|
||||
----
|
||||
|
||||
关于Steam的注意事项
|
||||
----
|
||||
|
||||
Linux Steam 现在可以在Box86上运行,但还是有点不稳定,而且有些功能可能不正常:
|
||||
- 如果Steam在显示登录界面后崩溃,你可能需要安装libappindicator库,例如运行`sudo apt install libappindicator1`。
|
||||
- 如果你选择记住密码,而Steam在下次启动时崩溃,你可能需要安装libnm库,例如运行`sudo apt install libnm0`。
|
||||
- Steam不能在正常的大界面模式下工作,因为Steam在浏览器模式使用的一些组件只能在64位平台上运行。所以请在查看选项卡中选择"小模式",否则Steam将无法正常显示列表。或者在启动Steam添加`+open steam://open/minigameslist`参数,这样Steam将会直接在小模式下启动。
|
||||
- 为了避免"libc.so.6 is absent"的错误,请添加环境变量`STEAMOS=1` 与 `STEAM_RUNTIME=1`。
|
||||
- 一些游戏(例如基于起源引擎的游戏:《传送门》、《半衰期2》)使用了libtcmalloc库,Box86会尝试检测它们并通过LD_PRELOAD预加载它们来获得更好的兼容性,虽然应该可以在没有上述功能的情况下工作,但保险起见,我们还是建议你安装它,例如运行`sudo apt install libtcmalloc-minimal4`。
|
||||
|
||||
Windows Steam 可以安装但目前不能运行。
|
||||
|
||||
----
|
||||
|
||||
关于Wine的注意事项
|
||||
----
|
||||
|
||||
Box86现在已经支持Wine。Wine的内建程序全部能运行,许多Windows 程序和游戏也运行良好。但是不要忘记大多数 Windows 游戏都使用 Direct3D,这可能需要完整的 OpenGL 驱动程序和尽可能高的配置文件(基于 ES2 后端的 gl4es 现在不能运行 Wine 的Direct3D组件)。
|
||||
注意:如果你想在 Raspberry Pi 3 或更早版本上用 Box86 运行 Wine,由于这些设备的内核默认使用 2G/2G 虚拟内存分配(2G 空间用于用户态程序,2G 空间用于内核),与需要访问内存地址 > 2G 的 Wine 程序不兼容。 因此,你需要重新配置内核以使用 3G/1G 的内存分配方式。
|
||||
|
||||
----
|
||||
|
||||
关于Vulkan的注意事项
|
||||
----
|
||||
|
||||
Box86已经封装了Vulkan。如果设备的系统有32位的Vulkan驱动程序,Box86会在需要时使用它。但请注意,由于作者目前拥有的硬件上的Vulkan支持有限,因此Vulkan封装库尚未经过太多测试。 Vulkan 1.0、1.1与一些扩展应该能工作。 但Vulkan 1.2还没有被实现。已经有一些在树莓派4上的Vulkan演示 (Sascha Willems 的演示中,为x86构建的demo与与直接为armhf构建的demo工作均正常)。但请注意,Pi4的Vulkan驱动程序目前不支持 dxvk(wine DirectX->Vulkan 兼容层),这不是Box86的问题,而是由于缺少扩展(硬件支持)与一些其他驱动问题。而在Panfrost上,PanVK尚不成熟,暂时没有用它测试dxvk。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
----
|
||||
|
||||
我要感谢所有为 box86 开发做出贡献的人。
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, icecream95, M-HT
|
||||
* 财务帮助:FlyingFathead, stormchaser3000
|
||||
* 硬件捐赠:[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)
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
(如果你的项目中使用了Box86,请不要忘记提及!)
|
||||
+29
-3
@@ -119,6 +119,7 @@ Forbid dynablock creation in the interval specified (helpfull for debugging beha
|
||||
Enables/Disables Box86's Dynarec building BigBlock.
|
||||
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 1 : Build Dynarec block as big as possible (Default.)
|
||||
* 2 : Build Dynarec block bigger (don't stop when block overlaps)
|
||||
|
||||
#### BOX86_DYNAREC_STRONGMEM
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
@@ -126,6 +127,16 @@ Enable/Disable simulation of Strong Memory model
|
||||
* 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
|
||||
|
||||
#### BOX86_DYNAREC_X87DOUBLE
|
||||
Force the use of Double for x87 emulation
|
||||
* 0 : Try to use float when possible for x87 emulation (faster)
|
||||
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis)
|
||||
|
||||
#### BOX86_DYNAREC_FASTNAN
|
||||
Enable/Disable generation of -NAN
|
||||
* 0 : Generate -NAN like on x86 (slower, more x86 accurate)
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (Default)
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
@@ -140,11 +151,26 @@ Enable/Disable simulation of Strong Memory model
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX86_ALLOWMISSINGLIBS
|
||||
Allow Box86 to continue even if a library is missing.
|
||||
#### BOX86_ALLOWMISSING_LIBS
|
||||
Allow Box86 to continue even if a library is missing (renamed from BOX86_ALLOWMISSINGLIBS).
|
||||
* 0 : Box86 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_ALLOWMISSING_SYMBOLS
|
||||
Allow dlopen with RTLD_NOW flag to not resolve all symbols.
|
||||
* 0 : Box86 will stop if a library have unresolved symbols. (Default.)
|
||||
* 1 : Continue even if a needed library have unresolved symbols (like symbols not yet wrapped).
|
||||
|
||||
#### BOX86_PREFER_WRAPPED
|
||||
Box86 will use wrapped libs even if the lib is specified with absolute path
|
||||
* 0 : Try to use emulated libs when they are defined with absolute path (Default.)
|
||||
* 1 : Use Wrapped native libs even if path is absolute
|
||||
|
||||
#### BOX86_PREFER_EMULATED
|
||||
Box86 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11
|
||||
* 0 : Native libs are prefered (Default.)
|
||||
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
|
||||
|
||||
#### BOX86_NOPULSE
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
@@ -153,7 +179,7 @@ Disables the load of pulseaudio libraries.
|
||||
#### BOX86_NOGTK
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
#### BOX86_NOVULKAN
|
||||
Disables the load of vulkan libraries.
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ _TwisterOS users: Wine, winetricks, and Box86 are already installed in TwisterOS
|
||||
|
||||
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 already has a 3G/1G split kernel and works with Wine, but **the Pi 3B+ and earlier models have a 2G/2G kernel and require a custom-compiled 3G/1G kernel to get Wine working.**_
|
||||
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (for x64, use [box64](https://github.com/ptitSeb/box64) & wine-amd64 with an `aarch64` processor).
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM devices other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
|
||||
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 58 KiB |
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 169 KiB |
+5
-20
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-arm-git}" -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-gameshell-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-gameshell-git}" -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroid-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-odroid-git}" -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pandora-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-pandora-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-pandora-git}" -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+5
-20
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pyra-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-pyra-git}" -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rpi-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -20,8 +20,7 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
build() {
|
||||
# Check for Pi version number
|
||||
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
|
||||
_piversion=4
|
||||
@@ -36,24 +35,11 @@ prepare() {
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-rpi-git}" -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -19,26 +19,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-rk3399-git}" -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+5
-20
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-x86-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r3858.5368285
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('i386')
|
||||
@@ -18,26 +18,11 @@ pkgver() {
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
make -j$(nproc)
|
||||
cmake -B build -S "${pkgname%-x86-git}" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ This will copy the PKGBUILD for your platform (where you type your platform name
|
||||
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
|
||||
|
||||
### 2. What platforms are currently supported.
|
||||
All specified in [COMPILE.md](../COMPILE.md).
|
||||
All specified in [COMPILE.md](../docs/COMPILE.md).
|
||||
|
||||
### 3. Any advantages with that sollution?
|
||||
This might give you some advantages like those:
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
#!/bin/sh
|
||||
systemctl restart systemd-binfmt
|
||||
if [ -d '/run/systemd/system' ]; then
|
||||
systemctl restart systemd-binfmt || :
|
||||
fi
|
||||
+4
-1
@@ -748,9 +748,12 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("smpeg", "smpeg2") \
|
||||
or match("udev0", "udev1") \
|
||||
or match("gstinterfaces010","gstvideo")\
|
||||
or match("gstinterfaces010","gstaudio")\
|
||||
or match("gstreamer010","gstreamer") \
|
||||
\
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "ldlinux") \
|
||||
or match("libc", "ldlinux") \
|
||||
:
|
||||
# libc and ldlinux have some "__libc_" data symbols in common... TODO check if ok
|
||||
continue
|
||||
|
||||
@@ -52,5 +52,10 @@ if( TEST_RESULT )
|
||||
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
|
||||
endif( TEST_RESULT )
|
||||
|
||||
# remove the temporary files if they exist
|
||||
if( EXISTS ${TEST_OUTPUT} )
|
||||
file(REMOVE "${TEST_OUTPUT}")
|
||||
endif()
|
||||
|
||||
# everything went fine...
|
||||
message( "Passed: The output of ${TEST_PROGRAM} matches ${TEST_REFERENCE}" )
|
||||
@@ -176,6 +176,7 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
context->defver = NewDefaultVersion();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, iFEv, x86Syscall, 0, NULL);
|
||||
addAlternate((void*)0xffffe400, (void*)context->vsyscall);
|
||||
@@ -283,6 +284,9 @@ void FreeBox86Context(box86context_t** context)
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if(ctx->stack_clone)
|
||||
free(ctx->stack_clone);
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
@@ -304,6 +308,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
FreeDefaultVersion(&ctx->defver);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 2
|
||||
#define BOX86_REVISION 4
|
||||
#define BOX86_REVISION 6
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
+182
-1
@@ -44,6 +44,13 @@ static uintptr_t box86_jmptbl_default[1<<JMPTABL_SHIFT];
|
||||
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
static int inited = 0;
|
||||
|
||||
typedef struct mapmem_s {
|
||||
uintptr_t begin, end;
|
||||
struct mapmem_s *next;
|
||||
} mapmem_t;
|
||||
|
||||
static mapmem_t *mapmem = NULL;
|
||||
|
||||
typedef struct blocklist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
@@ -348,7 +355,7 @@ uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t) && !mmaplist[i].locked) {
|
||||
mmaplist[i].locked = 1;
|
||||
int rsize = 0;
|
||||
size_t rsize = 0;
|
||||
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
|
||||
if(sub) {
|
||||
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
|
||||
@@ -674,8 +681,99 @@ void unprotectDB(uintptr_t addr, uintptr_t size)
|
||||
|
||||
#endif
|
||||
|
||||
void printMapMem()
|
||||
{
|
||||
mapmem_t* m = mapmem;
|
||||
while(m) {
|
||||
printf_log(LOG_INFO, " %p-%p\n", (void*)m->begin, (void*)m->end);
|
||||
m = m->next;
|
||||
}
|
||||
}
|
||||
|
||||
void addMapMem(uintptr_t begin, uintptr_t end)
|
||||
{
|
||||
begin &=~0xfff;
|
||||
end = (end&~0xfff)+0xfff; // 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*)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;
|
||||
free(tmp);
|
||||
}
|
||||
// all done!
|
||||
}
|
||||
void removeMapMem(uintptr_t begin, uintptr_t end)
|
||||
{
|
||||
begin &=~0xfff;
|
||||
end = (end&~0xfff)+0xfff; // 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;
|
||||
}
|
||||
free(tmp);
|
||||
} else if(begin>m->begin && end<m->end) { // the zone is totaly inside the block => split it!
|
||||
mapmem_t* newm = (mapmem_t*)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)
|
||||
{
|
||||
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) {
|
||||
@@ -688,6 +786,7 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
|
||||
void forceProtection(uintptr_t addr, uintptr_t size, uint32_t 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) {
|
||||
@@ -698,6 +797,7 @@ void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t 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) {
|
||||
@@ -705,6 +805,16 @@ void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
}
|
||||
}
|
||||
|
||||
void freeProtection(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
@@ -712,6 +822,67 @@ uint32_t getProtection(uintptr_t addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void allocProtection(uintptr_t addr, uintptr_t size, uint32_t 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) {
|
||||
if(!memprot[i])
|
||||
memprot[i] = prot;
|
||||
}
|
||||
}
|
||||
|
||||
void loadProtectionFromMap()
|
||||
{
|
||||
if(box86_mapclean)
|
||||
return;
|
||||
char buf[500];
|
||||
FILE *f = fopen("/proc/self/maps", "r");
|
||||
uintptr_t current = 0x0;
|
||||
if(!f)
|
||||
return;
|
||||
while(!feof(f)) {
|
||||
char* ret = fgets(buf, sizeof(buf), f);
|
||||
(void)ret;
|
||||
char r, w, x;
|
||||
uintptr_t s, e;
|
||||
if(sscanf(buf, "%lx-%lx %c%c%c", &s, &e, &r, &w, &x)==5) {
|
||||
if(current<s) {
|
||||
removeMapMem(current, s-1);
|
||||
current = e;
|
||||
}
|
||||
int prot = ((r=='r')?PROT_READ:0)|((w=='w')?PROT_WRITE:0)|((x=='x')?PROT_EXEC:0);
|
||||
allocProtection(s, e-s, prot);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
box86_mapclean = 1;
|
||||
}
|
||||
|
||||
#define LOWEST (void*)0x10000
|
||||
void* findBlockNearHint(void* hint, size_t size)
|
||||
{
|
||||
mapmem_t* m = mapmem;
|
||||
uintptr_t h = (uintptr_t)hint;
|
||||
while(m) {
|
||||
// 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;
|
||||
m = m->next;
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
void* find32bitBlock(size_t size)
|
||||
{
|
||||
return findBlockNearHint(LOWEST, size);
|
||||
}
|
||||
|
||||
int unlockCustommemMutex()
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -769,6 +940,11 @@ void init_custommem_helper(box86context_t* ctx)
|
||||
#endif
|
||||
#endif
|
||||
pthread_atfork(NULL, NULL, atfork_child_custommem);
|
||||
// init mapmem list
|
||||
mapmem = (mapmem_t*)calloc(1, sizeof(mapmem_t));
|
||||
mapmem->begin = 0x0;
|
||||
mapmem->end = (uintptr_t)LOWEST - 1;
|
||||
loadProtectionFromMap();
|
||||
}
|
||||
|
||||
void fini_custommem_helper(box86context_t *ctx)
|
||||
@@ -821,4 +997,9 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
#endif
|
||||
free(p_blocks);
|
||||
pthread_mutex_destroy(&mutex_blocks);
|
||||
while(mapmem) {
|
||||
mapmem_t *tmp = mapmem;
|
||||
mapmem = mapmem->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
+97
-12
@@ -66,7 +66,7 @@ Op is 20-27
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
// nop
|
||||
#define NOP EMIT(0xe1a00000)
|
||||
#define NOP EMIT(0xe320f000)
|
||||
|
||||
// mov dst, src
|
||||
#define MOV_REG(dst, src) EMIT(0xe1a00000 | ((dst) << 12) | (src) )
|
||||
@@ -213,6 +213,9 @@ Op is 20-27
|
||||
// add dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.c dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x00800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.s dst, src1, src2, lsl #imm
|
||||
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -242,9 +245,12 @@ Op is 20-27
|
||||
// cmp.s dst, src, #imm
|
||||
#define CMPS_IMM8(src, imm8) \
|
||||
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
// cmn.s.cond dst, src, #imm
|
||||
#define CMNS_IMM8_COND(cond, src, imm8) \
|
||||
EMIT((cond) | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
#define CMNS_IMM8(src, imm8) \
|
||||
EMIT(c__ | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// tst.s dst, src1, src2, lsl #imm
|
||||
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
|
||||
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -254,21 +260,33 @@ Op is 20-27
|
||||
// tst.s dst, src1, #imm ror rot*2
|
||||
#define TSTS_IMM8_ROR(src, imm8, rot) \
|
||||
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// tst.s.cond dst, src1, #imm ror rot*2
|
||||
#define TSTS_IMM8_ROR_COND(cond, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// orr dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.cond dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT(cond | 0x01800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl #imm
|
||||
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.cond dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT(cond | 0x01800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsr #imm
|
||||
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl rs
|
||||
#define ORRS_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr.s dst, src1, src2, lsr rs
|
||||
#define ORRS_REG_LSR_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSR(rs, src2) )
|
||||
// orr dst, src1, #imm8
|
||||
#define ORR_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
@@ -281,6 +299,9 @@ Op is 20-27
|
||||
// orr dst, src1, src2, lsl rs
|
||||
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr dst, src1, src2, lsr rs
|
||||
#define ORR_REG_LSR_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSR(rs, src2) )
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -466,6 +487,7 @@ Op is 20-27
|
||||
// Mul and MulA
|
||||
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | 0b000000<<22 | (A)<<21 | (S)<<20 | (Rd)<<16 | (Rn)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
|
||||
#define MUL(Rd, Rm, Rn) EMIT(MULMULA(c__, 0, 0, (Rd), 0, (Rm), (Rn)))
|
||||
#define MLA(Rd, Rn, Rm, Ra) EMIT(MULMULA(c__, 1, 0, (Rd), (Ra), (Rm), (Rn)))
|
||||
|
||||
#define MLS_gen(Cond, Rd, Ra, Rm, Rn) (Cond | 0b00000110<<20 | (Rd)<<16 | (Ra)<<12 | (Rm)<<8 | 0b1001<<4 | (Rn))
|
||||
//MLS : Rd = Ra - Rm*Rn
|
||||
@@ -486,6 +508,8 @@ Op is 20-27
|
||||
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// SBFX: Signed Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define SBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111101<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
|
||||
@@ -554,6 +578,16 @@ Op is 20-27
|
||||
#define STREXB(Rd, Rt, Rn) EMIT(STREXB_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXB_COND(cond, Rd, Rt, Rn) EMIT(STREXB_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
#define LDREXH_gen(cond, Rn, Rt) (cond | 0b0001111<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
|
||||
// Load Exclusive Half-Word Rt from Rn (tagging the memory)
|
||||
#define LDREXH(Rt, Rn) EMIT(LDREXH_gen(c__, Rn, Rt))
|
||||
#define LDREXH_COND(cond, Rt, Rn) EMIT(LDREXH_gen(cond, Rn, Rt))
|
||||
|
||||
#define STREXH_gen(cond, Rd, Rn, Rt) (cond | 0b0001111<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
|
||||
// Store Exclusive Half-Word Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
|
||||
#define STREXH(Rd, Rt, Rn) EMIT(STREXH_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXH_COND(cond, Rd, Rt, Rn) EMIT(STREXH_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
// 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))
|
||||
// Reverse bits of Rm, store result in Rd
|
||||
@@ -654,6 +688,10 @@ Op is 20-27
|
||||
// Store to memory to single VSTR Sd, [Rn, #+/-imm8], imm8&3 ignored!
|
||||
#define VSTR_32(Sd, Rn, Imm8) EMIT(c__ | (0b1101<<24) | (((Imm8)<0)?0:1)<<23 | (((Sd)&1)<<22) | (0<<20) | ((Rn)<<16) | ((((Sd)>>1)&15)<<12) | (0b1010<<8) | ((abs(Imm8)>>2)&255))
|
||||
|
||||
#define VSTM_64_gen(cond, P, U, D, W, Rn, Vd, imm8) (cond | 0b110<<25 | (P)<<24 | (U)<<23 | (D)<<22 | (W)<<21 | (Rn)<<16 | (Vd)<<12 | 0b1011<<8 | (imm8))
|
||||
// Store a sery of Dx, post imcrementing Rn
|
||||
#define VSTM_64_W(Dd, Rn) EMIT(VSTM_64_gen(c__, 0, 1, ((Dd)>>4)&1, 1, Rn, (Dd)&15, 2))
|
||||
|
||||
// Convert from single Sm to double Dd
|
||||
#define VCVT_F64_F32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0111<<16) | (((Dd)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (0<<4) | (((Sm)>>1)&15))
|
||||
// Convert from double Dm to single Sd
|
||||
@@ -680,6 +718,42 @@ Op is 20-27
|
||||
// Inplace convert from F64 to S16. Rounding is not selectable
|
||||
#define VCVT_S16_F64(Dd) EMIT(VCVT_FP_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
|
||||
|
||||
#define VRINT_FP_gen(D, RM, Vd, size, M, Vm) (0b111111101<<23 | (D)<<22 | 0b111<<19 | (RM)<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<4 | (Vm))
|
||||
// Round floating-point to integer to Nearest with Ties to Away
|
||||
#define VRINTA_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b00, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer to Nearest with Ties to Away
|
||||
#define VRINTA_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer towards -Infinity
|
||||
#define VRINTM_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b11, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards -Infinity
|
||||
#define VRINTM_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b11, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer to Nearest
|
||||
#define VRINTN_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b01, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer to Nearest
|
||||
#define VRINTN_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer towards +Infinity
|
||||
#define VRINTP_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b10, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards +Infinity
|
||||
#define VRINTP_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTR_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b110<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR
|
||||
#define VRINTR_F32(Sd, Sm) EMIT(VRINTR_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR
|
||||
#define VRINTR_F64(Dd, Dm) EMIT(VRINTR_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTX_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b111<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR with eXecptions if inexact
|
||||
#define VRINTX_F32(Sd, Sm) EMIT(VRINTX_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR with eXecptions if inexact
|
||||
#define VRINTX_F64(Dd, Dm) EMIT(VRINTX_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTZ_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b110<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer towards Zero
|
||||
#define VRINTZ_F32(Sd, Sm) EMIT(VRINTZ_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards Zero
|
||||
#define VRINTZ_F64(Dd, Dm) EMIT(VRINTZ_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
// Mutiply F64 Dd = Dn*Dm
|
||||
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
@@ -814,19 +888,19 @@ Op is 20-27
|
||||
#define VMOVQ_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 1, 0, (imm8)&15))
|
||||
|
||||
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VLD1LANE_32(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, (index)<<3, 15))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VLD1LANE_32(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, (index)<<3, 15))
|
||||
|
||||
#define VLD1ALL_gen(D, Rn, Vd, size, T, a, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | 0b11<<10| (size)<<6 | (T)<<5 | (a)<<4 | (Rm))
|
||||
#define VLD1ALL_16(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, 0, 0, 15))
|
||||
#define VLD1ALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, 0, 0, 15))
|
||||
#define VLD1QALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, 1, 0, 15))
|
||||
#define VLD1ALL_16(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, 0, 0, 15))
|
||||
#define VLD1ALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, 0, 0, 15))
|
||||
#define VLD1QALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, 1, 0, 15))
|
||||
|
||||
#define VST1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b00<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VST1LANE_8(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VST1LANE_16(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VST1LANE_32(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, (index)<<3, 15))
|
||||
#define VST1LANE_8(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VST1LANE_16(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VST1LANE_32(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, (index)<<3, 15))
|
||||
|
||||
#define VADD_gen(size, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VADD_8(Dd, Dn, Dm) EMIT(VADD_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -870,7 +944,7 @@ Op is 20-27
|
||||
#define VCEQQ_16(Dd, Dn, Dm) EMIT(VCEQ_I_gen(1, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_32(Dd, Dn, Dm) EMIT(VCEQ_I_gen(2, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_32(Dd, Dn, Dm) EMIT(VCEQ_I_gen(2, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
//#define VCEQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15)) // doesn't exist
|
||||
#define VCEQQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_F_gen(sz, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | (sz)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1110<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VCEQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -883,6 +957,7 @@ Op is 20-27
|
||||
#define VCEQQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_F32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VCGT_I_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VCGT_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -1288,7 +1363,17 @@ Op is 20-27
|
||||
|
||||
#define VDUP_sgen(D, imm4, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (imm4)<<16 | (Vd)<<12 | 0b1100<<8 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Dd <= Dup(Dm[x])
|
||||
#define VDUP_8(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<1)|0b1), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_8(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<1)|0b1), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUP_16(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<2)|0b10), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_16(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<2)|0b10), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUP_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_64(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<4)|0b1000), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VREV64_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VREV64_32(Dd, Dm) EMIT(VREV64_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VREV64Q_32(Dd, Dm) EMIT(VREV64_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VABS_vgen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b110<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VABS_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
@@ -179,7 +179,7 @@ INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d64 &g&g param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
|
||||
|
||||
@@ -1164,7 +1164,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int m = ((opcode >> 5) & 1) << 4 | ((opcode >> 0) & 0xF);
|
||||
int param = (opcode >> 7) & 0x3;
|
||||
|
||||
sprintf(ret, "VREV%d.%d %s, %s", 16 << param, 8 << size, vecname[(q << 5) + 0x20 + d], vecname[(q << 5) + 0x20 + m]);
|
||||
sprintf(ret, "VREV%d.%d %s, %s", 64 >> param, 8 << size, vecname[(q << 5) + 0x20 + d], vecname[(q << 5) + 0x20 + m]);
|
||||
} else if ((opcode & 0xFFB30F10) == 0xF3B00200) {
|
||||
int u = (opcode >> 7) & 1;
|
||||
int size = (opcode >> 18) & 0x3;
|
||||
|
||||
@@ -314,7 +314,7 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
if(current && current->done) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
|
||||
@@ -30,6 +30,7 @@ void arm_epilog_fast() EXPORTDYN;
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef HAVE_TRACE
|
||||
#include "elfloader.h"
|
||||
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#endif
|
||||
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
@@ -38,7 +39,9 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
void* x86addr = db?(void*)getX86Address(db, (uintptr_t)x2):NULL;
|
||||
const char* pcname = getAddrFunctionName((uintptr_t)x86addr);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p/%s)\n", x2, db, x86addr, pcname);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
|
||||
+156
-66
@@ -3,6 +3,7 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -60,9 +61,17 @@ void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const cha
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(!box86_dynarec_bigblock)
|
||||
return;
|
||||
// exist?
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
// put in a free slot
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(!dyn->next[i]) {
|
||||
dyn->next[i] = addr;
|
||||
return;
|
||||
}
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
@@ -75,13 +84,12 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
memmove(dyn->next+i, dyn->next+i+1, (dyn->next_sz-i-1)*sizeof(uintptr_t));
|
||||
--dyn->next_sz;
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
@@ -206,7 +214,7 @@ int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 1: // DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
@@ -231,7 +239,7 @@ int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
|
||||
static instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
|
||||
{
|
||||
// x86 instruction is <16 bytes
|
||||
int toadd;
|
||||
@@ -260,6 +268,98 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size,
|
||||
return insts;
|
||||
}
|
||||
|
||||
static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
int pred_sz = 0;
|
||||
// compute total size of predecessor to alocate the array
|
||||
// first compute the jumps
|
||||
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;
|
||||
}
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x86.has_next && (!i || dyn->insts[i].pred_sz)) {
|
||||
++pred_sz;
|
||||
++dyn->insts[i+1].pred_sz;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)malloc(pred_sz*sizeof(int));
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
dyn->insts[i].pred = p;
|
||||
p += dyn->insts[i].pred_sz;
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
assert(p==dyn->predecessor+pred_sz);
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(i!=dyn->size-1 && dyn->insts[i].x86.has_next && (!i || dyn->insts[i].pred_sz))
|
||||
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)
|
||||
dyn->insts[dyn->insts[i].x86.jmp_insts].pred[dyn->insts[dyn->insts[i].x86.jmp_insts].pred_sz++] = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void updateNeed(dynarec_arm_t* dyn, int ninst, uint32_t need) {
|
||||
uint32_t old_need = dyn->insts[ninst].x86.need_flags;
|
||||
uint32_t new_need = old_need | need;
|
||||
uint32_t new_use = dyn->insts[ninst].x86.use_flags;
|
||||
uint32_t old_use = dyn->insts[ninst].x86.old_use;
|
||||
|
||||
if((new_need&X_PEND) && dyn->insts[ninst].x86.state_flags==SF_SUBSET) {
|
||||
new_need &=~X_PEND;
|
||||
new_need |= X_ALL;
|
||||
}
|
||||
|
||||
uint32_t new_set = 0;
|
||||
if(dyn->insts[ninst].x86.state_flags & SF_SET)
|
||||
new_set = dyn->insts[ninst].x86.set_flags;
|
||||
if(dyn->insts[ninst].x86.state_flags & SF_PENDING)
|
||||
new_set |= X_PEND;
|
||||
if((new_need&X_PEND) && (
|
||||
dyn->insts[ninst].x86.state_flags==SF_SET || dyn->insts[ninst].x86.state_flags==SF_SUBSET)) {
|
||||
new_need &=~X_PEND;
|
||||
new_need |=X_ALL;
|
||||
}
|
||||
|
||||
dyn->insts[ninst].x86.need_flags = new_need;
|
||||
dyn->insts[ninst].x86.old_use = new_use;
|
||||
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1)
|
||||
new_need |= X_PEND;
|
||||
|
||||
// a Flag Barrier will change all need to "Pending", as it clear all flags optimisation
|
||||
if(new_need && dyn->insts[ninst].x86.barrier&BARRIER_FLAGS)
|
||||
new_need = X_PEND;
|
||||
|
||||
if((new_need == old_need) && (new_use == old_use)) // no changes, bye
|
||||
return;
|
||||
|
||||
if(!(new_need && dyn->insts[ninst].x86.barrier&BARRIER_FLAGS)) {
|
||||
new_need &=~new_set; // clean needed flag that were suplied
|
||||
new_need |= new_use; // new need
|
||||
}
|
||||
|
||||
if((new_need == (X_ALL|X_PEND)) && (dyn->insts[ninst].x86.state_flags & SF_SET))
|
||||
new_need = X_ALL;
|
||||
|
||||
//update need to new need on predecessor
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], new_need);
|
||||
}
|
||||
|
||||
static void resetNeed(dynarec_arm_t* dyn) {
|
||||
for(int i = dyn->size; i-- > 0;) {
|
||||
dyn->insts[i].x86.old_use = 0;
|
||||
dyn->insts[i].x86.need_flags = dyn->insts[i].x86.default_need;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
@@ -275,6 +375,7 @@ void CancelBlock()
|
||||
return;
|
||||
free(helper->next);
|
||||
free(helper->insts);
|
||||
free(helper->predecessor);
|
||||
free(helper->sons_x86);
|
||||
free(helper->sons_arm);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
@@ -314,30 +415,17 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
// already protect the block and compute hash signature
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// Compute flag_need, without taking into account any barriers
|
||||
uint32_t last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
}
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Compute flag_need, without with current barriers
|
||||
resetNeed(&helper);
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
updateNeed(&helper, i, 0);
|
||||
// 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) {
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
@@ -345,76 +433,76 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(helper.insts[i2].x86.addr==j)
|
||||
k=i2;
|
||||
}
|
||||
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
|
||||
helper.insts[k].x86.barrier = 1;
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x86.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x86.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
fillPredecessors(&helper);
|
||||
// check for the optionnal barriers now
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.barrier==3)
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
// out-of-block jump
|
||||
if(helper.insts[i].x86.jmp_insts == -1) {
|
||||
if(i==helper.size-1 || helper.insts[i+1].x86.barrier)
|
||||
helper.insts[i].x86.barrier=2; // nope, end of block or barrier just after
|
||||
else
|
||||
helper.insts[i].x86.barrier=0; // ok, no need for a barrier here after all
|
||||
} else
|
||||
helper.insts[i].x86.barrier=2;
|
||||
// nothing for now
|
||||
} else {
|
||||
// inside block jump
|
||||
int k = helper.insts[i].x86.jmp_insts;
|
||||
if(k>i) {
|
||||
// jump in the future
|
||||
if(helper.insts[k].pred_sz>1) {
|
||||
// with multiple flow, put a barrier
|
||||
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
} else {
|
||||
// jump back
|
||||
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
/*for(int i=helper.size-1; i>=0; --i) {
|
||||
int k;
|
||||
if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
&& helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1) {
|
||||
int k = helper.insts[i].x86.jmp_insts;
|
||||
&& ((k=helper.insts[i].x86.jmp_insts)>=0)
|
||||
&& helper.insts[k].x86.barrier&BARRIER_FLAGS) {
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x86.need_flags)
|
||||
||(helper.insts[k].x86.set_flags==X_ALL
|
||||
&& helper.insts[k].x86.state_flags==SF_SET)
|
||||
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x86.barrier = 4; // remove barrier (keep FPU barrier, and still reset state flag)
|
||||
helper.insts[k].x86.barrier &= ~BARRIER_FLAGS; // remove flag barrier
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
if(helper.insts[i].x86.barrier==1)
|
||||
// immediate barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
int k;
|
||||
if(helper.insts[i].x86.jmp
|
||||
&& ((k=helper.insts[i].x86.jmp_insts)>=0)
|
||||
) {
|
||||
if(helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1)
|
||||
if(helper.insts[k].x86.barrier&BARRIER_FLAGS)
|
||||
// jumpto barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
if(helper.insts[i].x86.barrier&BARRIER_FLAGS && (helper.insts[k].x86.need_flags | helper.insts[k].x86.use_flags))
|
||||
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
|
||||
else
|
||||
helper.insts[i].x86.use_flags |= helper.insts[helper.insts[i].x86.jmp_insts].x86.need_flags;
|
||||
helper.insts[i].x86.use_flags |= (helper.insts[k].x86.need_flags | helper.insts[k].x86.use_flags);
|
||||
}
|
||||
if(helper.insts[i].x86.barrier&BARRIER_FLAGS)
|
||||
// immediate barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
}
|
||||
resetNeed(&helper);
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
helper.insts[i].x86.need_flags = 0;
|
||||
last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
}
|
||||
}
|
||||
updateNeed(&helper, i, 0);
|
||||
|
||||
// pass 1, float optimisations
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
arm_pass1(&helper, addr);
|
||||
|
||||
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
@@ -510,6 +598,8 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
free(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
free(helper.sons_x86);
|
||||
helper.sons_x86 = NULL;
|
||||
free(helper.sons_arm);
|
||||
@@ -517,4 +607,4 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
current_helper = NULL;
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
}
|
||||
+132
-98
@@ -340,7 +340,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x27:
|
||||
INST_NAME("DAA");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization DAA\n");
|
||||
READFLAGS(X_AF|X_CF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTB(x1, xEAX, 0);
|
||||
@@ -402,7 +402,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x2F:
|
||||
INST_NAME("DAS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization DAS\n");
|
||||
READFLAGS(X_AF|X_CF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTB(x1, xEAX, 0);
|
||||
@@ -464,7 +464,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x37:
|
||||
INST_NAME("AAA");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization AAA\n");
|
||||
READFLAGS(X_AF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTH(x1, xEAX, 0);
|
||||
@@ -532,7 +532,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x3F:
|
||||
INST_NAME("AAS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization AAS\n");
|
||||
READFLAGS(X_AF);
|
||||
SETFLAGS(X_AF|X_CF|X_PF|X_SF|X_ZF, SF_SET);
|
||||
UXTH(x1, xEAX, 0);
|
||||
@@ -548,7 +548,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC reg");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&0x07);
|
||||
emit_inc32(dyn, ninst, gd, x3, x14);
|
||||
break;
|
||||
@@ -561,7 +561,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC reg");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&0x07);
|
||||
emit_dec32(dyn, ninst, gd, x3, x14);
|
||||
break;
|
||||
@@ -691,24 +691,29 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F|(dyn->insts[ninst].x86.barrier?0:X_PEND)); \
|
||||
READFLAGS(F); \
|
||||
i8 = F8S; \
|
||||
BARRIER(3); \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8);\
|
||||
Bcond(NO, i32); \
|
||||
if(!dyn->insts[ninst].x86.barrier) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
|
||||
case 0x70:
|
||||
@@ -1377,7 +1382,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Eb, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
u8 = F8;
|
||||
emit_rol8c(dyn, ninst, x1, u8&0x1f, x2, x14);
|
||||
@@ -1385,7 +1390,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Eb, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
u8 = F8;
|
||||
emit_ror8c(dyn, ninst, x1, u8&0x1f, x2, x14);
|
||||
@@ -1393,7 +1398,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEB(x1);
|
||||
@@ -1404,7 +1409,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Eb, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEB(x1);
|
||||
@@ -1467,7 +1472,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rol32c(dyn, ninst, ed, u8, x3, x14);
|
||||
@@ -1475,7 +1480,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_ror32c(dyn, ninst, ed, u8, x3, x14);
|
||||
@@ -1483,7 +1488,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEDW(x14, x1);
|
||||
@@ -1498,7 +1503,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDW(x14, x1);
|
||||
u8 = F8&0x1f;
|
||||
if(u8==1) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(ed, xEmu, offsetof(x86emu_t, op1));
|
||||
MOVW(x3, u8);
|
||||
@@ -1523,7 +1528,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
WBACK;
|
||||
} else if(u8>1) {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, u8);
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
@@ -1565,7 +1570,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RETN");
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ninst, i32);
|
||||
*need_epilog = 0;
|
||||
@@ -1576,7 +1581,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
// ^^^ that hack break PlantsVsZombies and GOG Setup under wine....
|
||||
READFLAGS(X_PEND); // so instead, force the defered flags, so it's not too slow, and flags are not lost
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -1624,7 +1629,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
if(PK(0)=='S' && PK(1)=='C') {
|
||||
addr+=2;
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
INST_NAME("Special Box86 instruction");
|
||||
if((PK(0)==0) && (PK(1)==0) && (PK(2)==0) && (PK(3)==0))
|
||||
{
|
||||
@@ -1684,7 +1689,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(PK(0)==0x80) {
|
||||
INST_NAME("Syscall");
|
||||
u8 = F8;
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
MOV32(xEIP, ip+2);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP)|(1<<xEIP)|(1<<xFlags));
|
||||
CALL_S(x86Syscall, -1, 0);
|
||||
@@ -1706,7 +1711,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCF:
|
||||
INST_NAME("IRET");
|
||||
SETFLAGS(X_ALL, SF_SET); // Not a hack, EFLAGS are restored
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
iret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -1718,14 +1723,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("ROL Eb, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_rol8c(dyn, ninst, ed, 1, x2, x14);
|
||||
EBBACK;
|
||||
} else {
|
||||
INST_NAME("ROL Eb, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization ROL 8b\n");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEB(x1);
|
||||
CALL_(rol8, x1, (1<<x3));
|
||||
@@ -1736,7 +1741,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(opcode==0xD0) {
|
||||
INST_NAME("ROR Eb, 1");
|
||||
MOVW(x2, 1);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_ror8c(dyn, ninst, ed, 1, x2, x14);
|
||||
EBBACK;
|
||||
@@ -1744,7 +1749,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("ROR Eb, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization ROR 8b\n");
|
||||
GETEB(x1);
|
||||
CALL_(ror8, x1, (1<<x3));
|
||||
EBBACK;
|
||||
@@ -1752,7 +1757,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD0) {INST_NAME("RCL Eb, 1");} else {INST_NAME("RCL Eb, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL 8b\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD0) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
@@ -1762,7 +1767,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD0) {INST_NAME("RCR Eb, 1");} else {INST_NAME("RCR Eb, CL");}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR 8b\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD0) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
@@ -1826,21 +1831,21 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, 1);
|
||||
@@ -1850,12 +1855,31 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, 1);
|
||||
GETEDW(x14, x1);
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(ed, xEmu, offsetof(x86emu_t, op1));
|
||||
MOVW(x3, 1);
|
||||
STR_IMM9(x3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(x3, d_rcr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(x3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
XOR_REG_LSR_IMM8(x3, xFlags, ed, 31);
|
||||
BFI(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
MOVS_REG_LSR_IMM5(x3, xFlags, 1); // load CC (F_CF==0) into ARM CF
|
||||
MOVS_REG_RRX(ed, ed);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(ed, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1, 0);
|
||||
BFC_COND(cCC, xFlags, F_CF, 1);
|
||||
|
||||
}
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1931,7 +1955,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCL\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
@@ -1941,7 +1965,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization RCR\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
@@ -2035,20 +2059,27 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDF:
|
||||
addr = dynarecDF(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x86.barrier) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ");
|
||||
@@ -2120,8 +2151,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// disabling this to avoid fetching data outside current block (in case this part changed, this block will not been marck as dirty)
|
||||
/*case 3:
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall-1)), dyn->insts[ninst].retn);
|
||||
@@ -2162,15 +2193,13 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(ninst && dyn->insts[ninst-1].x86.set_flags) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
if(u32==0) { // self modifying code maybe? so use indirect address fetching
|
||||
@@ -2184,7 +2213,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
BARRIER(1);
|
||||
BARRIER(BARRIER_MAYBE);
|
||||
if(opcode==0xE9) {
|
||||
INST_NAME("JMP Id");
|
||||
i32 = F32S;
|
||||
@@ -2193,18 +2222,18 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i32 = F8S;
|
||||
}
|
||||
JUMP(addr+i32, 0);
|
||||
if(dyn->insts) {
|
||||
PASS2IF(dyn->insts[ninst].x86.jmp_insts==-1, 1) {
|
||||
// out of the block
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) {
|
||||
// out of the block
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
} else {
|
||||
// inside the block
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3);
|
||||
tmp = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);
|
||||
if(tmp==-4) {
|
||||
NOP;
|
||||
} else {
|
||||
// inside the block
|
||||
tmp = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);
|
||||
if(tmp==-4) {
|
||||
NOP;
|
||||
} else {
|
||||
Bcond(c__, tmp);
|
||||
}
|
||||
Bcond(c__, tmp);
|
||||
}
|
||||
}
|
||||
*need_epilog = 0;
|
||||
@@ -2315,7 +2344,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC3:
|
||||
INST_NAME("(REPZ) RET");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
BARRIER(2);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -2537,7 +2566,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AL, Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization IMUL 8b\n");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEB(x1);
|
||||
STM(xEmu, (1<<xEAX));
|
||||
@@ -2546,7 +2575,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization DIV 8b\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEB(x1);
|
||||
STM(xEmu, (1<<xEAX));
|
||||
@@ -2555,7 +2584,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Eb");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization IDIV 8b\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEB(x1);
|
||||
STM(xEmu, (1<<xEAX));
|
||||
@@ -2612,7 +2641,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(arm_div && ninst && dyn->insts
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x86.addr)==0x31
|
||||
&& (*(uint8_t*)(dyn->insts[ninst-1].x86.addr)==0x31
|
||||
|| *(uint8_t*)(dyn->insts[ninst-1].x86.addr)==0x33)
|
||||
&& *(uint8_t*)(dyn->insts[ninst-1].x86.addr+1)==0xD2) {
|
||||
// previous instruction is XOR EDX, EDX, so its 32bits / 32bits
|
||||
SET_DFNONE(x2); // flags are undefined
|
||||
@@ -2655,9 +2685,15 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
GETEDH(x1);
|
||||
if(arm_div) {
|
||||
// check if a 32bits division is enough
|
||||
CMPS_IMM8(xEDX, 0); // compare to 0
|
||||
CMNS_IMM8_COND(cNE, xEDX, 1); // compare to FFFFFFFF if not 0
|
||||
TSTS_IMM8_ROR_COND(cEQ, xEAX, 0b10, 1); // also test that xEAX is not signed!
|
||||
B_MARK(cEQ);
|
||||
CMNS_IMM8(xEDX, 1); // compare to FFFFFFFF if not 0
|
||||
B_MARK2(cNE);
|
||||
TSTS_IMM8_ROR(xEAX, 0b10, 1); // also test that xEAX is signed!
|
||||
B_MARK(cNE);
|
||||
MARK2;
|
||||
}
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
|
||||
@@ -2711,14 +2747,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_inc8(dyn, ninst, x1, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEB(x1);
|
||||
emit_dec8(dyn, ninst, x1, x2, x14);
|
||||
EBBACK;
|
||||
@@ -2733,14 +2769,14 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_inc32(dyn, ninst, ed, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETED;
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
WBACK;
|
||||
@@ -2750,22 +2786,20 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
PASS2IF(ninst && dyn->insts[ninst-1].x86.set_flags, 1) {
|
||||
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); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDH(xEIP);
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
BARRIER(1);
|
||||
BARRIER(BARRIER_FULL);
|
||||
GETEDH(xEIP);
|
||||
jump_to_next(dyn, 0, ed, ninst);
|
||||
*need_epilog = 0;
|
||||
|
||||
+277
-123
@@ -87,6 +87,20 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
//CALL(arm_ud, -1, 0);
|
||||
UDF(0);
|
||||
break;
|
||||
|
||||
case 0x0D:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("PREFETCHW");
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = fakeed(dyn,addr, ninst, nextop);
|
||||
// should use PLDW, but it's not available on cortex-a8 for example
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -433,6 +447,29 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3A: // these are some more SSSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0F:
|
||||
INST_NAME("PALIGNR Gm, Em, Ib");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1);
|
||||
u8 = F8;
|
||||
if(u8>15) {
|
||||
VEOR(q0, q0, q0);
|
||||
} else if(u8>7) {
|
||||
d0 = fpu_get_scratch_quad(dyn);
|
||||
VEOR(d0, d0, d0);
|
||||
VEXT_8(q0, q0, d0, u8-8);
|
||||
} else {
|
||||
VEXT_8(q0, q1, q0, u8);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
@@ -577,23 +614,37 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
#if 0
|
||||
VRSQRTEQ_F32(v2, q0);
|
||||
//step?
|
||||
VRECPEQ_F32(v0, v2);
|
||||
//step?
|
||||
#else
|
||||
// more precise
|
||||
if(v0==q0)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = v0;
|
||||
VRSQRTEQ_F32(v2, q0);
|
||||
VMULQ_F32(v1, v2, q0);
|
||||
VRSQRTSQ_F32(v1, v1, v2);
|
||||
VMULQ_F32(v1, v1, v2);
|
||||
VMULQ_F32(v0, v1, q0);
|
||||
#endif
|
||||
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
|
||||
// and VSQRTS is (3-A*B)/2
|
||||
// so VSQRTE(d) -> X is initial step
|
||||
// VSQRTS(d,X*X)*X -> X loop
|
||||
// than d*X -> SQRT(d) (because X ~ 1/sqrt(d))
|
||||
VRSQRTEQ_F32(v2, q0); // v2 = X0 (=X), q0 = d
|
||||
VMULQ_F32(v1, v2, v2); // v1 = X0²
|
||||
VRSQRTSQ_F32(v1, v1, q0); // v1 = (3-d*X0²)/2
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X0*(3-d*X0²)/2 = X1
|
||||
VMULQ_F32(v1, v2, v2); // v1 = x1²
|
||||
VRSQRTSQ_F32(v1, v1, q0); // v1 = (3-d*X1²)/2
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X1*(3-d*X1²)/2 = X2
|
||||
if(!box86_dynarec_fastnan) {
|
||||
// need to preserve v0, in case it's == q0
|
||||
VMULQ_F32(v1, v2, q0); // v1 = X2*d ~ SQRT(d)
|
||||
if(v0<dyn->n.fpu_scratch || v0!=q0)
|
||||
q1 = v0; // v0 is a scratch register
|
||||
else
|
||||
q1 = fpu_get_scratch_quad(dyn); // need a new scratch
|
||||
VCEQQ_0_F32(q1, q0); // prepare mask, 111 when == 0.0
|
||||
VMOVQ_H32(v2, 0xff); // prepare +inf
|
||||
VSHRQ_U32(v2, v2, 1); // 0xff000000 -> 0x7f800000 == +inf
|
||||
VCEQQ_32(v2, v2, q0); // v2 mask: 111 when == +inf
|
||||
VORRQ(q1, q1, v2); // q1 mask: 111 when ==0 || == +inf
|
||||
VBICQ(v1, v1, q1); // mask value in result
|
||||
VANDQ(q1, q0, q1); // keep original value that are 0 or +inf
|
||||
VORRQ(v0, v1, q1); // copy over
|
||||
} else {
|
||||
VMULQ_F32(v0, v2, q0); // v0 = X2*d ~ SQRT(d)
|
||||
}
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
@@ -601,21 +652,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
#if 0
|
||||
VRSQRTEQ_F32(v0, q0);
|
||||
//step?
|
||||
#else
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
// more precise
|
||||
if(v0==q0)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = v0;
|
||||
VRSQRTEQ_F32(v2, q0);
|
||||
VMULQ_F32(v1, v2, q0);
|
||||
VRSQRTSQ_F32(v1, v1, v2);
|
||||
VMULQ_F32(v0, v1, v2);
|
||||
#endif
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
@@ -623,14 +660,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(q0 == v0)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = v0;
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(v2, q0);
|
||||
VRECPSQ_F32(v1, v2, q0);
|
||||
VMULQ_F32(v0, v2, v1);
|
||||
VRECPEQ_F32(v0, q0);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
@@ -719,16 +749,19 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0);
|
||||
GETGX(v0, 1);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(q0, v1);
|
||||
VRECPSQ_F32(q1, q0, v1);
|
||||
VMULQ_F32(q0, q0, q1);
|
||||
VRECPSQ_F32(q1, q0, v1);
|
||||
VMULQ_F32(q0, q0, q1);
|
||||
VMULQ_F32(v0, v0, q0);
|
||||
GETEX(q0, 0);
|
||||
GETGX(q1, 1);
|
||||
// use Gx * 1/Ex, using RECP
|
||||
// Newton-Raphson: Xn+1 = Xn*(2-d*Xn) converge to 1/d if X0 if result of VRECPE(d)
|
||||
// VRECPE is 2-A*B
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
v2 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(v2, q0); // v2 = X0, q0 = d
|
||||
VRECPSQ_F32(v1, q0, v2); // v1 = 2-d*X0
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X0*(2-d*X0) = X1
|
||||
VRECPSQ_F32(v1, q0, v2); // v1 = 2-d*X1
|
||||
VMULQ_F32(v2, v2, v1); // v2 = X1*(2-d*X1) = X2 ~ 1/d
|
||||
VMULQ_F32(q1, q1, v2);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPS Gx, Ex");
|
||||
@@ -857,9 +890,13 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(q0+0, v0);
|
||||
VMOVD(q0+1, v1);
|
||||
if(!(v0&1) && (v1==(v0+1))) {
|
||||
q0 = v0; // no need to move the regs...
|
||||
} else {
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(q0+0, v0);
|
||||
VMOVD(q0+1, v1);
|
||||
}
|
||||
VQMOVN_S32(v0, q0);
|
||||
break;
|
||||
|
||||
@@ -1130,24 +1167,29 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F|(dyn->insts[ninst].x86.barrier?0:X_PEND)); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(3); \
|
||||
JUMP(addr+i32_, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8);\
|
||||
Bcond(NO, i32); \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i32_, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x86.barrier) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i32_, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
|
||||
case 0x80:
|
||||
@@ -1396,13 +1438,11 @@ 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");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTB(x3, xECX, 0);
|
||||
GETEDW(x14, x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETED;
|
||||
GETGD;
|
||||
MOV_REG(x2, gd);
|
||||
CALL(shld32, ed, (wback?(1<<wback):0));
|
||||
emit_shld32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
@@ -1971,68 +2011,182 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
i32 = -1;
|
||||
j32 = 0;
|
||||
GETGX(v0, 1);
|
||||
q0 = fpu_get_scratch_quad(dyn); // temporary storage
|
||||
// use stack as temporary storage
|
||||
SUB_IMM8(xSP, xSP, 4);
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
u8 = F8;
|
||||
// first two elements from Gx
|
||||
for (int i=0; i<2; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
VST1LANE_32(v0+(idx/2), xSP, idx&1);
|
||||
i32 = idx;
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
if((nextop&0xC0)!=0xC0) {
|
||||
// from memory
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0);
|
||||
u8 = F8;
|
||||
q0 = v0;
|
||||
// Low part
|
||||
switch (u8&0xf) {
|
||||
case 0b0000: VDUP_32(q0, v0, 0); break;
|
||||
case 0b0001: VREV64_32(q0, v0); break; // reverse low part
|
||||
case 0b0010: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v2, v0, 4); break;
|
||||
case 0b0011: VEXT_8(q0, v0+1, v0, 4); break;
|
||||
case 0b0100: break; // same
|
||||
case 0b0101: VDUP_32(q0, v0, 1); break;
|
||||
case 0b0110: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v2, v0, 4); break;
|
||||
case 0b0111: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v0+1, v2, 4); break;
|
||||
case 0b1000: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v2, v0+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0, v0, v0+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0, v0+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0, v0+1); break;
|
||||
case 0b1100: VEXT_8(q0, v0+1, v0, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b1101: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v0, v2, 4); break;
|
||||
case 0b1110: VMOVD(q0, v0+1); break;
|
||||
case 0b1111: VDUP_32(q0, v0+1, 1); break;
|
||||
}
|
||||
VLD1LANE_32(q0+(i/2), xSP, i&1);
|
||||
}
|
||||
i32 = -1;
|
||||
// next two from Ex
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
for (int i=2; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
VST1LANE_32(v1+(idx/2), xSP, idx&1);
|
||||
i32 = idx;
|
||||
// High part
|
||||
if(((u8>>4)&3) == ((u8>>6)&3)) {
|
||||
if((u8>>4)&3) {
|
||||
ADD_IMM8(x3, wback, ((u8>>4)&3)*4);
|
||||
}
|
||||
VLD1LANE_32(q0+(i/2), xSP, i&1);
|
||||
VLD1ALL_32(q0+1, ((u8>>4)&3)?x3:wback);
|
||||
} else {
|
||||
if((u8>>4)&3) {
|
||||
ADD_IMM8(x3, wback, ((u8>>4)&3)*4);
|
||||
}
|
||||
VLD1LANE_32(q0+1, ((u8>>4)&3)?x3:wback, 0);
|
||||
if((u8>>6)&3) {
|
||||
ADD_IMM8(x3, wback, ((u8>>6)&3)*4);
|
||||
}
|
||||
VLD1LANE_32(q0+1, ((u8>>6)&3)?x3:wback, 1);
|
||||
}
|
||||
} else {
|
||||
for (int i=2; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
ADD_IMM8(x2, ed, idx*4);
|
||||
i32 = idx;
|
||||
// from register
|
||||
wback = 0; ed = nextop&7;
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
u8 = F8;
|
||||
if((v0==v1) && ((u8==0) || (u8==0b01010101) || (u8==0b10101010) || (u8==0b11111111))) {
|
||||
// same value duplicated all along
|
||||
q0 = v0;
|
||||
VDUPQ_32(v0, v0+((u8>>1)&1), u8&1);
|
||||
} else if ((v0==v1) && (u8==0b01000100)) {
|
||||
q0 = v0;
|
||||
VMOVD(v0+1, v0);
|
||||
} else if ((v0==v1) && (u8==0b11101110)) {
|
||||
q0 = v0;
|
||||
VMOVD(v0, v0+1);
|
||||
} else if ((v0==v1) && (u8==0b10110001)) {
|
||||
q0 = v0;
|
||||
VREV64Q_32(v0, v0);
|
||||
} else if ((v0==v1) && (u8==0b01001110)) {
|
||||
q0 = v0;
|
||||
VSWP(v0, v0+1);
|
||||
} else if ((v0==v1) && (u8==0b11011000)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0, v0+1);
|
||||
} else if ((v0==v1) && (u8==0b00100111)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0+1, v0);
|
||||
} else if ((v0==v1) && (u8==0b01110010)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0, v0+1);
|
||||
VREV64Q_32(v0, v0);
|
||||
} else if ((v0==v1) && (u8==0b10001101)) {
|
||||
q0 = v0;
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VTRN_32(v0+1, v0);
|
||||
VREV64Q_32(v0, v0);
|
||||
} else {
|
||||
if(v1!=v0)
|
||||
q0 = v0; // no need for temp storage
|
||||
else if((u8&0b10100000)==0b10100000)
|
||||
q0 = v0; // no need for temp if only low/low and high/high are shuffled
|
||||
else
|
||||
q0 = fpu_get_scratch_quad(dyn); // temporary storage
|
||||
// Low part
|
||||
switch (u8&0xf) {
|
||||
case 0b0000: VDUP_32(q0, v0, 0); break;
|
||||
case 0b0001: VREV64_32(q0, v0); break; // reverse low part
|
||||
case 0b0010: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v2, v0, 4); break;
|
||||
case 0b0011: VEXT_8(q0, v0+1, v0, 4); break;
|
||||
case 0b0100: VMOVD(q0, v0); break; // same
|
||||
case 0b0101: VDUP_32(q0, v0, 1); break;
|
||||
case 0b0110: VEXT_8(q0, v0, v0+1, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b0111: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v0+1, v2, 4); break;
|
||||
case 0b1000: VREV64_32(v2, v0);
|
||||
VEXT_8(q0, v2, v0+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0, v0, v0+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0, v0+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0, v0+1); break;
|
||||
case 0b1100: VEXT_8(q0, v0+1, v0, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b1101: VREV64_32(v2, v0+1);
|
||||
VEXT_8(q0, v0, v2, 4); break;
|
||||
case 0b1110: VMOVD(q0, v0+1); break;
|
||||
case 0b1111: VDUP_32(q0, v0+1, 1); break;
|
||||
}
|
||||
// High part
|
||||
switch ((u8>>4)&0xf) {
|
||||
case 0b0000: VDUP_32(q0+1, v1, 0); break;
|
||||
case 0b0001: VREV64_32(q0+1, v1); break; // reverse low part
|
||||
case 0b0010: VREV64_32(v2, v1+1);
|
||||
VEXT_8(q0+1, v2, v1, 4); break;
|
||||
case 0b0011: VEXT_8(q0+1, v1+1, v1, 4); break;
|
||||
case 0b0100: VMOVD(q0+1, v1); break; // same
|
||||
case 0b0101: VDUP_32(q0+1, v1, 1); break;
|
||||
case 0b0110: VEXT_8(q0+1, v1, v1+1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b0111: VREV64_32(v2, v1);
|
||||
VEXT_8(q0+1, v1+1, v2, 4); break;
|
||||
case 0b1000: VREV64_32(v2, v1);
|
||||
VEXT_8(q0+1, v2, v1+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0+1, v1, v1+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0+1, v1+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0+1, v1+1); break;
|
||||
case 0b1100: VEXT_8(q0+1, v1+1, v1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b1101: VREV64_32(v2, v1+1);
|
||||
VEXT_8(q0+1, v1, v2, 4); break;
|
||||
case 0b1110: VMOVD(q0+1, v1+1); break;
|
||||
case 0b1111: VDUP_32(q0+1, v1+1, 1); break;
|
||||
}
|
||||
VLD1LANE_32(q0+(i/2), x2, i&1);
|
||||
}
|
||||
}
|
||||
ADD_IMM8(xSP, xSP, 4);
|
||||
VMOVQ(v0, q0);
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x1, wback, fixedaddress+0);
|
||||
LDR_IMM9(x2, wback, fixedaddress+4);
|
||||
CMPS_REG_LSL_IMM5(xEAX, x1, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x2, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
STR_IMM9(xEBX, wback, fixedaddress+0);
|
||||
STR_IMM9(xECX, wback, fixedaddress+4);
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x1);
|
||||
MOV_REG(xEDX, x2);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x1, wback, fixedaddress+0);
|
||||
LDR_IMM9(x2, wback, fixedaddress+4);
|
||||
CMPS_REG_LSL_IMM5(xEAX, x1, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x2, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
STR_IMM9(xEBX, wback, fixedaddress+0);
|
||||
STR_IMM9(xECX, wback, fixedaddress+4);
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x1);
|
||||
MOV_REG(xEDX, x2);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -299,13 +300,9 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
|
||||
}
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst!=dyn->size-1) {
|
||||
} else {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
BARRIER(BARRIER_FULL);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -28,16 +29,30 @@ uintptr_t dynarecGS(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, wb1, wb2, wb;
|
||||
uint8_t wback, wb1, wb2, wb, eb1, eb2;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
MAYUSE(wback);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("ADD GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -137,6 +152,16 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, ed, gd, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -400,6 +425,24 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(xEAX, x2, 0);
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV GS:Eb, Ib");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= u8
|
||||
u8 = F8;
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
MOVW(x3, u8);
|
||||
BFI(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
u8 = F8;
|
||||
MOVW(x3, u8);
|
||||
STRB_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
@@ -422,14 +465,14 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEDO2(x14);
|
||||
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEDO2(x14);
|
||||
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
|
||||
@@ -175,6 +175,12 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PUSH DS");
|
||||
MOVW(x1, offsetof(x86emu_t, segs[_DS]));
|
||||
LDRH_REG(x2, xEmu, x1);
|
||||
PUSH16(x2, xESP);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
@@ -295,7 +301,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg16");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
@@ -310,7 +316,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg16");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
@@ -681,6 +687,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, 2);
|
||||
UXTH(x1, xEAX, 0);
|
||||
LDRHAI_REG_LSL_IMM5(x2, xEDI, x3);
|
||||
@@ -898,6 +905,10 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec66F0(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
@@ -991,6 +1002,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("CMC");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
XOR_IMM8(xFlags, xFlags, 1<<F_CF);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -1045,8 +1063,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ORR_REG_LSL_IMM5(x2, x2, xEDX, 16);
|
||||
UDIV(x3, x2, ed);
|
||||
MLS(x14, x3, ed, x2); // x14 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFI(xEAX, x3, 1, 16);
|
||||
BFI(xEDX, x14, 1, 16);
|
||||
BFI(xEAX, x3, 0, 16);
|
||||
BFI(xEDX, x14, 0, 16);
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
@@ -1086,14 +1104,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
emit_dec16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
|
||||
+216
-82
@@ -619,17 +619,55 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("ADDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VADD_F64(v0, v0, q0);
|
||||
VADD_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VMUL_F64(v0, v0, q0);
|
||||
VMUL_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPD2PS Gx, Ex");
|
||||
@@ -656,9 +694,28 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SUBPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VSUB_F64(v0, v0, q0);
|
||||
VSUB_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINPD Gx, Ex");
|
||||
@@ -677,9 +734,28 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0, 1);
|
||||
VDIV_F64(v0, v0, q0);
|
||||
VDIV_F64(v0+1, v0+1, q0+1);
|
||||
GETGX(q1, 1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(q1, q1, q0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1, q1);
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(q1+1, q1+1, q0+1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, q1+1, q1+1);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPD Gx, Ex");
|
||||
@@ -866,51 +942,113 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
u8 = F8;
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(u8==0x4E) {
|
||||
if ((u8==0) || (u8==0b01010101) || (u8==0b10101010) || (u8==0b11111111)) {
|
||||
VDUPQ_32(v0, v1+((u8>>1)&1), u8&1);
|
||||
} else if (u8==0b01000100) {
|
||||
VMOVD(v0+1, v1);
|
||||
VMOVD(v0, v1);
|
||||
} else if (u8==0b11101110) {
|
||||
VMOVD(v0, v1+1);
|
||||
VMOVD(v0+1, v1+1);
|
||||
} else if (u8==0b10110001) {
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if (u8==0b00011011) {
|
||||
VREV64Q_32(v0, v1);
|
||||
VSWP(v0, v0+1);
|
||||
} else if (u8==0b01001110) {
|
||||
if(v0==v1) {
|
||||
VSWP(v0, v0+1);
|
||||
} else {
|
||||
VMOVD(v0, v1+1);
|
||||
VMOVD(v0+1, v1);
|
||||
}
|
||||
} else if (u8==0b11011000) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VMOVQ(v0, v1);
|
||||
VTRN_32(v0, v0+1);
|
||||
} else if (u8==0b00100111) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VMOVQ(v0, v1);
|
||||
VTRN_32(v0+1, v0);
|
||||
} else if (u8==0b10001101) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VREV64Q_32(v0, v1); // 10 11 00 01
|
||||
VTRN_32(v0, v0+1); // 10 00 11 01
|
||||
} else if (u8==0b01110010) {
|
||||
//VTRN_32(Dd, Dm) swap Dd[1] with Dm[0]
|
||||
VREV64Q_32(v0, v1); // 10 11 00 01
|
||||
VTRN_32(v0+1, v0); // 01 11 00 10
|
||||
} else {
|
||||
uint32_t swp[4] = {
|
||||
(0)|(1<<8)|(2<<16)|(3<<24),
|
||||
(4)|(5<<8)|(6<<16)|(7<<24),
|
||||
(8)|(9<<8)|(10<<16)|(11<<24),
|
||||
(12)|(13<<8)|(14<<16)|(15<<24)
|
||||
};
|
||||
q0 = fpu_get_scratch_quad(dyn); // temporary storage
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
if(v0==v1) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else
|
||||
q1 = v1;
|
||||
uint32_t a1, a2, a3, a4;
|
||||
a1 = swp[(u8>>(0*2))&3];
|
||||
a2 = swp[(u8>>(1*2))&3];
|
||||
MOV32(x2, a1);
|
||||
if(a1==a2) {MOV_REG(x3, x2);} else {MOV32(x3, a2);}
|
||||
VMOVtoV_D(d0, x2, x3);
|
||||
VTBL2_8(v0+0, q1, d0);
|
||||
a3 = swp[(u8>>(2*2))&3];
|
||||
a4 = swp[(u8>>(3*2))&3];
|
||||
if(a3!=a1 || a4!=a2) {
|
||||
if(a3!=a1) {
|
||||
if(a3==a2) {MOV_REG(x2, x3);} else {MOV32(x2, a3);}
|
||||
}
|
||||
if(a4!=a2) {
|
||||
if(a4==a3) {MOV_REG(x3, x2);} else {MOV32(x3, a4);}
|
||||
}
|
||||
VMOVtoV_D(d0, x2, x3);
|
||||
if(v1!=v0)
|
||||
q0 = v0; // no need for temp storage
|
||||
else if((u8&0xf)==((u8>>4)&0xf))
|
||||
q0 = v0;
|
||||
// Low part
|
||||
switch (u8&0xf) {
|
||||
case 0b0000: VDUP_32(q0, v1, 0); break;
|
||||
case 0b0001: VREV64_32(q0, v1); break; // reverse low part
|
||||
case 0b0010: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0, d0, v1, 4); break;
|
||||
case 0b0011: VEXT_8(q0, v1+1, v1, 4); break;
|
||||
case 0b0100: VMOVD(q0, v1); break; // same
|
||||
case 0b0101: VDUP_32(q0, v1, 1); break;
|
||||
case 0b0110: VEXT_8(q0, v1, v1+1, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b0111: VREV64_32(d0, v1);
|
||||
VEXT_8(q0, v1+1, d0, 4); break;
|
||||
case 0b1000: VREV64_32(d0, v1);
|
||||
VEXT_8(q0, d0, v1+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0, v1, v1+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0, v1+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0, v1+1); break;
|
||||
case 0b1100: VEXT_8(q0, v1+1, v1, 4);
|
||||
VREV64_32(q0, q0); break;
|
||||
case 0b1101: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0, v1, d0, 4); break;
|
||||
case 0b1110: VMOVD(q0, v1+1); break;
|
||||
case 0b1111: VDUP_32(q0, v1+1, 1); break;
|
||||
}
|
||||
VTBL2_8(v0+1, q1, d0);
|
||||
// High part
|
||||
if((u8&0xf)==((u8>>4)&0xf)) {
|
||||
VMOVD(q0+1, q0);
|
||||
} else switch ((u8>>4)&0xf) {
|
||||
case 0b0000: VDUP_32(q0+1, v1, 0); break;
|
||||
case 0b0001: VREV64_32(q0+1, v1); break; // reverse low part
|
||||
case 0b0010: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0+1, d0, v1, 4); break;
|
||||
case 0b0011: VEXT_8(q0+1, v1+1, v1, 4); break;
|
||||
case 0b0100: VMOVD(q0+1, v1); break; // same
|
||||
case 0b0101: VDUP_32(q0+1, v1, 1); break;
|
||||
case 0b0110: VEXT_8(q0+1, v1, v1+1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b0111: VREV64_32(d0, v1);
|
||||
VEXT_8(q0+1, v1+1, d0, 4); break;
|
||||
case 0b1000: VREV64_32(d0, v1);
|
||||
VEXT_8(q0+1, d0, v1+1, 4); break;
|
||||
case 0b1001: VEXT_8(q0+1, v1, v1+1, 4); break;
|
||||
case 0b1010: VDUP_32(q0+1, v1+1, 0); break;
|
||||
case 0b1011: VREV64_32(q0+1, v1+1); break;
|
||||
case 0b1100: VEXT_8(q0+1, v1+1, v1, 4);
|
||||
VREV64_32(q0+1, q0+1); break;
|
||||
case 0b1101: VREV64_32(d0, v1+1);
|
||||
VEXT_8(q0+1, v1, d0, 4); break;
|
||||
case 0b1110: VMOVD(q0+1, v1+1); break;
|
||||
case 0b1111: VDUP_32(q0+1, v1+1, 1); break;
|
||||
}
|
||||
VMOVQ(v0, q0);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if ((u8==0) || (u8==0b01010101) || (u8==0b10101010) || (u8==0b11111111)) {
|
||||
if(u8&3) {
|
||||
ADD_IMM8(x3, ed, (u8&3)*4);
|
||||
}
|
||||
VLD1QALL_32(v0, (u8&3)?x3:ed);
|
||||
} else {
|
||||
for (int i=0; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
@@ -919,8 +1057,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
VLD1LANE_32(v0+(i/2), x2, i&1);
|
||||
}
|
||||
} else {
|
||||
VLD1QALL_32(v0, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1554,6 +1690,13 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0xBF:
|
||||
INST_NAME("MOVSX Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1);
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Gw, Ew");
|
||||
@@ -1562,7 +1705,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGW(x1);
|
||||
GETEW(x2);
|
||||
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16); // GW <- EW
|
||||
emit_add16(dyn, ninst, x1, x2, x14, x3, 1);
|
||||
emit_add16(dyn, ninst, x2, x1, x14, x3, 1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xC2:
|
||||
@@ -1571,42 +1714,34 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
u8 = F8;
|
||||
u8 = F8&7;
|
||||
// 0
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0, v0);
|
||||
} else {
|
||||
VCMP_F64(v0, d0);
|
||||
}
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal or unordered
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
// 1
|
||||
if((u8&7)==6){
|
||||
VCMP_F64(d0+1, v0+1);
|
||||
} else {
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
}
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal or unordered
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0+1, x2, x2);
|
||||
@@ -1646,17 +1781,21 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0);
|
||||
u8 = F8;
|
||||
if(v0==v1 && u8==0) {
|
||||
VMOVD(v0+1, v0);
|
||||
if(v0==v1) {
|
||||
switch (u8&3) {
|
||||
case 0b00: VMOVD(v0+1, v0); break;
|
||||
case 0b01: VSWP(v0, v0+1); break;
|
||||
case 0b10: break;
|
||||
case 0b11: VMOVD(v0, v0+1); break;
|
||||
}
|
||||
} else {
|
||||
if(v0==v1)
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
q0 = v0;
|
||||
VMOVD(q0, v0+(u8&1));
|
||||
VMOVD(q0+1, v1+((u8>>1)&1));
|
||||
if(v0==v1) {
|
||||
VMOVQ(v0, q0);
|
||||
switch(u8&1) {
|
||||
case 0: break;
|
||||
case 1: VMOVD(v0, v0+1); break;
|
||||
}
|
||||
switch((u8>>1)&1) {
|
||||
case 0: VMOVD(v0+1, v1); break;
|
||||
case 1: VMOVD(v0+1, v1+1); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1688,13 +1827,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(v0, q1);
|
||||
VMOVD(v0+1, q1);
|
||||
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
|
||||
VMOVD(v0+1, v0);
|
||||
VQMOVN_S32(v0, v0); // 4*q1 in 16bits now
|
||||
VNEGN_16(v0, v0); // because we want SHR and not SHL
|
||||
VMOVD(v0+1, v0);
|
||||
VDUPQ_16(v0, q1, 0);
|
||||
VNEGNQ_16(v0, v0); // because we want SHR and not SHL
|
||||
VSHLQ_U16(q0, q0, v0);
|
||||
break;
|
||||
case 0xD2:
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode = F8;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
uint8_t ed, gd, u8;
|
||||
int fixedaddress;
|
||||
int32_t i32, j32;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
switch(opcode) {
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
DMB_ISH();
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Ew
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 1);
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
DMB_ISH();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
MARK;
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GETEW(x1);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 1);
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
DMB_ISH();
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
MARK;
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// default to NO LOCK
|
||||
addr-=2;
|
||||
}
|
||||
DMB_ISH();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -132,20 +133,27 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!dyn->insts[ninst].x86.barrier) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
|
||||
+168
-58
@@ -34,11 +34,15 @@ static const float f_pi = PI;
|
||||
static const float f_lg2 = LG2;
|
||||
static const float f_ln2 = LN2;
|
||||
|
||||
extern int arm_v8;
|
||||
|
||||
static const void* round_map[4] = {nearbyint, floor, ceil, trunc};
|
||||
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
@@ -50,6 +54,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j32);
|
||||
(void)u8;
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
@@ -69,9 +74,12 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMOV_64(v2, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("FXCH ST0");
|
||||
break;
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
@@ -81,17 +89,8 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
i1 = x87_get_cache(dyn, ninst, 1, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
@@ -106,6 +105,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VNEG_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
@@ -115,6 +115,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VABS_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -136,7 +137,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// 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->x87stack;
|
||||
i2 = -dyn->n.x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
@@ -154,7 +155,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
B_MARK3(cEQ);
|
||||
} else {
|
||||
// simply move from cache reg to r2/r3
|
||||
v1 = dyn->x87reg[i1];
|
||||
v1 = dyn->n.x87reg[i1];
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
}
|
||||
// get exponant in r1
|
||||
@@ -199,6 +200,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
@@ -210,6 +212,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
@@ -221,6 +224,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
@@ -232,6 +236,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
@@ -243,6 +248,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
@@ -254,6 +260,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
@@ -263,41 +270,32 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VMOV_8(v1, 0); // cannot use VMOV_i_F64
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// use C helper for now, nothing staightforward is available
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_frndint, -1, 0);
|
||||
/*
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
VCVT_S32_F64(x1, v1); // limit to 32bits....
|
||||
VCVT_F64_S32(v1, x1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
*/
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
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(v1, 0);
|
||||
addr+=4;
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000); // 1.0
|
||||
VSUB_F64(v1, 0, v1);
|
||||
}
|
||||
#endif
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
@@ -307,24 +305,30 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d)*ST(1).d
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
INST_NAME("FPTAN");
|
||||
v2 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1); // prepare call to tan
|
||||
CALL_1D(tan, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C1 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C1 C2 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
// 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
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v2, 0b01110000);
|
||||
} else {
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
@@ -335,6 +339,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CALL_2D(atan2, 0);
|
||||
VMOV_64(v2, 0); //ST(1).d = atan2(ST1.d, ST0.d);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
@@ -342,13 +347,48 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1, 0);
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch_double(dyn);
|
||||
VDIV_F64(s0, v1, v2);
|
||||
// set rounding to Nearest
|
||||
MOVW(x2, 1); // Nearest
|
||||
VMRS(x1); // get fpscr
|
||||
MOV_REG(x14, x1);
|
||||
BFI(x1, x2, 22, 2); // inject new round
|
||||
VMSR(x1); // put new fpscr
|
||||
VCVTR_S32_F64(s0*2, s0); // => Q
|
||||
// set back rounding
|
||||
VMSR(x14);
|
||||
// get Q
|
||||
VMOVfrV(x14, s0*2);
|
||||
// Put back Q in a double
|
||||
VCVT_F64_S32(s0, s0*2);
|
||||
VMUL_F64(s0, s0, v2);
|
||||
VSUB_F64(v1, v1, s0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFC(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFI(x1, x14, 9, 1);
|
||||
// set C3 = Q1
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 14, 1);
|
||||
// Set C0 = Q2
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 8, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -357,6 +397,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SUB_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
@@ -365,13 +406,40 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ADD_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch_double(dyn);
|
||||
VDIV_F64(s0, v1, v2);
|
||||
VCVT_S32_F64(s0*2, s0); // => Q
|
||||
// get Q
|
||||
VMOVfrV(x14, s0*2);
|
||||
// Put back Q in a double
|
||||
VCVT_F64_S32(s0, s0*2);
|
||||
VMUL_F64(s0, s0, v2);
|
||||
VSUB_F64(v1, v1, s0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFC(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFI(x1, x14, 9, 1);
|
||||
// set C3 = Q1
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 14, 1);
|
||||
// Set C0 = Q2
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 8, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
@@ -382,21 +450,56 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(sin, 0);
|
||||
VSWP(v1, 0);
|
||||
CALL_1D(cos, 0);
|
||||
CALL_1D(cos, 0); // would it be faster to do sqrt(1-sin()²) ???
|
||||
VMOV_64(v2, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if(!arm_v8) {
|
||||
// check if finite first
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
// load round mode
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x2, x1, 10, 2); // extract round...
|
||||
MOV32(x1, round_map);
|
||||
LDR_REG_LSL_IMM5(x2, x1, x2, 2);
|
||||
VMOV_64(0, v1); // prepare call to fpu_round
|
||||
CALL_1DR(x2, x3, 0);
|
||||
VMOV_64(v1, 0);
|
||||
} else {
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VRINTR_F64(v1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
@@ -406,9 +509,15 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cEQ);
|
||||
VMOV_64(0, v2);
|
||||
CALL_1DD(trunc, exp2, 0);
|
||||
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);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
@@ -416,9 +525,9 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOV_64(0, v1); // prepare call to sin
|
||||
CALL_1D(sin, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFF:
|
||||
@@ -427,9 +536,9 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VMOV_64(0, v1); // prepare call to cos
|
||||
CALL_1D(cos, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
|
||||
@@ -459,7 +568,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, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
@@ -476,6 +585,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(!ST_IS_F(0)) {
|
||||
VCVT_F64_F32(v1, s0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
|
||||
@@ -122,9 +122,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
MOVW(x1, 0);
|
||||
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFI(x2, x1, 15, 1); // B
|
||||
BFC(x2, 0, 8); // IE .. PE, SF, ES
|
||||
BFC(x2, 15, 1); // B
|
||||
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
@@ -230,7 +229,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
ed = x1;
|
||||
ed = x1; // will not be writen immediatly, so x1 is safe for now
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
@@ -289,16 +288,49 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x3, ed, 4);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
} else {
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1, 0);
|
||||
#else
|
||||
v1 = x87_do_push(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;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUB_IMM8(x3, x3, -a);
|
||||
} else {
|
||||
ADD_IMM8(x3, x3, a);
|
||||
}
|
||||
AND_IMM8(x3, x3, 7);
|
||||
}
|
||||
ADD_IMM8(x2, xEmu, offsetof(x86emu_t, fpu_ld)+offsetof(fpu_ld_t, ld));
|
||||
MOVW(x14, sizeof(fpu_ld_t));
|
||||
MLA(x2, x3, x14, x2);
|
||||
LDR_IMM9(x14, ed, 0);
|
||||
STR_IMM9(x14, x2, 0);
|
||||
LDR_IMM9(x14, ed, 4);
|
||||
STR_IMM9(x14, x2, 4);
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
STRH_IMM8(x14, x2, 8);
|
||||
// convert 10bytes -> double
|
||||
CALL_1RD(FromLD, ed, x2, (1<<x3)|(1<<xFlags)|(1<<x2));
|
||||
// store ref to STld(0).uref, but can be unaligned...
|
||||
VMOVfrV_D(x3, x14, 0);
|
||||
// also, store result to ST0
|
||||
VMOVD(v1, 0);
|
||||
STR_IMM9(x3, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld));
|
||||
STR_IMM9(x14, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld)+4);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
@@ -306,6 +338,55 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
// get top in x3
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, top));
|
||||
int a = -dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUB_IMM8(x3, x3, -a);
|
||||
} else {
|
||||
ADD_IMM8(x3, x3, a);
|
||||
}
|
||||
AND_IMM8(x3, x3, 7);
|
||||
}
|
||||
// get STld(0)
|
||||
ADD_IMM8(x2, xEmu, offsetof(x86emu_t, fpu_ld)+offsetof(fpu_ld_t, ld));
|
||||
MOVW(x14, sizeof(fpu_ld_t));
|
||||
MLA(x2, x3, x14, x2);
|
||||
// compare uref with actual value, top is not used anymore, so x3 is free
|
||||
LDR_IMM9(x14, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld));
|
||||
LDR_IMM9(x3, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld)+4);
|
||||
VMOVtoV_D(v2, x14, x3);
|
||||
VCEQ_32(v2, v2, v1); // same?
|
||||
VMOVfrV_D(x14, x3, v2);
|
||||
TSTS_REG_LSL_IMM5(x14, x3, 0);
|
||||
B_MARK(cEQ); // different, do the conversion
|
||||
// same... copy STld(0).ld
|
||||
LDR_IMM9(x14, x2, 0);
|
||||
LDR_IMM9(x3, x2, 4);
|
||||
STR_IMM9(x14, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
LDRH_IMM8(x14, x2, 8);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
B_MARK2(c__);
|
||||
MARK;
|
||||
// different, call D2LD
|
||||
SUB_IMM8(xSP, xSP, 8);
|
||||
VSTR_64(v1, xSP, 0);
|
||||
PUSH(xSP, (1<<xEmu)|(1<<xFlags));
|
||||
ADD_IMM8(0, xSP, 8); //1st arg is &d
|
||||
if(ed!=x1) {
|
||||
MOV_REG_LSL_IMM5(x1, ed, 0); //2nd arg is ed
|
||||
}
|
||||
CALL_S(D2LD, -2, 0);
|
||||
POP(xSP, (1<<xEmu)|(1<<xFlags));
|
||||
ADD_IMM8(xSP, xSP, 8);
|
||||
MARK2;
|
||||
#endif
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -80,17 +80,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
i1 = x87_get_cache(dyn, ninst, 0, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
@@ -231,12 +221,12 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
ADD_IMM8(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
static const void* round_map[4] = {arm_fist64_0, arm_fist64_1, arm_fist64_2, arm_fist64_3};
|
||||
uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
@@ -31,7 +31,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t j32;
|
||||
uint8_t wback;
|
||||
uint8_t ed;
|
||||
int v0, v1, v2;
|
||||
int /*v0, */v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
@@ -39,7 +39,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v0);
|
||||
//MAYUSE(v0);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(nextop) {
|
||||
@@ -60,12 +60,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
ADD_IMM8(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
@@ -281,41 +281,39 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Hack for FILD/FISTP i64");
|
||||
} else {
|
||||
// Save xFlags to use it as scratch...
|
||||
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
// set STll(0).ll=i64 and ref=ST(0).q later (emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top])
|
||||
// get TOP
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(xFlags, xFlags, -a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
SUB_IMM8(x1, x1, -a);
|
||||
AND_IMM8(x1, x1, 7);
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(xFlags, xFlags, a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
ADD_IMM8(x1, x1, a);
|
||||
AND_IMM8(x1, x1, 7);
|
||||
}
|
||||
ADD_REG_LSL_IMM5(xFlags, xEmu, xFlags, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(xFlags, xFlags, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, xFlags, 8); // save ll
|
||||
// ed (and so x1) is not use anymore.
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x1, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(x1, x1, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, x1, 8); // save ll
|
||||
// continue with conversion
|
||||
MOVS_REG_LSR_IMM5(x14, x3, 31); // x14 is sign bit
|
||||
B_MARK(cEQ); // no NEG is no sign bit
|
||||
RSBS_IMM8(x2, x2, 0);
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
MARK;
|
||||
VMOVtoV(s0, x3);
|
||||
VMOVtoV(s0, x3); // last time x3 is used
|
||||
VCVT_F64_U32(v1, s0);
|
||||
VEOR(v2, v2, v2);
|
||||
MOVW(x1, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x1);
|
||||
MOVW(x3, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x3);
|
||||
VMUL_F64(v1, v1, v2); // v1 = double high part of i64
|
||||
VMOVtoV(s0, x2);
|
||||
VCVT_F64_U32(v2, s0);
|
||||
VADD_F64(v1, v1, v2);
|
||||
TSTS_IMM8(x14, 1);
|
||||
VNEG_F64_cond(cNE, v1, v1);
|
||||
VST1_64(v1, xFlags); // Store STll(0).ref
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
VST1_64(v1, x1); // Store STll(0).ref
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
@@ -343,16 +341,51 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0);
|
||||
#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);
|
||||
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;
|
||||
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;
|
||||
// load round mode
|
||||
LDRH_IMM8(x14, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x2, x14, 10, 2); // extract round...
|
||||
MOV32(x14, round_map);
|
||||
LDR_REG_LSL_IMM5(x2, x14, x2, 2);
|
||||
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);
|
||||
#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->x87stack;
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
@@ -407,6 +440,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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);
|
||||
|
||||
@@ -469,6 +469,7 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
@@ -521,6 +522,69 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHLD32 instruction, from s1, fill s2 , shift s3, store result in s1 using s4 and s3 as scratch
|
||||
void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
IFX(X_PEND) {
|
||||
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);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
CMPS_IMM8(s3, 0);
|
||||
IFX(F_OF) {
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_CF) {
|
||||
RSB_IMM8(s4, s3, 32);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVS_REG_LSL_REG(s1, s1, s3);
|
||||
} else {
|
||||
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);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
//else
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
RSB_IMM8(s3, s3, 32);
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSR_REG(s1, s1, s2, s3);
|
||||
} else {
|
||||
ORR_REG_LSR_REG(s1, s1, s2, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
|
||||
@@ -374,7 +374,7 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch. May destroy s2 also
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
@@ -401,10 +401,9 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
AND_IMM8(s2, 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);
|
||||
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);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
@@ -351,6 +352,10 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
DMB_ISH();
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
return dynarec66F0(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
@@ -637,7 +642,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MARK3;
|
||||
DMB_ISH();
|
||||
// done, do the cmp now
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x1, x2, x3, x14);}
|
||||
break;
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
@@ -678,16 +683,16 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
TSTS_IMM8(wback, 3); // anoying, all those test
|
||||
STR_IMM9_COND(cNE, gd, wback, 0);
|
||||
}
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);}
|
||||
} else {
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);}
|
||||
MOV_REG(ed, gd);
|
||||
}
|
||||
// done
|
||||
B_MARK3(c__); // not next, in case its called with a LOCK prefix
|
||||
MARK;
|
||||
// EAX != Ed
|
||||
emit_cmp32(dyn, ninst, xEAX, ed, x3, x14);
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, xEAX, ed, x3, x14);}
|
||||
MOV_REG(xEAX, ed);
|
||||
MARK3
|
||||
DMB_ISH();
|
||||
@@ -936,48 +941,54 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
DMB_ISH();
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 1);
|
||||
MARKLOCK;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
LDREXD_COND(cEQ, x2, wback);
|
||||
LDREX_COND(cNE, x2, wback);
|
||||
LDR_IMM9_COND(cNE, x3, wback, 4);
|
||||
} else {
|
||||
LDREXD(x2, wback);
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
DMB_ISH();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 1);
|
||||
MARKLOCK;
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
LDREXD_COND(cEQ, x2, wback);
|
||||
LDR_IMM9_COND(cNE, x3, wback, 4);
|
||||
LDREX_COND(cNE, x2, wback);
|
||||
} else {
|
||||
LDREXD(x2, wback);
|
||||
}
|
||||
CMPS_REG_LSL_IMM5(xEAX, x2, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x3, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
MOV_REG(x2, xEBX);
|
||||
MOV_REG(x3, xECX);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STREXD_COND(cEQ, x14, x2, wback);
|
||||
STREX_COND(cNE, x14, x2, wback);
|
||||
} else {
|
||||
STREXD(x14, x2, wback);
|
||||
}
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STR_IMM9_COND(cNE, x3, wback, 4);
|
||||
}
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x2);
|
||||
MOV_REG(xEDX, x3);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
DMB_ISH();
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
CMPS_REG_LSL_IMM5(xEAX, x2, 0);
|
||||
B_MARK(cNE); // EAX != Ed[0]
|
||||
CMPS_REG_LSL_IMM5(xEDX, x3, 0);
|
||||
B_MARK(cNE); // EDX != Ed[1]
|
||||
MOV_REG(x2, xEBX);
|
||||
MOV_REG(x3, xECX);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STREXD_COND(cEQ, x14, x2, wback);
|
||||
STREX_COND(cNE, x14, x2, wback);
|
||||
} else {
|
||||
STREXD(x14, x2, wback);
|
||||
}
|
||||
CMPS_IMM8(x14, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&7))) {
|
||||
TSTS_IMM8(wback, 7);
|
||||
STR_IMM9_COND(cNE, x3, wback, 4);
|
||||
}
|
||||
MOVW(x1, 1);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV_REG(xEAX, x2);
|
||||
MOV_REG(xEDX, x3);
|
||||
MOVW(x1, 0);
|
||||
MARK3;
|
||||
DMB_ISH();
|
||||
BFI(xFlags, x1, F_ZF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -993,7 +1004,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);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_inc32(dyn, ninst, ed, x3, x14);
|
||||
@@ -1030,7 +1041,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
@@ -159,7 +163,18 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSQRT_F64(v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -168,7 +183,18 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
@@ -176,7 +202,18 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
@@ -200,7 +237,18 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
@@ -219,7 +267,18 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
@@ -311,6 +370,14 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0);
|
||||
VMOV_64(v0, v1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
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)
|
||||
|
||||
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -98,10 +101,17 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity && (v0<16)) {
|
||||
VEORQ(v0, v0, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(v0*2, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -128,9 +138,15 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(q0, d1);
|
||||
}
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity && (v0<16)) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0);
|
||||
VSTR_32(v0*2, ed, fixedaddress);
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
@@ -614,6 +630,28 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ2DQ Gx, Em");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV_64(v0, v1);
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -66,12 +67,12 @@ void arm_fxtract(x86emu_t* emu)
|
||||
}
|
||||
void arm_fprem(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
int64_t tmp64s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp64s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
emu->sw.f.F87_C1 = (tmp64s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp64s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
}
|
||||
void arm_frndint(x86emu_t* emu)
|
||||
{
|
||||
@@ -116,6 +117,43 @@ void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
}
|
||||
}
|
||||
|
||||
int64_t arm_fist64_0(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = nearbyint(d);
|
||||
return tmp;
|
||||
}
|
||||
int64_t arm_fist64_1(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = floor(d);
|
||||
return tmp;
|
||||
}
|
||||
int64_t arm_fist64_2(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = ceil(d);
|
||||
return tmp;
|
||||
}
|
||||
int64_t arm_fist64_3(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = trunc(d);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
@@ -126,7 +164,7 @@ void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
LD2D(&STld(0).ld, &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
}
|
||||
|
||||
@@ -142,7 +180,7 @@ void arm_fsave(x86emu_t* emu, uint8_t* ed)
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +191,7 @@ void arm_frstor(x86emu_t* emu, uint8_t* ed)
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
@@ -162,48 +200,48 @@ void arm_frstor(x86emu_t* emu, uint8_t* ed)
|
||||
void arm_fprem1(x86emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
int64_t tmp64s = lrint(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp64s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
emu->sw.f.F87_C1 = (tmp64s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp64s>>1)&1);
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
}
|
||||
|
||||
|
||||
// Get a FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn)
|
||||
{
|
||||
return dyn->fpu_scratch++; // return an Sx
|
||||
return dyn->n.fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Get a FPU double scratch reg
|
||||
int fpu_get_scratch_double(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i = (dyn->fpu_scratch+1)&(~1);
|
||||
dyn->fpu_scratch = i+2;
|
||||
int i = (dyn->n.fpu_scratch+1)&(~1);
|
||||
dyn->n.fpu_scratch = i+2;
|
||||
return i/2; // return a Dx
|
||||
}
|
||||
// Get a FPU quad scratch reg
|
||||
int fpu_get_scratch_quad(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->fpu_scratch>4) {
|
||||
if(dyn->fpu_extra_qscratch) {
|
||||
if(dyn->n.fpu_scratch>4) {
|
||||
if(dyn->n.fpu_extra_qscratch) {
|
||||
dynarec_log(LOG_NONE, "Warning, Extra QScratch slot taken and need another one!\n");
|
||||
} else
|
||||
dyn->fpu_extra_qscratch = fpu_get_reg_quad(dyn, NEON_CACHE_SCR, 0);
|
||||
return dyn->fpu_extra_qscratch;
|
||||
dyn->n.fpu_extra_qscratch = fpu_get_reg_quad(dyn, NEON_CACHE_SCR, 0);
|
||||
return dyn->n.fpu_extra_qscratch;
|
||||
}
|
||||
int i = (dyn->fpu_scratch+3)&(~3);
|
||||
dyn->fpu_scratch = i+4;
|
||||
int i = (dyn->n.fpu_scratch+3)&(~3);
|
||||
dyn->n.fpu_scratch = i+4;
|
||||
return i/2; // Return a Dx, not a Qx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
if(dyn->fpu_extra_qscratch) {
|
||||
fpu_free_reg_quad(dyn, dyn->fpu_extra_qscratch);
|
||||
dyn->fpu_extra_qscratch = 0;
|
||||
dyn->n.fpu_scratch = 0;
|
||||
if(dyn->n.fpu_extra_qscratch) {
|
||||
fpu_free_reg_quad(dyn, dyn->n.fpu_extra_qscratch);
|
||||
dyn->n.fpu_extra_qscratch = 0;
|
||||
}
|
||||
}
|
||||
// Get a FPU double reg
|
||||
@@ -211,10 +249,13 @@ int fpu_get_reg_double(dynarec_arm_t* dyn, unsigned int t, unsigned int n)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
int i=0;
|
||||
while (dyn->fpuused[i]) ++i;
|
||||
dyn->fpuused[i] = 1;
|
||||
while (dyn->n.fpuused[i] && (i<24)) ++i;
|
||||
assert(i<24);
|
||||
|
||||
dyn->n.fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.news |= (1<<i);
|
||||
return i+FPUFIRST; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
@@ -222,7 +263,7 @@ void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = 0;
|
||||
dyn->n.fpuused[i] = 0;
|
||||
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;
|
||||
}
|
||||
@@ -230,36 +271,42 @@ void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn, unsigned int t, unsigned int n)
|
||||
{
|
||||
int i=0;
|
||||
while (dyn->fpuused[i] || dyn->fpuused[i+1]) i+=2;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 1;
|
||||
while ((dyn->n.fpuused[i] || dyn->n.fpuused[i+1]) && (i<24)) i+=2;
|
||||
assert(i<24);
|
||||
dyn->n.fpuused[i] = dyn->n.fpuused[i+1] = 1;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i+1].t = t;
|
||||
dyn->n.neoncache[i+1].n = n;
|
||||
dyn->n.news |= (3<<i);
|
||||
return i+FPUFIRST; // Return a Dx, not a Qx
|
||||
}
|
||||
// Free a FPU quad reg
|
||||
void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
|
||||
dyn->n.fpuused[i] = dyn->n.fpuused[i+1] = 0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
dyn->n.neoncache[i+1].v = 0;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_reg = 0;
|
||||
dyn->n.fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i) {
|
||||
dyn->fpuused[i]=0;
|
||||
dyn->n.fpuused[i]=0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if(!dyn->insts)
|
||||
return NEON_CACHE_ST_D;
|
||||
if (dyn->insts[ninst].n.swapped) {
|
||||
if(dyn->insts[ninst].n.combined1 == a)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if(dyn->insts[ninst].n.combined2 == a)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
@@ -283,114 +330,141 @@ int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if(a+dyn->insts[ninst].n.stack_next-st<0)
|
||||
/*if(a+dyn->insts[ninst].n.stack_next-st<0)
|
||||
// The STx has been pushed at the end of instructon, so stop going back
|
||||
return -1;
|
||||
return -1;*/
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a+dyn->insts[ninst].n.stack-st)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a+dyn->insts[ninst].n.stack-st)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a, int st)
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->n.neoncache[i].n==a+dyn->n.stack-st)
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st);
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st);
|
||||
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
|
||||
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
if(a == dyn->insts[ninst].n.combined1) {
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, dyn->insts[ninst].n.combined2, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined2 %d i=%d\n", ninst, dyn->insts[ninst].n.combined2 ,i);
|
||||
if(a == dyn->insts[ninst].n.combined1 || a == dyn->insts[ninst].n.combined2) {
|
||||
if(a == dyn->insts[ninst].n.combined1) {
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
} else
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_combined, ninst=%d combined%c %d i=%d (stack:%d/%d)\n", ninst, (a == dyn->insts[ninst].n.combined2)?'2':'1', a ,i, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
if(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, dyn->insts[ninst].n.combined2, st);
|
||||
if(!dyn->insts[ninst].n.barrier)
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, a-dyn->insts[ninst].n.stack_push);
|
||||
// go forward is combined is not pop'd
|
||||
if(dyn->insts[ninst].n.stack_next-dyn->insts[ninst].n.stack<=dyn->insts[ninst].n.combined2)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, dyn->insts[ninst].n.combined2, st);
|
||||
}
|
||||
} else if(a == dyn->insts[ninst].n.combined2) {
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, dyn->insts[ninst].n.combined1, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined1 %d i=%d\n", ninst, dyn->insts[ninst].n.combined1 ,i);
|
||||
if(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, dyn->insts[ninst].n.combined1, st);
|
||||
// go forward is combined is not pop'd
|
||||
if(dyn->insts[ninst].n.stack_next-dyn->insts[ninst].n.stack<=dyn->insts[ninst].n.combined1)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, dyn->insts[ninst].n.combined1, st);
|
||||
if(a-dyn->insts[ninst].n.stack_pop>=0)
|
||||
if(!dyn->insts[ninst+1].n.barrier)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, a-dyn->insts[ninst].n.stack_pop);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
if(dyn->insts[ninst+1].n.barrier)
|
||||
return;
|
||||
while(ninst>=0) {
|
||||
int i = neoncache_get_st_f(dyn, ninst, a, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d/%d, i=%d\n", ninst, a, st, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
a+=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: add pop'd ST (going backward)
|
||||
int i = neoncache_get_st_f(dyn, ninst, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d, i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
a+=dyn->insts[ninst].n.stack-st; // adjust STx
|
||||
st = dyn->insts[ninst].n.stack; // new stack depth
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d/%d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, st, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a, st);
|
||||
if(dyn->insts[ninst].n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
} else {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
|
||||
--ninst;
|
||||
if(ninst<0 || a<0 || dyn->insts[ninst].n.barrier)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
|
||||
{
|
||||
while(ninst<maxinst) {
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d/%d, i=%d\n", ninst, a, st, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
while((ninst!=-1) && (ninst<maxinst) && (a>=0)) {
|
||||
a+=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: add push'd ST (going forward)
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && dyn->insts[ninst].n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d(%d/%d), i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
a+=dyn->insts[ninst].n.stack-st; // adjust STx
|
||||
st = dyn->insts[ninst].n.stack; // new stack depth
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d/%d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, st, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a, st);
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && !dyn->insts[ninst].n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
++ninst;
|
||||
a-=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: remove pop'd ST (going forward)
|
||||
if(dyn->insts[ninst].x86.has_next && !dyn->insts[ninst].n.barrier)
|
||||
++ninst;
|
||||
else
|
||||
ninst=-1;
|
||||
}
|
||||
neoncache_promote_double(dyn, ninst, a, st);
|
||||
if(ninst==maxinst)
|
||||
neoncache_promote_double(dyn, ninst, a);
|
||||
}
|
||||
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
int i = neoncache_get_current_st_f(dyn, a, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d/%d i=%d\n", ninst, a, st, dyn->n.stack, i);
|
||||
int i = neoncache_get_current_st_f(dyn, a);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d i=%d\n", ninst, a, dyn->n.stack, i);
|
||||
if(i<0) return;
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
a+=dyn->n.stack-st;
|
||||
st = dyn->n.stack;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if(dyn->n.combined1 || dyn->n.combined2) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined2, st);
|
||||
else if(dyn->n.combined2 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined1, st);
|
||||
if(dyn->n.swapped) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d swapped! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
a = dyn->n.combined2;
|
||||
else if(dyn->n.combined2 == a)
|
||||
a = dyn->n.combined1;
|
||||
} else {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined2);
|
||||
else if(dyn->n.combined2 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined1);
|
||||
}
|
||||
}
|
||||
if(!ninst) return;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, ninst, a, st);
|
||||
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
|
||||
if(!ninst || a<0) return;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, ninst, a);
|
||||
}
|
||||
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
@@ -403,6 +477,158 @@ int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
if(dyn->insts[ninst].pred[i]==pred)
|
||||
return pred;
|
||||
return -1;
|
||||
}
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst) {
|
||||
if((ninst<=0) || !dyn->insts[ninst].pred_sz)
|
||||
return -1;
|
||||
if(isPred(dyn, ninst, ninst-1)!=-1)
|
||||
return ninst-1;
|
||||
return dyn->insts[ninst].pred[0];
|
||||
}
|
||||
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int i2 = dyn->insts[ninst].x86.jmp_insts;
|
||||
if(i2<0)
|
||||
return 1;
|
||||
if((dyn->insts[i2].x86.barrier&BARRIER_FLOAT))
|
||||
return ((dyn->insts[ninst].x86.barrier&BARRIER_FLOAT))?0:1; // if the barrier as already been apply, no transform needed
|
||||
int ret = 0;
|
||||
if(!i2) { // just purge
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 1;
|
||||
}
|
||||
for(int i=0; i<24 && !ret; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Check if ninst can be compatible to i2
|
||||
if(dyn->insts[ninst].n.stack_next != dyn->insts[i2].n.stack-dyn->insts[i2].n.stack_push) {
|
||||
return 1;
|
||||
}
|
||||
neoncache_t cache_i2 = dyn->insts[i2].n;
|
||||
neoncacheUnwind(&cache_i2);
|
||||
|
||||
for(int i=0; i<24; ++i) {
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
ret = 1;
|
||||
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
|
||||
if(dyn->insts[ninst].n.neoncache[i].n!=cache_i2.neoncache[i].n) { // not the same x86 reg
|
||||
ret = 1;
|
||||
}
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{/* nothing */ }
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
} else if(cache_i2.neoncache[i].v)
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neoncacheUnwind(neoncache_t* cache)
|
||||
{
|
||||
if(cache->swapped) {
|
||||
// unswap
|
||||
int a = -1;
|
||||
int b = -1;
|
||||
for(int j=0; j<24 && ((a==-1) || (b==-1)); ++j)
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n == cache->combined1)
|
||||
a = j;
|
||||
else if(cache->neoncache[j].n == cache->combined2)
|
||||
b = j;
|
||||
}
|
||||
if(a!=-1 && b!=-1) {
|
||||
int tmp = cache->neoncache[a].n;
|
||||
cache->neoncache[a].n = cache->neoncache[b].n;
|
||||
cache->neoncache[b].n = tmp;
|
||||
}
|
||||
cache->swapped = 0;
|
||||
cache->combined1 = cache->combined2 = 0;
|
||||
}
|
||||
if(cache->news) {
|
||||
// reove the newly created neoncache
|
||||
for(int i=0; i<24; ++i)
|
||||
if(cache->news&(1<<i))
|
||||
cache->neoncache[i].v = 0;
|
||||
cache->news = 0;
|
||||
}
|
||||
if(cache->stack_push) {
|
||||
// unpush
|
||||
for(int j=0; j<24; ++j) {
|
||||
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(cache->neoncache[j].n<cache->stack_push)
|
||||
cache->neoncache[j].v = 0;
|
||||
else
|
||||
cache->neoncache[j].n-=cache->stack_push;
|
||||
}
|
||||
}
|
||||
cache->x87stack-=cache->stack_push;
|
||||
cache->stack-=cache->stack_push;
|
||||
cache->stack_push = 0;
|
||||
}
|
||||
cache->x87stack+=cache->stack_pop;
|
||||
cache->stack_next = cache->stack;
|
||||
cache->stack_pop = 0;
|
||||
cache->barrier = 0;
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
cache->mmxcount = 0;
|
||||
cache->fpu_scratch = 0;
|
||||
cache->fpu_extra_qscratch = 0;
|
||||
cache->fpu_reg = 0;
|
||||
for(int i=0; i<8; ++i) {
|
||||
cache->x87cache[i] = -1;
|
||||
cache->mmxcache[i] = -1;
|
||||
cache->ssecache[i].v = -1;
|
||||
cache->x87reg[i] = 0;
|
||||
}
|
||||
int x87reg = 0;
|
||||
for(int i=0; i<24; ++i) {
|
||||
if(cache->neoncache[i].v) {
|
||||
cache->fpuused[i] = 1;
|
||||
switch (cache->neoncache[i].t) {
|
||||
case NEON_CACHE_MM:
|
||||
cache->mmxcache[cache->neoncache[i].n] = i+FPUFIRST;
|
||||
++cache->mmxcount;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_XMMW:
|
||||
cache->ssecache[cache->neoncache[i].n].reg = i+FPUFIRST;
|
||||
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
|
||||
++cache->fpu_reg;
|
||||
++i; // next next
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
case NEON_CACHE_ST_D:
|
||||
cache->x87cache[x87reg] = cache->neoncache[i].n;
|
||||
cache->x87reg[x87reg] = i+FPUFIRST;
|
||||
++x87reg;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_SCR:
|
||||
cache->fpuused[i] = 0;
|
||||
cache->neoncache[i].v = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cache->fpuused[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
@@ -496,3 +722,35 @@ int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int
|
||||
#undef PK
|
||||
}
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
static char buff[20];
|
||||
switch(t) {
|
||||
case NEON_CACHE_ST_D: sprintf(buff, "ST%d", n); break;
|
||||
case NEON_CACHE_ST_F: sprintf(buff, "st%d", n); break;
|
||||
case NEON_CACHE_MM: sprintf(buff, "MM%d", n); break;
|
||||
case NEON_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
|
||||
case NEON_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
|
||||
case NEON_CACHE_SCR: sprintf(buff, "Scratch"); break;
|
||||
case NEON_CACHE_NONE: buff[0]='\0'; break;
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
// check flags cache
|
||||
if(dyn->insts[ninst].f_entry.dfnone || dyn->insts[ninst].f_entry.pending)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].x86.state_flags)
|
||||
return 0;
|
||||
// check neoncache
|
||||
neoncache_t* n = &dyn->insts[ninst].n;
|
||||
if(n->news || n->stack || n->stack_next)
|
||||
return 0;
|
||||
for(int i=0; i<24; ++i)
|
||||
if(n->neoncache[i].v)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -23,6 +23,11 @@ void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x86emu_t* emu);
|
||||
|
||||
int64_t arm_fist64_0(double d);
|
||||
int64_t arm_fist64_1(double d);
|
||||
int64_t arm_fist64_2(double d);
|
||||
int64_t arm_fist64_3(double d);
|
||||
|
||||
void arm_ud(x86emu_t* emu);
|
||||
|
||||
#define FPUFIRST 8
|
||||
@@ -50,13 +55,29 @@ void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
// Get type for STx
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or DOUBLE
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual type for STx
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual STx is FLOAT or DOUBLE
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a);
|
||||
// Back-propagate a change float->double
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Combine and propagate if needed (pass 1 only)
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
|
||||
|
||||
// FPU Cache transformation (for loops)
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
|
||||
// Do the GETED, but don't emit anything...
|
||||
@@ -65,4 +86,6 @@ uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
+731
-234
File diff suppressed because it is too large.
Load diff
@@ -76,7 +76,8 @@
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, O, 0);\
|
||||
ADD_REG_LSL_IMM5(x2, wback, O, 0); \
|
||||
if(wback != x2) wback = x2; \
|
||||
LDR_IMM9(x1, wback, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -153,8 +154,9 @@
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, i, 0); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
ADD_REG_LSL_IMM5(x3, wback, i, 0); \
|
||||
if(wback!=x3) wback = x3; \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
@@ -211,6 +213,12 @@
|
||||
#define CALL_2D(F, M) call_d(dyn, ninst, F, NULL, 2, x3, -1, M, 0)
|
||||
// CALL_1DD will use x3 for the call address. Return value in D0, 1 ARG in D0, cals 2 functions in a row
|
||||
#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
|
||||
#define CALL_1DR(R, S, M) call_dr(dyn, ninst, R, 1, S, -1, -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);
|
||||
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
@@ -239,7 +247,7 @@
|
||||
Bcond(cond, j32)
|
||||
// Branch to next instruction if cond (use j32)
|
||||
#define B_NEXT(cond) \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
|
||||
j32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKSEG if cond (use j32)
|
||||
#define B_MARKSEG(cond) \
|
||||
@@ -284,15 +292,16 @@
|
||||
} \
|
||||
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=1;}
|
||||
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->dfnone = 0
|
||||
#define SET_DFOK() dyn->dfnone = 1
|
||||
#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_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET && dyn->state_flags!=SF_SET_PENDING) { \
|
||||
if(dyn->state_flags!=SF_PENDING) { \
|
||||
if((dyn->f.pending!=SF_SET) \
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) { \
|
||||
if(dyn->f.pending!=SF_PENDING) { \
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0); \
|
||||
j32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
@@ -300,16 +309,28 @@
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
// SF_MAYSET doesn't change the flags status cache
|
||||
// it also doesn't consume any needed flags
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)/*|X_PEND*/)))) \
|
||||
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A)|X_PEND)); \
|
||||
dyn->state_flags = (B==SF_SUBSET)?SF_SET: \
|
||||
((B==SF_SET_PENDING && !(dyn->insts[ninst].x86.need_flags&X_PEND)?SF_SET:B))
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->f.pending!=SF_SET \
|
||||
&& (B==SF_SUBSET || B==SF_SUBSET_PENDING) \
|
||||
&& (dyn->insts[ninst].x86.need_flags&(~((A)|((B==SF_SUBSET_PENDING)?X_PEND:0))))) \
|
||||
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A)|X_PEND)); \
|
||||
if(dyn->insts[ninst].x86.need_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
|
||||
case SF_SUBSET_PENDING: \
|
||||
case SF_SET_PENDING: \
|
||||
dyn->f.pending = (dyn->insts[ninst].x86.need_flags&X_PEND)?SF_SET_PENDING:SF_SET; \
|
||||
break; \
|
||||
case SF_MAYSET: break; \
|
||||
} else dyn->f.pending = SF_SET
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A, C)
|
||||
@@ -327,10 +348,7 @@
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x86.need_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x86.need_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
#ifndef NEW_BARRIER_INST
|
||||
#define NEW_BARRIER_INST
|
||||
#define DEFAULT *ok = -1; BARRIER(BARRIER_NOFLAGS)
|
||||
#endif
|
||||
|
||||
#if STEP < 2
|
||||
@@ -368,6 +386,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define dynarecDF STEPNAME(dynarecDF)
|
||||
#define dynarecF0 STEPNAME(dynarecF0)
|
||||
#define dynarec660F STEPNAME(dynarec660F)
|
||||
#define dynarec66F0 STEPNAME(dynarec66F0)
|
||||
#define dynarecF20F STEPNAME(dynarecF20F)
|
||||
#define dynarecF30F STEPNAME(dynarecF30F)
|
||||
|
||||
@@ -380,6 +399,8 @@ 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_dr STEPNAME(call_dr_)
|
||||
#define call_rd STEPNAME(call_rd_)
|
||||
#define grab_fsdata STEPNAME(grab_fsdata_)
|
||||
#define grab_tlsdata STEPNAME(grab_tlsdata_)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
@@ -454,6 +475,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
#define emit_shrd32 STEPNAME(emit_shrd32)
|
||||
#define emit_shld32 STEPNAME(emit_shld32)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
@@ -471,6 +493,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define x87_swapreg STEPNAME(x87_swapreg)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
@@ -492,6 +515,8 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
// put back (if needed) the single reg in place
|
||||
#define fpu_putback_single_reg STEPNAME(fpu_putback_single_reg)
|
||||
|
||||
#define fpuCacheTransform STEPNAME(fpuCacheTransform)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly);
|
||||
|
||||
@@ -507,10 +532,10 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
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_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);
|
||||
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_unlock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -583,6 +608,7 @@ void emit_ror8c(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);
|
||||
|
||||
@@ -615,9 +641,19 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// swap 2 x87 regs
|
||||
void x87_swapreg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int b);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
#if STEP < 2
|
||||
#define CHECK_CACHE() 0
|
||||
#else
|
||||
#define CHECK_CACHE() fpuCacheNeedsTransform(dyn, ninst)
|
||||
#endif
|
||||
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
|
||||
@@ -656,7 +692,7 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst);
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
// purge the FPU cache (needs 3 scratch registers) next=1 if for a conditionnal branch jumping out of block (no tracking updated)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
@@ -688,6 +724,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
|
||||
|
||||
+116
-19
@@ -36,15 +36,71 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
fpu_reset(dyn, ninst);
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
fpu_reset(dyn);
|
||||
int reset_n = -1;
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
ip = addr;
|
||||
if((dyn->insts[ninst].x86.barrier==1)) {
|
||||
NEW_BARRIER_INST;
|
||||
if (reset_n!=-1) {
|
||||
if(reset_n==-2) {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
} else {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box86_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
fpu_reset(dyn);
|
||||
}
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLAGS) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
}
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
@@ -58,6 +114,9 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
NEW_INST;
|
||||
fpu_reset_scratch(dyn);
|
||||
#ifdef HAVE_TRACE
|
||||
@@ -80,43 +139,81 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
int next = ninst+1;
|
||||
#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);
|
||||
if(dyn->insts[next].x86.barrier&BARRIER_FLAGS) {
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
}
|
||||
}
|
||||
#if STEP != 0
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
while(ii<dyn->size && !dyn->insts[ii].pred_sz)
|
||||
++ii;
|
||||
if((dyn->insts[ii].x86.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
reset_n = -2; // hack to say Barrier!
|
||||
else {
|
||||
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are availble
|
||||
if(reset_n==-1) {
|
||||
reset_n = -2;
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#if STEP == 0
|
||||
if(!ok && !need_epilog && box86_dynarec_bigblock && getProtection(addr+3))
|
||||
#else
|
||||
if(!ok && !need_epilog && box86_dynarec_bigblock && getProtection(addr+3)&~PROT_CUSTOM)
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
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);
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault((void*)addr))
|
||||
if((ok && !isJumpTableDefault((void*)addr) && (box86_dynarec_bigblock<2)) ||
|
||||
(ok && dyn->size >= 2000))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 3
|
||||
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x86.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
#if STEP == 0
|
||||
if(dyn->insts[ninst].x86.set_flags)
|
||||
dyn->insts[ninst].x86.default_need |= X_PEND;
|
||||
else
|
||||
dyn->insts[ninst].x86.use_flags |= X_PEND;
|
||||
#endif
|
||||
BARRIER(2);
|
||||
++ninst;
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
|
||||
@@ -5,12 +5,20 @@
|
||||
dyn->insts[ninst].x86.addr = addr;\
|
||||
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr
|
||||
#define MESSAGE(A, ...)
|
||||
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
|
||||
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x86.use_flags = A; dyn->f.dfnone = 1;\
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x86.set_flags = A; \
|
||||
if(B!=SF_MAYSET) { \
|
||||
dyn->insts[ninst].x86.state_flags = B; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0; \
|
||||
}
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x86.barrier = A
|
||||
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)(A)); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#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 NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
@@ -19,14 +27,20 @@
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
dyn->insts[ninst].x86.addr = ip; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;}
|
||||
|
||||
#define INST_EPILOG
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].x86.has_next = ok;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box86_dynarec_log>=LOG_INFO) {\
|
||||
if(box86_dynarec_log>=LOG_INFO || box86_dynarec_dump) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define READFLAGS(A)
|
||||
#define SETFLAGS(A,B)
|
||||
|
||||
#define NEW_INST dyn->n.combined1 = dyn->n.combined2 = 0
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0
|
||||
|
||||
#define INST_EPILOG dyn->insts[ninst].n = dyn->n
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
|
||||
#define INST_NAME(name)
|
||||
@@ -3,7 +3,11 @@
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
|
||||
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
if(ninst && isInstClean(dyn, ninst)) \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
|
||||
@@ -7,46 +7,55 @@
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box86_dynarec_dump) {\
|
||||
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d, set=%X, use=%X, need=%X", \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), set=%X, use=%X, need=%X", \
|
||||
(box86_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x86.barrier, \
|
||||
dyn->insts[ninst].x86.state_flags, \
|
||||
dyn->state_flags, \
|
||||
dyn->f.pending, \
|
||||
dyn->f.dfnone, \
|
||||
dyn->insts[ninst].x86.set_flags, \
|
||||
dyn->insts[ninst].x86.use_flags, \
|
||||
dyn->insts[ninst].x86.need_flags); \
|
||||
if(dyn->insts[ninst].pred_sz) { \
|
||||
dynarec_log(LOG_NONE, ", pred="); \
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)\
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);\
|
||||
} \
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts>=0)\
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x86.jmp_insts);\
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts==-1)\
|
||||
dynarec_log(LOG_NONE, ", jmp=out");\
|
||||
for(int ii=0; ii<24; ++ii) { \
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) { \
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:ST%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:st%d", (ii+8)*2, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:MM%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:XMM%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:xmm%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:Scratch", ii+8); break; \
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", (ii+8)*2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_NONE: \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next) \
|
||||
printf_log(LOG_NONE, " X87:%d/%d", dyn->n.stack, dyn->insts[ninst].n.stack_next);\
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
printf_log(LOG_NONE, " CMB:%d/%d", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define NEW_BARRIER_INST \
|
||||
if(ninst) { \
|
||||
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
|
||||
++dyn->sons_size; \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack) \
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack); \
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
#define NEON_CACHE_ST_F 2
|
||||
@@ -20,31 +22,6 @@ typedef union neon_cache_s {
|
||||
unsigned int n:4; // reg number
|
||||
};
|
||||
} neon_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x86_t x86;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
neoncache_t n;
|
||||
} instruction_arm_t;
|
||||
|
||||
typedef union sse_cache_s {
|
||||
int v;
|
||||
struct {
|
||||
@@ -52,6 +29,57 @@ typedef union sse_cache_s {
|
||||
uint8_t write;
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
// Neon cache
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
int8_t stack_push;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int8_t 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
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch;// scratch counter
|
||||
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x86_t x86;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
int barrier_maybe;
|
||||
flagcache_t f_exit; // flags status at end of intruction
|
||||
neoncache_t n; // neoncache at end of intruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_arm_t;
|
||||
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm_t *insts;
|
||||
@@ -62,25 +90,15 @@ typedef struct dynarec_arm_s {
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
int arm_size; // size of emitted arm code
|
||||
int state_flags;// actual state for on-demand flags
|
||||
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int x87reg[8]; // reg used for x87cache entry
|
||||
int mmxcache[8];// cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
flagcache_t f;
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
int x87stack; // cache stack counter
|
||||
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
} dynarec_arm_t;
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
#define BARRIER_NONE 0
|
||||
#define BARRIER_FLAGS 1
|
||||
#define BARRIER_FLOAT 2
|
||||
#define BARRIER_FULL 3
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
@@ -9,27 +14,32 @@
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x1000)
|
||||
#define X_PEND (0x80)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_SET_PENDING 3
|
||||
#define SF_MAYSET 4
|
||||
#define SF_SUBSET 5
|
||||
#define SF_SET_PENDING (SF_SET|SF_PENDING)
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
#define SF_MAYSET 8
|
||||
|
||||
typedef struct instruction_x86_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
int barrier; // next instruction is a jump point, so no optim allowed
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_cond; // 1 of conditionnal jump
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint32_t use_flags; // 0 or combination of X_?F
|
||||
uint32_t set_flags; // 0 or combination of X_?F
|
||||
uint32_t need_flags; // calculated
|
||||
int state_flags; // One of SF_XXX state
|
||||
uint8_t jmp_cond; // 1 of conditionnal jump
|
||||
uint8_t has_next; // does this opcode can continue to the next?
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
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
|
||||
uint8_t default_need;// 0 or X_PEND basically
|
||||
uint8_t need_flags; // calculated
|
||||
uint8_t old_use; // calculated
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
|
||||
@@ -83,7 +83,7 @@ INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d64 &g&g param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
|
||||
|
||||
+558
-232
File diff suppressed because it is too large.
Load diff
@@ -241,6 +241,10 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->initarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
if(val)
|
||||
printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
@@ -350,6 +354,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
version&=0x7fff; // remove bit15 that switch between hidden/public
|
||||
if(!h->VerNeed || (version<2))
|
||||
return NULL;
|
||||
/*if(version==1)
|
||||
|
||||
+47
-17
@@ -60,6 +60,18 @@
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
_0f_0x0D: /* PREFETCH group */
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1: /* PREFETCHW */
|
||||
GET_ED; //nothing for now. Could maybe use some builtin prefetch instruction
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x10: /* MOVUPS Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -227,7 +239,7 @@
|
||||
if(EM->ub[i]&128)
|
||||
GM.ub[i] = 0;
|
||||
else
|
||||
GM.ub[i] = eax1.ub[EM->ub[i]&7];
|
||||
GM.ub[i] = eam1.ub[EM->ub[i]&7];
|
||||
}
|
||||
break;
|
||||
case 0x04: /* PMADDUBSW Gm,Em */
|
||||
@@ -288,7 +300,7 @@
|
||||
_0f_0x3A:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0xF: /* palignr */
|
||||
case 0x0F: /* palignr */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
tmp8u = F8;
|
||||
@@ -297,8 +309,10 @@
|
||||
} else if (tmp8u > 8) {
|
||||
tmp8u -= 8;
|
||||
GM.q >>= tmp8u*8;
|
||||
} else if (tmp8u == 8 || tmp8u == 0) {
|
||||
|
||||
} else if (tmp8u == 8) {
|
||||
// nothing
|
||||
} else if (tmp8u == 0) {
|
||||
GM.q = EM->q;
|
||||
} else {
|
||||
GM.q <<= (8-tmp8u)*8;
|
||||
GM.q |= (EM->q >> tmp8u*8);
|
||||
@@ -435,8 +449,18 @@
|
||||
_0f_0x52: /* RSQRTPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.f[i] = 1.0f/sqrtf(EX->f[i]);
|
||||
for(int i=0; i<4; ++i) {
|
||||
if(EX->f[i]==0)
|
||||
GX.f[i] = 1.0f/EX->f[i];
|
||||
else if (EX->f[i]<0)
|
||||
GX.f[i] = NAN;
|
||||
else if (isnan(EX->f[i]))
|
||||
GX.f[i] = EX->f[i];
|
||||
else if (isinf(EX->f[i]))
|
||||
GX.f[i] = 0.0;
|
||||
else
|
||||
GX.f[i] = 1.0f/sqrtf(EX->f[i]);
|
||||
}
|
||||
NEXT;
|
||||
_0f_0x53: /* RCPPS Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -1093,19 +1117,25 @@
|
||||
GX.q[1] = eax1.q[1];
|
||||
NEXT;
|
||||
_0f_0xC7: /* CMPXCHG8B Gq */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
CHECK_FLAGS(emu);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
_0f_0xC8:
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0x1E: /* PUSH DS */
|
||||
Push16(emu, emu->segs[_DS]);
|
||||
NEXT;
|
||||
_66_0x1F: /* POP DS */
|
||||
emu->segs[_DS] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_DS] = 0;
|
||||
@@ -482,6 +485,11 @@
|
||||
R_ECX = tmp32u;
|
||||
NEXT;
|
||||
|
||||
_66_0xF5: /* CMC */
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!ACCESS_FLAG(F_CF), F_CF);
|
||||
NEXT;
|
||||
|
||||
_66_0xF7: /* GRP3 Ew(,Iw) */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
ll = ST(nextop&7).sq;
|
||||
ST(nextop&7).sq = ST0.sq;
|
||||
ST0.sq = ll;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
|
||||
case 0xD0: /* FNOP */
|
||||
@@ -30,9 +31,11 @@
|
||||
|
||||
case 0xE0: /* FCHS */
|
||||
ST0.d = -ST0.d;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xE1: /* FABS */
|
||||
ST0.d = fabs(ST0.d);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
|
||||
case 0xE4: /* FTST */
|
||||
@@ -73,25 +76,30 @@
|
||||
|
||||
case 0xF0: /* F2XM1 */
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF1: /* FYL2X */
|
||||
ST(1).d *= log2(ST0.d);
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF2: /* FPTAN */
|
||||
ST0.d = tan(ST0.d);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = 1.0;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xF3: /* FPATAN */
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
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;
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
|
||||
case 0xF8: /* FPREM */
|
||||
@@ -146,30 +154,37 @@
|
||||
case 0xF9: /* FYL2XP1 */
|
||||
ST(1).d *= log2(ST0.d + 1.0);
|
||||
fpu_do_pop(emu);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFA: /* FSQRT */
|
||||
ST0.d = sqrt(ST0.d);
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFB: /* FSINCOS */
|
||||
fpu_do_push(emu);
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFC: /* FRNDINT */
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
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));
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFE: /* FSIN */
|
||||
ST0.d = sin(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
case 0xFF: /* FCOS */
|
||||
ST0.d = cos(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
memcpy(&STld(0).ld, ED, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
LD2D(&STld(0).ld, &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
|
||||
+30
-2
@@ -53,17 +53,32 @@
|
||||
case 0x51: /* SQRTSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] = sqrt(EX->d[0]);
|
||||
if(EX->d[0]<0.0 )
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
GX.d[0] = sqrt(EX->d[0]);
|
||||
break;
|
||||
|
||||
case 0x58: /* ADDSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
// add generate a -NAN only if doing inf + -inf
|
||||
if((isinf(GX.d[0]) && isinf(EX->d[0]) && (EX->q[0]&0x8000000000000000LL)!=(GX.q[0]&0x8000000000000000LL)))
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[0] += EX->d[0];
|
||||
break;
|
||||
case 0x59: /* MULSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
// mul generate a -NAN only if doing (+/-)inf * (+/-)0
|
||||
if((isinf(GX.d[0]) && EX->d[0]==0.0) || (isinf(EX->d[0]) && GX.d[0]==0.0))
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[0] *= EX->d[0];
|
||||
break;
|
||||
case 0x5A: /* CVTSD2SS Gx, Ex */
|
||||
@@ -75,18 +90,31 @@
|
||||
case 0x5C: /* SUBSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
// sub generate a -NAN only if doing inf - inf
|
||||
if((isinf(GX.d[0]) && isinf(EX->d[0]) && (EX->q[0]&0x8000000000000000LL)==(GX.q[0]&0x8000000000000000LL)))
|
||||
GX.d[0] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[0] -= EX->d[0];
|
||||
break;
|
||||
case 0x5D: /* MINSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if (isnan(GX.d[0]) || isnan(EX->d[0]) || isless(EX->d[0], GX.d[0]))
|
||||
if (isnan(GX.d[0]) || isnan(EX->d[0]) || (EX->d[0]<=GX.d[0]))
|
||||
GX.d[0] = EX->d[0];
|
||||
break;
|
||||
case 0x5E: /* DIVSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[0]) || isnan(EX->d[0]);
|
||||
#endif
|
||||
GX.d[0] /= EX->d[0];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[0]))
|
||||
GX.d[0] = -NAN;
|
||||
#endif
|
||||
break;
|
||||
case 0x5F: /* MAXSD Gx, Ex */
|
||||
nextop = F8;
|
||||
|
||||
+2
-2
@@ -323,14 +323,14 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
}
|
||||
// start with FPU regs...
|
||||
if(emu->fpu_stack) {
|
||||
if(emu->fpu_stack<8)
|
||||
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, " ");
|
||||
if(i==3) strcat(buff, "\n");
|
||||
}
|
||||
else {
|
||||
sprintf(tmp, "Warning, incoherent fpu_stack=%d", emu->fpu_stack);
|
||||
|
||||
+37
-24
@@ -119,16 +119,20 @@ void x86Int3(x86emu_t* emu)
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "shm_open")) {
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strcmp(s, "mkdir")==0) {
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "fopen")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
perr = 1;
|
||||
perr = 2;
|
||||
} else if(!strcmp(s, "freopen")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", %p)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
perr = 2;
|
||||
} else if(!strcmp(s, "fopen64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
perr = 2;
|
||||
@@ -138,9 +142,14 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(strstr(s, "getenv")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
post = 2;
|
||||
} else if(strstr(s, "putenv")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "pread")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u, %d)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12), *(int32_t*)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "read")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "ioctl")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, 0x%x, %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(int32_t*)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
@@ -150,13 +159,13 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "rindex")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "my___xstat64")==s) {
|
||||
} else if(strstr(s, "__xstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strcmp(s, "my___xstat")==0) {
|
||||
} else if(strcmp(s, "__xstat")==0) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "my___lxstat64")==s) {
|
||||
} else if(strstr(s, "__lxstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "sem_timedwait")==s) {
|
||||
@@ -174,10 +183,10 @@ void x86Int3(x86emu_t* emu)
|
||||
int16_t* p16 = *(int16_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/0x%x], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "my_mmap64")) {
|
||||
} else if(!strcmp(s, "mmap64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %lld)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int64_t*)(R_ESP+24));
|
||||
perr = 3;
|
||||
} else if(!strcmp(s, "my_mmap")) {
|
||||
} else if(!strcmp(s, "mmap")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %d)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int*)(R_ESP+24));
|
||||
perr = 3;
|
||||
} else if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
|
||||
@@ -190,54 +199,58 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%.127s\", \"%.127s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "strlen")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
|
||||
} else if(strstr(s, "my_vsnprintf")==s) {
|
||||
} else if(strstr(s, "vsnprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_vsprintf")==s) {
|
||||
} else if(strstr(s, "vsprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my___vsprintf_chk")==s) {
|
||||
} else if(strstr(s, "__vsprintf_chk")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %d, %zu, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(int*)(R_ESP+8), *(size_t*)(R_ESP+12), *(char**)(R_ESP+16), *(void**)(R_ESP+20));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my___snprintf_chk")==s) {
|
||||
} else if(strstr(s, "__snprintf_chk")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %d, %d, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(char**)(R_ESP+20), *(void**)(R_ESP+24));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_snprintf")==s) {
|
||||
} else if(strstr(s, "snprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(char**)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_sprintf")==s) {
|
||||
} else if(strstr(s, "sprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "my_printf")==s) {
|
||||
} else if(strstr(s, "printf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "my_wprintf")==s) {
|
||||
} else if(strstr(s, "wprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%S\"...)", tid, *(void**)(R_ESP), s, pu32?((wchar_t*)(pu32)):L"nil");
|
||||
} else if(strstr(s, "my___vswprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%S\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(wchar_t**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 6;
|
||||
} else if(strstr(s, "__vswprintf")==s) {
|
||||
if(*(size_t*)(R_ESP+12)<2) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %p, %p, %p, %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16), *(void**)(R_ESP+20));
|
||||
} else {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%S\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(wchar_t**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 6;
|
||||
}
|
||||
} else if(strstr(s, "puts")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "fputs")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %p...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_fprintf")==s) {
|
||||
} else if(strstr(s, "fprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a __fprint_chk
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "my_vfprintf")==s) {
|
||||
} else if(strstr(s, "vfprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a _chk function
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
@@ -246,9 +259,9 @@ void x86Int3(x86emu_t* emu)
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "vkGetDeviceProcAddr")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "my_glXGetProcAddress")==s) {
|
||||
} else if(strstr(s, "glXGetProcAddress")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
} else if(strstr(s, "my_sscanf")==s) {
|
||||
} else if(strstr(s, "sscanf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "vsscanf")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
@@ -270,7 +283,7 @@ void x86Int3(x86emu_t* emu)
|
||||
} else if(strstr(s, "udev_monitor_new_from_netlink")==s) {
|
||||
post = 5;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "my_syscall")) {
|
||||
} else if(!strcmp(s, "syscall")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %p, %p...)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else {
|
||||
|
||||
+6
-3
@@ -46,6 +46,9 @@ int Run(x86emu_t *emu, int step)
|
||||
int64_t ll;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx87_regs_t *opem, eam1;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
#endif
|
||||
|
||||
if(emu->quit)
|
||||
return 0;
|
||||
@@ -101,7 +104,7 @@ int Run(x86emu_t *emu, int step)
|
||||
|
||||
static const void* opcodes0f[256] = {
|
||||
&&_0f_0x00, &&_0f_0x01, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
|
||||
&&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_default, &&_default, &&_default, //0x08-0x0F
|
||||
&&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_0f_0x0D, &&_default, &&_default, //0x08-0x0F
|
||||
&&_0f_0x10, &&_0f_0x11, &&_0f_0x12, &&_0f_0x13, &&_0f_0x14, &&_0f_0x15, &&_0f_0x16, &&_0f_0x17, //0x10-0x17
|
||||
&&_0f_0x18, &&_default, &&_0f_0x1A, &&_0f_0x1B, &&_default ,&&_default, &&_default, &&_0f_0x1F, //0x18-0x1F
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
|
||||
@@ -138,7 +141,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_66_0x00_0, &&_66_0x00_1, &&_66_0x00_2, &&_66_0x00_3, &&_66_0x00_4 ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
|
||||
&&_66_0x08_0, &&_66_0x08_1, &&_66_0x08_2, &&_66_0x08_3, &&_66_0x08_4 ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
|
||||
&&_66_0x10_0, &&_66_0x10_1, &&_66_0x10_2, &&_66_0x10_3, &&_66_0x10_4 ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
|
||||
&&_66_0x18_0, &&_66_0x18_1, &&_66_0x18_2, &&_66_0x18_3, &&_66_0x18_4 ,&&_66_0x18_5, &&_default, &&_66_0x1F, //0x18-0x1F
|
||||
&&_66_0x18_0, &&_66_0x18_1, &&_66_0x18_2, &&_66_0x18_3, &&_66_0x18_4 ,&&_66_0x18_5, &&_66_0x1E, &&_66_0x1F, //0x18-0x1F
|
||||
&&_66_0x20_0, &&_66_0x20_1, &&_66_0x20_2, &&_66_0x20_3, &&_66_0x20_4 ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
|
||||
&&_66_0x28_0, &&_66_0x28_1, &&_66_0x28_2, &&_66_0x28_3, &&_66_0x28_4 ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
|
||||
&&_66_0x30_0, &&_66_0x30_1, &&_66_0x30_2, &&_66_0x30_3, &&_66_0x30_4 ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
|
||||
@@ -165,7 +168,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_66_0xD9, &&_default, &&_default, &&_default ,&&_66_0xDD, &&_default, &&_default, //0xD8-0xDF
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE8-0xEF
|
||||
&&_66_0xF0, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_default, &&_default, &&_66_0xF7,
|
||||
&&_66_0xF0, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_66_0xF5, &&_default, &&_66_0xF7,
|
||||
&&_66_0xF8, &&_66_0xF9, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
|
||||
};
|
||||
|
||||
|
||||
+124
-49
@@ -536,63 +536,73 @@ void RunLock(x86emu_t *emu)
|
||||
#endif
|
||||
break;
|
||||
case 0xC7: /* CMPXCHG8B Gq */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
CHECK_FLAGS(emu);
|
||||
#ifdef DYNAREC
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned!!!
|
||||
uint64_t ref = R_EDX;
|
||||
ref = ref<<32 | R_EAX;
|
||||
void* p = (void*)(((uintptr_t)ED + 3)&~3);
|
||||
int d = (((uintptr_t)p - (uintptr_t)ED))*8;
|
||||
do {
|
||||
uint64_t m = *(uint64_t*)ED;
|
||||
m&=~((0xffffffffLL)<<d);
|
||||
tmp32u = arm_lock_read_d(p);
|
||||
m|=((uint64_t)tmp32u)<<d;
|
||||
if(ref == m) {
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned!!!
|
||||
uint64_t ref = R_EDX;
|
||||
ref = ref<<32 | R_EAX;
|
||||
void* p = (void*)(((uintptr_t)ED + 3)&~3);
|
||||
int d = (((uintptr_t)p - (uintptr_t)ED))*8;
|
||||
do {
|
||||
uint64_t m = *(uint64_t*)ED;
|
||||
m&=~((0xffffffffLL)<<d);
|
||||
tmp32u = arm_lock_read_d(p);
|
||||
m|=((uint64_t)tmp32u)<<d;
|
||||
if(ref == m) {
|
||||
SET_FLAG(F_ZF);
|
||||
m = ((uint64_t)R_ECX)<<32 | R_EBX;
|
||||
tmp32u2 = m>>d;
|
||||
tmp32s = arm_lock_write_d(p, tmp32u2);
|
||||
if(!tmp32s)
|
||||
*(uint64_t*)ED = m;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = m&0xffffffff;
|
||||
R_EDX = m>>32;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else
|
||||
do {
|
||||
arm_lock_read_dd(&tmp32u, &tmp32u2, ED);
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm_lock_write_dd(R_EBX, R_ECX, ED);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
m = ((uint64_t)R_ECX)<<32 | R_EBX;
|
||||
tmp32u2 = m>>d;
|
||||
tmp32s = arm_lock_write_d(p, tmp32u2);
|
||||
if(!tmp32s)
|
||||
*(uint64_t*)ED = m;
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = m&0xffffffff;
|
||||
R_EDX = m>>32;
|
||||
tmp32s = 0;
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else
|
||||
do {
|
||||
arm_lock_read_dd(&tmp32u, &tmp32u2, ED);
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm_lock_write_dd(R_EBX, R_ECX, ED);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP;
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0xC7 0x%02X 0x%02X\n", nextop, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// trigger invalid lock?
|
||||
@@ -798,6 +808,59 @@ void RunLock66(x86emu_t *emu)
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#ifdef DYNAREC
|
||||
if((uintptr_t)ED&1) {
|
||||
//meh.
|
||||
do {
|
||||
tmp16u = ED->dword[0];
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= arm_lock_read_b(ED);
|
||||
tmp16u = inc16(emu, tmp16u);
|
||||
} while(arm_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->dword[0] = tmp16u;
|
||||
} else
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
} 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]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#ifdef DYNAREC
|
||||
if((uintptr_t)ED&1) {
|
||||
//meh.
|
||||
do {
|
||||
tmp16u = ED->dword[0];
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= arm_lock_read_b(ED);
|
||||
tmp16u = dec16(emu, tmp16u);
|
||||
} while(arm_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->dword[0] = tmp16u;
|
||||
} else
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
} 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]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ip=R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip-=3; // unfetch nextop, F0 & 66
|
||||
UnimpOpcode(emu);
|
||||
@@ -889,6 +952,18 @@ void RunGS(x86emu_t *emu)
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x39: /* CMP Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x3B: /* CMP Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
|
||||
+209
-11
@@ -38,6 +38,9 @@ void Run660F(x86emu_t *emu)
|
||||
int32_t tmp32s;
|
||||
sse_regs_t *opex, eax1, *opx2;
|
||||
mmx87_regs_t *opem;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
#endif
|
||||
|
||||
|
||||
opcode = F8;
|
||||
@@ -366,6 +369,23 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x14: /* BLENDVPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<4; ++i) {
|
||||
if(emu->xmm[0].ud[i]&0x80000000)
|
||||
GX.ud[i] = EX->ud[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x17: // PTEST GX, EX
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
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);
|
||||
break;
|
||||
|
||||
case 0x1C: /* PABSB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -388,6 +408,96 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20: /* PMOVSXBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=7; i>=0; --i)
|
||||
GX.sw[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x21: /* PMOVSXBD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.sd[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x22: /* PMOVSXBQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = EX->sb[i];
|
||||
break;
|
||||
case 0x23: /* PMOVSXWD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.sd[i] = EX->sw[i];
|
||||
break;
|
||||
case 0x24: /* PMOVSXWQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = EX->sw[i];
|
||||
break;
|
||||
case 0x25: /* PMOVSXDQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.sq[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x30: /* PMOVZXBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=7; i>=0; --i)
|
||||
GX.uw[i] = EX->ub[i];
|
||||
break;
|
||||
case 0x31: /* PMOVZXBD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.ud[i] = EX->ub[i];
|
||||
break;
|
||||
case 0x32: /* PMOVZXBQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.q[i] = EX->ub[i];
|
||||
break;
|
||||
case 0x33: /* PMOVZXWD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=3; i>=0; --i)
|
||||
GX.ud[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x34: /* PMOVZXWQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.q[i] = EX->uw[i];
|
||||
break;
|
||||
case 0x35: /* PMOVZXDQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=1; i>=0; --i)
|
||||
GX.q[i] = EX->ud[i];
|
||||
break;
|
||||
|
||||
case 0x39: /* PMINSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX.sd[i]>EX->sd[i])
|
||||
GX.sd[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
case 0x3D: /* PMAXSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(GX.sd[i]<EX->sd[i])
|
||||
GX.sd[i] = EX->sd[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
@@ -397,6 +507,15 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x3A: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0E: /* PBLENDW Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
for (int i=0; i<8; ++i) {
|
||||
if(tmp8u&(1<<i))
|
||||
GX.uw[i] = EX->uw[i];
|
||||
}
|
||||
break;
|
||||
case 0x0F: // PALIGNR GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -434,6 +553,31 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x16: // PEXTRD ED, GX, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
ED->dword[0] = GX.ud[tmp8u&3];
|
||||
break;
|
||||
|
||||
case 0x21: // INSERTPS GX, EX, u8
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)==0xC0) 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))
|
||||
GX.ud[i] = 0;
|
||||
break;
|
||||
case 0x22: // PINSRD GX, ED, u8
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
GX.ud[tmp8u&0x3] = ED->dword[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
@@ -450,8 +594,14 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x51: /* SQRTPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] = sqrt(EX->d[0]);
|
||||
GX.d[1] = sqrt(EX->d[1]);
|
||||
for (int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
if(EX->d[i]<0.0) // on x86, default nan are negative
|
||||
GX.d[i] = -NAN; // but input NAN are not touched (so sqrt(+nan) -> +nan)
|
||||
else
|
||||
#endif
|
||||
GX.d[i] = sqrt(EX->d[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x54: /* ANDPD Gx, Ex */
|
||||
@@ -481,14 +631,28 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x58: /* ADDPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] += EX->d[0];
|
||||
GX.d[1] += EX->d[1];
|
||||
for(int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
// add generate a -NAN only if doing inf + -inf
|
||||
if((isinf(GX.d[i]) && isinf(EX->d[i]) && (EX->q[i]&0x8000000000000000LL)!=(GX.q[i]&0x8000000000000000LL)))
|
||||
GX.d[i] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[i] += EX->d[i];
|
||||
}
|
||||
break;
|
||||
case 0x59: /* MULPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] *= EX->d[0];
|
||||
GX.d[1] *= EX->d[1];
|
||||
for(int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
// mul generate a -NAN only if doing (+/-)inf * (+/-)0
|
||||
if((isinf(GX.d[i]) && EX->d[i]==0.0) || (isinf(EX->d[i]) && GX.d[i]==0.0))
|
||||
GX.d[i] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[i] *= EX->d[i];
|
||||
}
|
||||
break;
|
||||
case 0x5A: /* CVTPD2PS Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -530,8 +694,15 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x5C: /* SUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] -= EX->d[0];
|
||||
GX.d[1] -= EX->d[1];
|
||||
for(int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
// sub generate a -NAN only if doing inf - inf
|
||||
if((isinf(GX.d[i]) && isinf(EX->d[i]) && (EX->q[i]&0x8000000000000000LL)==(GX.q[i]&0x8000000000000000LL)))
|
||||
GX.d[i] = -NAN;
|
||||
else
|
||||
#endif
|
||||
GX.d[i] -= EX->d[i];
|
||||
}
|
||||
break;
|
||||
case 0x5D: /* MINPD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -544,8 +715,16 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x5E: /* DIVPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.d[0] /= EX->d[0];
|
||||
GX.d[1] /= EX->d[1];
|
||||
for (int i=0; i<2; ++i) {
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[i]) || isnan(EX->d[i]);
|
||||
#endif
|
||||
GX.d[i] /= EX->d[i];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[i]))
|
||||
GX.d[i] = -NAN;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0x5F: /* MAXPD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -834,11 +1013,25 @@ void Run660F(x86emu_t *emu)
|
||||
case 0x7C: /* HADDPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(GX.d[0]) || isnan(GX.d[1]);
|
||||
#endif
|
||||
GX.d[0] += GX.d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[0]))
|
||||
GX.d[0] = -NAN;
|
||||
#endif
|
||||
if(EX==&GX) {
|
||||
GX.d[1] = GX.d[0];
|
||||
} else {
|
||||
#ifndef NOALIGN
|
||||
is_nan = isnan(EX->d[0]) || isnan(EX->d[1]);
|
||||
#endif
|
||||
GX.d[1] = EX->d[0] + EX->d[1];
|
||||
#ifndef NOALIGN
|
||||
if(!is_nan && isnan(GX.d[1]))
|
||||
GX.d[1] = -NAN;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1059,6 +1252,11 @@ void Run660F(x86emu_t *emu)
|
||||
GET_EB;
|
||||
GW.sword[0] = EB->sbyte[0];
|
||||
break;
|
||||
case 0xBF: /* MOVSX Gw,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
GW.sword[0] = EW->sword[0];
|
||||
break;
|
||||
|
||||
case 0xC1: /* XADD Gw,Ew */ // Xchange and Add
|
||||
nextop = F8;
|
||||
@@ -1467,4 +1665,4 @@ void Run660F(x86emu_t *emu)
|
||||
|
||||
R_EIP = ip;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "x86run.h"
|
||||
#include "librarian.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
#ifdef HAVE_TRACE
|
||||
#include "x86trace.h"
|
||||
#endif
|
||||
@@ -339,6 +340,51 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_rcl8:
|
||||
cc = (emu->op1 >> (8 - emu->op2)) & 0x1;
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->op2 == 1 && XOR2(cc + ((emu->res >> 6) & 0x2)), F_OF);
|
||||
break;
|
||||
case d_rcl16:
|
||||
cc = (emu->op1 >> (16 - emu->op2)) & 0x1;
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->op2 == 1 && XOR2(cc + ((emu->res >> 14) & 0x2)), F_OF);
|
||||
break;
|
||||
case d_rcl32:
|
||||
cc = (emu->op1 >> (32 - emu->op2)) & 0x1;
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->op2 == 1 && XOR2(cc + ((emu->res >> 30) & 0x2)), F_OF);
|
||||
break;
|
||||
case d_rcr8:
|
||||
cnt = emu->op2 % 9;
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x1, F_CF);
|
||||
cc = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc + ((emu->op1 >> 6) & 0x2)), F_OF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (cnt - 1)) & 0x1, F_CF);
|
||||
}
|
||||
break;
|
||||
case d_rcr16:
|
||||
cnt = emu->op2 % 17;
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x1, F_CF);
|
||||
cc = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc + ((emu->op1 >> 14) & 0x2)), F_OF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (cnt - 1)) & 0x1, F_CF);
|
||||
}
|
||||
break;
|
||||
case d_rcr32:
|
||||
cnt = emu->op2 % 33;
|
||||
if (cnt == 1) {
|
||||
CONDITIONAL_SET_FLAG(emu->op1 & 0x1, F_CF);
|
||||
cc = ACCESS_FLAG(F_CF) != 0;
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc + ((emu->op1 >> 30) & 0x2)), F_OF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG((emu->op1 >> (cnt - 1)) & 0x1, F_CF);
|
||||
}
|
||||
break;
|
||||
case d_shl8:
|
||||
if (emu->op2 < 8) {
|
||||
cnt = emu->op2 % 8;
|
||||
@@ -512,7 +558,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
bc = (emu->res & ((~emu->op1) | emu->op2)) | ((~emu->op1) & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -521,7 +567,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
bc = (emu->res & ((~emu->op1) | emu->op2)) | ((~emu->op1) & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -530,7 +576,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
bc = (emu->res & ((~emu->op1) | emu->op2)) | ((~emu->op1) & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -727,14 +773,21 @@ const char* getAddrFunctionName(uintptr_t addr)
|
||||
static char ret[1000];
|
||||
uint32_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, addr), (void*)addr, &start, &sz);
|
||||
elfheader_t* elf = FindElfAddress(my_context, addr);
|
||||
const char* symbname = FindNearestSymbolName(elf, (void*)addr, &start, &sz);
|
||||
if(symbname && addr>=start && (addr<(start+sz) || !sz)) {
|
||||
if(addr==start)
|
||||
sprintf(ret, "%s/%s", ElfName(FindElfAddress(my_context, addr)), symbname);
|
||||
if(symbname[0]=='\0')
|
||||
sprintf(ret, "%s + 0x%x", ElfName(elf), addr - (uintptr_t)GetBaseAddress(elf));
|
||||
else if(addr==start)
|
||||
sprintf(ret, "%s/%s", ElfName(elf), symbname);
|
||||
else
|
||||
sprintf(ret, "%s/%s + %d", ElfName(FindElfAddress(my_context, addr)), symbname, addr - start);
|
||||
} else
|
||||
sprintf(ret, "???");
|
||||
sprintf(ret, "%s/%s + %d", ElfName(elf), symbname, addr - start);
|
||||
} else {
|
||||
if(elf) {
|
||||
sprintf(ret, "%s + 0x%x", ElfName(elf), addr - (uintptr_t)GetBaseAddress(elf));
|
||||
} else
|
||||
sprintf(ret, "???");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+81
-26
@@ -246,6 +246,9 @@ scwrap_t syscallwrap[] = {
|
||||
#ifdef __NR_memfd_create
|
||||
{ 356, __NR_memfd_create, 2},
|
||||
#endif
|
||||
#ifdef __NR_futex_waitv
|
||||
{ 449, __NR_futex_waitv, 5},
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mmap_arg_struct {
|
||||
@@ -317,6 +320,7 @@ int clone_fn(void* arg)
|
||||
DynaRun(emu);
|
||||
int ret = R_EAX;
|
||||
FreeX86Emu(&emu);
|
||||
my_context->stack_clone_used = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -481,42 +485,46 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
emu->quit = 1; // we should be inside a DynaCall in a sigaction callback....
|
||||
break;
|
||||
case 120: // clone
|
||||
// x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
|
||||
// so flags=R_EBX, stack=R_ECX, parent_tid=R_EDX, tls=R_ESI, child_tid=R_EDI
|
||||
if(R_ECX)
|
||||
{
|
||||
// should wrap that using a thread...
|
||||
//struct x86_pt_regs *regs = (struct x86_pt_regs *)R_EDI;
|
||||
// lets duplicate the emu
|
||||
void* stack_base = (void*)R_ECX;
|
||||
int stack_size = 0;
|
||||
if(!R_ECX) {
|
||||
// allocate a new stack...
|
||||
stack_size = 1024*1024;
|
||||
//stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
|
||||
int currstack = 0;
|
||||
if((R_ESP>=(uintptr_t)emu->init_stack) && (R_ESP<=((uintptr_t)emu->init_stack+emu->size_stack)))
|
||||
currstack = 1;
|
||||
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
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
if(currstack)
|
||||
memcpy(stack_base, emu->init_stack, stack_size);
|
||||
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);
|
||||
}
|
||||
}
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (R_ECX)?0:1);
|
||||
SetupX86Emu(newemu);
|
||||
CloneEmu(newemu, emu);
|
||||
SetESP(newemu, (uintptr_t)stack_base);
|
||||
// setup registers
|
||||
/*if(regs) {
|
||||
SetEAX(newemu, regs->eax);
|
||||
SetEBX(newemu, regs->ebx);
|
||||
SetECX(newemu, regs->ecx);
|
||||
SetEDX(newemu, regs->edx);
|
||||
SetEDI(newemu, regs->edi);
|
||||
SetESI(newemu, regs->esi);
|
||||
SetEBP(newemu, regs->ebp);
|
||||
SetESP(newemu, (uintptr_t)stack_base - size_to_copy);
|
||||
Push32(newemu, 0);
|
||||
PushExit(newemu);
|
||||
void* mystack = NULL;
|
||||
if(my_context->stack_clone_used) {
|
||||
mystack = malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it
|
||||
} else {
|
||||
if(!my_context->stack_clone)
|
||||
my_context->stack_clone = malloc(1024*1024);
|
||||
mystack = my_context->stack_clone;
|
||||
my_context->stack_clone_used = 1;
|
||||
}
|
||||
SetESP(newemu, (uintptr_t)stack_base - size_to_copy);*/
|
||||
void* mystack = (R_EBX&CLONE_VM)?malloc(1024*1024):NULL; // stack for own process... memory leak, but no practical way to remove it
|
||||
int ret = clone(clone_fn, (void*)((R_EBX&CLONE_VM)?((uintptr_t)mystack+1024*1024):0), R_EBX, newemu, R_ESI, R_EDI, R_EBP);
|
||||
//int r = syscall(__NR_clone, R_EBX, (R_EBX&CLONE_VM)?((uintptr_t)mystack):0, R_EDX, R_ESI, NULL); // cannot use that syscall in C: how to setup the stack?!
|
||||
R_EAX = ret;
|
||||
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;
|
||||
}
|
||||
else
|
||||
R_EAX = (uint32_t)syscall(__NR_clone, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
break;
|
||||
case 122: // uname
|
||||
{
|
||||
@@ -639,6 +647,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
|
||||
uint32_t 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
|
||||
@@ -677,6 +686,49 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
return (uint32_t)my_execve(emu, p(4), p(8), p(12));
|
||||
case 91: // munmap
|
||||
return (uint32_t)my_munmap(emu, p(4), u32(8));
|
||||
case 120: // clone
|
||||
// x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
|
||||
// so flags=u(4), stack=p(8), parent_tid=p(12), tls=p(16), child_tid=p(20)
|
||||
if(p(8))
|
||||
{
|
||||
void* stack_base = p(8);
|
||||
int stack_size = 0;
|
||||
if(!stack_base) {
|
||||
// allocate a new stack...
|
||||
int currstack = 0;
|
||||
if((R_ESP>=(uintptr_t)emu->init_stack) && (R_ESP<=((uintptr_t)emu->init_stack+emu->size_stack)))
|
||||
currstack = 1;
|
||||
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)
|
||||
memcpy(stack_base, emu->init_stack, stack_size);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
void* mystack = NULL;
|
||||
if(my_context->stack_clone_used) {
|
||||
mystack = malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it
|
||||
} else {
|
||||
if(!my_context->stack_clone)
|
||||
my_context->stack_clone = malloc(1024*1024);
|
||||
mystack = my_context->stack_clone;
|
||||
my_context->stack_clone_used = 1;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
else
|
||||
return (uint32_t)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
|
||||
@@ -718,9 +770,12 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
return (uint32_t)my_memfd_create(emu, (void*)R_EBX, R_ECX);
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
if(!(warned&(1<<s))) {
|
||||
printf_log(LOG_INFO, "Warning: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
warned|=(1<<s);
|
||||
}
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -34,7 +34,12 @@ static inline void fpu_do_push(x86emu_t* emu)
|
||||
return;
|
||||
}*/
|
||||
if(emu->fpu_stack<8)
|
||||
++emu->fpu_stack;
|
||||
++emu->fpu_stack;
|
||||
else {
|
||||
emu->sw.f.F87_C1 = 1;
|
||||
return;
|
||||
}
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
emu->p_regs[newtop].tag = 0; // full
|
||||
emu->top = newtop;
|
||||
}
|
||||
@@ -136,7 +141,7 @@ void fpu_fxam(x86emu_t* emu);
|
||||
|
||||
static inline void fpu_ftst(x86emu_t* emu) {
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
if(isinf(ST0.d) || isnan(ST0.d))
|
||||
if(isnan(ST0.d))
|
||||
{ // TODO: Unsuported and denormal not analysed...
|
||||
emu->sw.f.F87_C3 = 1;
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
#ifndef BUILD_LIB
|
||||
int init_auxval(int argc, const char **argv, const char **env);
|
||||
int init_auxval(int argc, const char **argv, char **env);
|
||||
#endif
|
||||
|
||||
unsigned long real_getauxval(unsigned long type);
|
||||
|
||||
@@ -13,7 +13,9 @@ typedef struct lib_s lib_t;
|
||||
typedef struct bridge_s bridge_t;
|
||||
typedef struct dlprivate_s dlprivate_t;
|
||||
typedef struct kh_symbolmap_s kh_symbolmap_t;
|
||||
typedef struct kh_defaultversion_s kh_defaultversion_t;
|
||||
typedef struct library_s library_t;
|
||||
typedef struct linkmap_s linkmap_t;
|
||||
typedef struct kh_fts_s kh_fts_t;
|
||||
typedef struct kh_threadstack_s kh_threadstack_t;
|
||||
typedef struct zydis_dec_s zydis_dec_t;
|
||||
@@ -111,6 +113,7 @@ typedef struct box86context_s {
|
||||
kh_symbolmap_t *almymap; // link to the mysymbolmap if libOpenAL
|
||||
kh_symbolmap_t *vkwrappers; // the map of wrapper for VulkanProcs (TODO: check SDL2)
|
||||
kh_symbolmap_t *vkmymap; // link to the mysymbolmap of libGL
|
||||
kh_defaultversion_t *defver; // the default version for symbols (the XXX@@vvvv of symbols)
|
||||
vkprocaddess_t vkprocaddress;
|
||||
|
||||
pthread_mutex_t mutex_once;
|
||||
@@ -150,6 +153,7 @@ typedef struct box86context_s {
|
||||
library_t *asound;
|
||||
library_t *pulse;
|
||||
library_t *d3dadapter9;
|
||||
linkmap_t *linkmap;
|
||||
|
||||
int deferedInit;
|
||||
elfheader_t **deferedInitList;
|
||||
@@ -186,9 +190,8 @@ typedef struct box86context_s {
|
||||
x86emu_t *emu_sig; // the emu with stack used for signal handling (must be separated from main ones)
|
||||
int no_sigsegv;
|
||||
int no_sigill;
|
||||
#ifdef BUILD_DYNAMIC
|
||||
int count; // number of instances
|
||||
#endif
|
||||
void* stack_clone;
|
||||
int stack_clone_used;
|
||||
} box86context_t;
|
||||
|
||||
extern box86context_t *my_context; // global context
|
||||
|
||||
@@ -35,14 +35,20 @@ uintptr_t getJumpTableAddress(uintptr_t addr);
|
||||
#endif
|
||||
|
||||
#define PROT_DYNAREC 0x80
|
||||
#define PROT_CUSTOM (PROT_DYNAREC)
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
uint32_t getProtection(uintptr_t addr);
|
||||
void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
void freeProtection(uintptr_t addr, uintptr_t size);
|
||||
void loadProtectionFromMap();
|
||||
#ifdef DYNAREC
|
||||
void protectDB(uintptr_t addr, uintptr_t size);
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
#endif
|
||||
void* find32bitBlock(size_t size);
|
||||
void* findBlockNearHint(void* hint, size_t size);
|
||||
|
||||
// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
|
||||
int unlockCustommemMutex();
|
||||
|
||||
@@ -15,7 +15,9 @@ extern int box86_dynarec_forced;
|
||||
extern int box86_dynarec_largest;
|
||||
extern int box86_dynarec_bigblock;
|
||||
extern int box86_dynarec_strongmem;
|
||||
extern int box86_dynarec_x87double;
|
||||
extern uintptr_t box86_nodynarec_start, box86_nodynarec_end;
|
||||
extern int box86_dynarec_fastnan;
|
||||
#ifdef ARM
|
||||
extern int arm_vfp; // vfp version (3 or 4), with 32 registers is mendatory
|
||||
extern int arm_swap;
|
||||
@@ -26,10 +28,16 @@ extern int dlsym_error; // log dlsym error
|
||||
extern int trace_xmm; // include XMM reg in trace?
|
||||
extern int trace_emm; // include EMM reg in trace?
|
||||
extern int allow_missing_libs;
|
||||
extern int box86_prefer_wrapped;
|
||||
extern int box86_prefer_emulated;
|
||||
extern int box86_steam;
|
||||
extern int box86_wine;
|
||||
extern int box86_nopulse; // disabling the use of wrapped pulseaudio
|
||||
extern int box86_nogtk; // disabling the use of wrapped gtk
|
||||
extern int box86_novulkan; // disabling the use of wrapped vulkan
|
||||
extern int box86_mapclean;
|
||||
extern int box86_showsegv;
|
||||
extern int allow_missing_symbols;
|
||||
extern uintptr_t trace_start, trace_end;
|
||||
extern char* trace_func;
|
||||
extern uintptr_t fmod_smc_start, fmod_smc_end; // to handle libfmod (from Unreal) SMC (self modifying code)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define __DICTIONNARY_H_
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct dic_s dic_t;
|
||||
typedef void dic_t;
|
||||
|
||||
dic_t *NewDictionnary();
|
||||
void FreeDictionnary(dic_t **dic);
|
||||
@@ -10,7 +10,4 @@ void FreeDictionnary(dic_t **dic);
|
||||
const char* AddDictionnary(dic_t* dic, const char* s);
|
||||
int ExistDictionnary(dic_t* dic, const char* s);
|
||||
|
||||
const char* AddDefault(dic_t* dic, const char* s, const char** vername);
|
||||
const char* ExistDefault(dic_t* dic, const char* s);
|
||||
|
||||
#endif //__DICTIONNARY_H_
|
||||
@@ -24,13 +24,13 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin);
|
||||
void FreeElfMemory(elfheader_t* head);
|
||||
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
|
||||
int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
|
||||
int RelocateElf(lib_t* maplib, lib_t* local_maplib, elfheader_t* head);
|
||||
int RelocateElfPlt(lib_t* maplib, lib_t* local_maplib, elfheader_t* head);
|
||||
int RelocateElf(lib_t* maplib, lib_t* local_maplib, int bindnow, elfheader_t* head);
|
||||
int RelocateElfPlt(lib_t* maplib, lib_t* local_maplib, int bindnow, elfheader_t* head);
|
||||
void CalcStack(elfheader_t* h, uint32_t* stacksz, int* stackalign);
|
||||
uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h);
|
||||
uintptr_t GetLastByte(elfheader_t* h);
|
||||
void AddSymbols(lib_t* maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h);
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, box86context_t* box86, x86emu_t* emu);
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, int bindnow, box86context_t* box86, x86emu_t* emu);
|
||||
uintptr_t GetElfInit(elfheader_t* h);
|
||||
uintptr_t GetElfFini(elfheader_t* h);
|
||||
void RunElfInit(elfheader_t* h, x86emu_t* emu);
|
||||
@@ -52,6 +52,7 @@ dynablocklist_t* GetDynablocksFromElf(elfheader_t* h);
|
||||
#endif
|
||||
void ResetSpecialCaseMainElf(elfheader_t* h);
|
||||
void CreateMemorymapFile(box86context_t* context, int fd);
|
||||
void* GetDynamicSection(elfheader_t* h);
|
||||
|
||||
int ElfCheckIfUseTCMallocMinimal(elfheader_t* h); // return 1 if tcmalloc is used
|
||||
|
||||
@@ -60,4 +61,8 @@ const char* GetParentSymbolVersion(elfheader_t* h, int index);
|
||||
const char* VersionnedName(const char* name, int ver, const char* vername);
|
||||
int SameVersionnedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2);
|
||||
|
||||
void* GetNativeSymbolUnversionned(void* lib, const char* name);
|
||||
|
||||
void AddMainElfToLinkmap(elfheader_t* lib);
|
||||
|
||||
#endif //__ELF_LOADER_H_
|
||||
@@ -210,6 +210,123 @@ typedef struct my_GtkWindowClass_s {
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkWindowClass_t;
|
||||
|
||||
typedef struct my_GtkButtonClass_s {
|
||||
my_GtkBinClass_t parent_class;
|
||||
void (* pressed) (void *button);
|
||||
void (* released) (void *button);
|
||||
void (* clicked) (void *button);
|
||||
void (* enter) (void *button);
|
||||
void (* leave) (void *button);
|
||||
void (* activate) (void *button);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkButtonClass_t;
|
||||
|
||||
typedef struct my_GtkToggleButtonClass_s {
|
||||
my_GtkButtonClass_t parent_class;
|
||||
void (* toggled) (void* toggle_button);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkToggleButtonClass_t;
|
||||
|
||||
typedef struct my_GtkCheckButtonClass_s {
|
||||
my_GtkToggleButtonClass_t parent_class;
|
||||
void (* draw_indicator) (void* check_button, void* area);
|
||||
void (*_gtk_reserved0) (void);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
} my_GtkCheckButtonClass_t;
|
||||
|
||||
typedef struct my_GtkComboBoxClass_s {
|
||||
my_GtkBinClass_t parent_class;
|
||||
void (* changed) (void* combo_box);
|
||||
void*(* get_active_text)(void* combo_box);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkComboBoxClass_t;
|
||||
|
||||
typedef struct my_GtkEntryClass_s {
|
||||
my_GtkWidgetClass_t parent_class;
|
||||
void (* populate_popup) (void* entry, void* menu);
|
||||
void (* activate) (void* entry);
|
||||
void (* move_cursor) (void* entry, int step, int count, int extend_selection);
|
||||
void (* insert_at_cursor) (void* entry, void* str);
|
||||
void (* delete_from_cursor) (void* entry, int type, int count);
|
||||
void (* backspace) (void* entry);
|
||||
void (* cut_clipboard) (void* entry);
|
||||
void (* copy_clipboard) (void* entry);
|
||||
void (* paste_clipboard) (void* entry);
|
||||
void (* toggle_overwrite) (void* entry);
|
||||
void (* get_text_area_size) (void* entry, void* x, void* y, void* width, void* height);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
} my_GtkEntryClass_t;
|
||||
|
||||
typedef struct my_GtkSpinButtonClass_s {
|
||||
my_GtkEntryClass_t parent_class;
|
||||
int (*input) (void* spin_button, void* new_value);
|
||||
int (*output) (void* spin_button);
|
||||
void (*value_changed) (void* spin_button);
|
||||
void (*change_value) (void* spin_button, int scroll);
|
||||
void (*wrapped) (void* spin_button);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
} my_GtkSpinButtonClass_t;
|
||||
|
||||
typedef struct my_GtkProgressClass_s {
|
||||
my_GtkWidgetClass_t parent_class;
|
||||
void (* paint) (void* progress);
|
||||
void (* update) (void* progress);
|
||||
void (* act_mode_enter) (void* progress);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkProgressClass_t;
|
||||
|
||||
typedef struct my_GtkProgressBarClass_s {
|
||||
my_GtkProgressClass_t parent_class;
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkProgressBarClass_t;
|
||||
|
||||
typedef struct my_GtkFrameClass_s {
|
||||
my_GtkBinClass_t parent_class;
|
||||
void (*compute_child_allocation) (void* frame, void* allocation);
|
||||
} my_GtkFrameClass_t;
|
||||
|
||||
typedef struct my_GtkMenuShellClass_s {
|
||||
my_GtkContainerClass_t parent_class;
|
||||
void (*deactivate) (void* menu_shell);
|
||||
void (*selection_done) (void* menu_shell);
|
||||
void (*move_current) (void* menu_shell, int direction);
|
||||
void (*activate_current) (void* menu_shell, int force_hide);
|
||||
void (*cancel) (void* menu_shell);
|
||||
void (*select_item) (void* menu_shell, void* menu_item);
|
||||
void (*insert) (void* menu_shell, void* child, int position);
|
||||
int (*get_popup_delay) (void* menu_shell);
|
||||
int (*move_selected) (void* menu_shell, int distance);
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
} my_GtkMenuShellClass_t;
|
||||
|
||||
typedef struct my_GtkMenuBarClass_s {
|
||||
my_GtkMenuShellClass_t parent_class;
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
} my_GtkMenuBarClass_t;
|
||||
|
||||
typedef struct my_MetaFramesClass_s
|
||||
{
|
||||
my_GtkWindowClass_t parent_class;
|
||||
@@ -302,6 +419,17 @@ GTKCLASS(GtkBin) \
|
||||
GTKCLASS(GtkWindow) \
|
||||
GTKCLASS(GtkTable) \
|
||||
GTKCLASS(GtkFixed) \
|
||||
GTKCLASS(GtkButton) \
|
||||
GTKCLASS(GtkComboBox) \
|
||||
GTKCLASS(GtkToggleButton)\
|
||||
GTKCLASS(GtkCheckButton)\
|
||||
GTKCLASS(GtkEntry) \
|
||||
GTKCLASS(GtkSpinButton) \
|
||||
GTKCLASS(GtkProgress) \
|
||||
GTKCLASS(GtkProgressBar)\
|
||||
GTKCLASS(GtkFrame) \
|
||||
GTKCLASS(GtkMenuShell) \
|
||||
GTKCLASS(GtkMenuBar) \
|
||||
GTKCLASS(MetaFrames) \
|
||||
GTKCLASS(GDBusObjectManagerClient) \
|
||||
|
||||
|
||||
@@ -25,20 +25,18 @@ kh_mapsymbols_t* GetMapSymbol(lib_t* maplib);
|
||||
kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib);
|
||||
kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib);
|
||||
kh_mapsymbols_t* GetGlobalData(lib_t* maplib);
|
||||
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, const char** paths, int npath, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
|
||||
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, int bindnow, const char** paths, int npath, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
|
||||
library_t* GetLibMapLib(lib_t* maplib, const char* name);
|
||||
library_t* GetLibInternal(const char* name);
|
||||
uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name, int version, const char* vername);
|
||||
int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self, int version, const char* vername);
|
||||
int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
|
||||
int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
|
||||
int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername);
|
||||
int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
|
||||
int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
|
||||
elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name, int version, const char* vername);
|
||||
int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name, int version, const char* vername);
|
||||
|
||||
const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, const char** libname, void** base);
|
||||
const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, const char** libname, void** base, library_t** lib);
|
||||
|
||||
void AddOffsetSymbol(lib_t *maplib, void* offs, const char* name);
|
||||
const char* GetNameOffset(lib_t *maplib, void* offs);
|
||||
|
||||
@@ -12,7 +12,7 @@ typedef struct needed_libs_s needed_libs_t;
|
||||
|
||||
library_t *NewLibrary(const char* path, box86context_t* box86);
|
||||
int AddSymbolsLibrary(lib_t* maplib, library_t* lib, x86emu_t* emu);
|
||||
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x86emu_t* emu);
|
||||
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, int bindnow, x86emu_t* emu);
|
||||
int ReloadLibrary(library_t* lib, x86emu_t* emu);
|
||||
void InactiveLibrary(library_t* lib);
|
||||
void Free1Library(library_t **lib, x86emu_t* emu);
|
||||
|
||||
@@ -329,3 +329,19 @@ void AlignFlock64(void* dest, void* source); // x86 -> Arm
|
||||
// defined in wrapperlibc.c
|
||||
int of_convert(int); // x86->arm
|
||||
int of_unconvert(int); // arm->x86
|
||||
|
||||
typedef struct my_GValue_s
|
||||
{
|
||||
int g_type;
|
||||
union {
|
||||
int v_int;
|
||||
int64_t v_int64;
|
||||
uint64_t v_uint64;
|
||||
float v_float;
|
||||
double v_double;
|
||||
void* v_pointer;
|
||||
} data[2];
|
||||
} my_GValue_t;
|
||||
|
||||
void alignNGValue(my_GValue_t* v, void* value, int n);
|
||||
void unalignNGValue(void* value, my_GValue_t* v, int n);
|
||||
@@ -16,9 +16,16 @@ void FreeMapSymbols(kh_mapsymbols_t** map);
|
||||
void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz, int ver, const char* vername);
|
||||
uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name, int ver, const char* vername, int local);
|
||||
// don't add if already there
|
||||
#define MAX_STEP 3
|
||||
void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz, int ver, const char* vername);
|
||||
int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end, int ver, const char* vername, int local);
|
||||
const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* offs, uint32_t* sz, const char** vername);
|
||||
|
||||
// default version handling
|
||||
KHASH_MAP_DECLARE_STR(defaultversion, const char*)
|
||||
kh_defaultversion_t* NewDefaultVersion();
|
||||
void FreeDefaultVersion(kh_defaultversion_t** def);
|
||||
|
||||
void AddDefaultVersion(kh_defaultversion_t* def, const char* symname, const char* vername);
|
||||
const char* GetDefaultVersion(kh_defaultversion_t* def, const char* symname);
|
||||
|
||||
#endif //__SYMBOLS_PRIVATE_H_
|
||||
+15
-58
@@ -6,20 +6,11 @@
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_SET_INIT_STR(store);
|
||||
KHASH_MAP_INIT_STR(default, const char*);
|
||||
|
||||
typedef struct dic_s {
|
||||
kh_store_t *dic;
|
||||
kh_default_t *def;
|
||||
} dic_t;
|
||||
|
||||
KHASH_SET_INIT_STR(dic);
|
||||
|
||||
dic_t *NewDictionnary()
|
||||
{
|
||||
dic_t *dic = (dic_t*)calloc(1, sizeof(dic_t));
|
||||
dic->dic = kh_init(store);
|
||||
dic->def = kh_init(default);
|
||||
dic_t *dic = kh_init(dic);
|
||||
return dic;
|
||||
}
|
||||
|
||||
@@ -27,65 +18,31 @@ void FreeDictionnary(dic_t **d)
|
||||
{
|
||||
if(!d || !*d)
|
||||
return;
|
||||
dic_t* dic = *d;
|
||||
kh_dic_t* dic = (kh_dic_t*)*d;
|
||||
const char* k;
|
||||
kh_foreach_value(dic->def, k, free((void*)k));
|
||||
kh_destroy(default, dic->def);
|
||||
kh_foreach_key(dic->dic, k, free((void*)k));
|
||||
kh_destroy(store, dic->dic);
|
||||
free(dic);
|
||||
kh_foreach_key(dic, k, free((void*)k));
|
||||
kh_destroy(dic, dic);
|
||||
*d = NULL;
|
||||
}
|
||||
|
||||
const char* AddDictionnary(dic_t* dic, const char* s)
|
||||
const char* AddDictionnary(dic_t* d, const char* s)
|
||||
{
|
||||
khint_t k = kh_get(store, dic->dic, s);
|
||||
if(k!=kh_end(dic->dic))
|
||||
return kh_key(dic->dic, k);
|
||||
kh_dic_t* dic = (kh_dic_t*)d;
|
||||
khint_t k = kh_get(dic, dic, s);
|
||||
if(k!=kh_end(dic))
|
||||
return kh_key(dic, k);
|
||||
char* n = strdup(s);
|
||||
int ret;
|
||||
k = kh_put(store, dic->dic, n, &ret);
|
||||
k = kh_put(dic, dic, n, &ret);
|
||||
return n;
|
||||
}
|
||||
|
||||
int ExistDictionnary(dic_t* dic, const char* s)
|
||||
int ExistDictionnary(dic_t* d, const char* s)
|
||||
{
|
||||
khint_t k = kh_get(store, dic->dic, s);
|
||||
if(k!=kh_end(dic->dic))
|
||||
kh_dic_t* dic = (kh_dic_t*)d;
|
||||
khint_t k = kh_get(dic, dic, s);
|
||||
if(k!=kh_end(dic))
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
const char* AddDefault(dic_t* dic, const char* s, const char** vername)
|
||||
{
|
||||
char name[strlen(s)+1];
|
||||
strcpy(name, s);
|
||||
char* p = strchr(name, '@');
|
||||
if(!p) {
|
||||
printf_log(LOG_NONE, "Warning, Added Default symbol without version mark %s\n", s);
|
||||
return NULL;
|
||||
}
|
||||
*p=0;
|
||||
const char* key = AddDictionnary(dic, name);
|
||||
char* def_ver = strdup(p+2);
|
||||
*vername = def_ver;
|
||||
int ret;
|
||||
khint_t k = kh_put(default, dic->def, key, &ret);
|
||||
if(!ret) {
|
||||
free(def_ver);
|
||||
*vername = kh_value(dic->def, k);
|
||||
return key;
|
||||
}
|
||||
kh_value(dic->def, k) = def_ver;
|
||||
return key;
|
||||
}
|
||||
|
||||
const char* ExistDefault(dic_t* dic, const char* s)
|
||||
{
|
||||
khint_t k = kh_get(default, dic->def, s);
|
||||
if(k!=kh_end(dic->def))
|
||||
return kh_value(dic->def, k);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
+66
-66
@@ -37,9 +37,9 @@ lib_t *NewLibrarian(box86context_t* context, int ownlibs)
|
||||
static void freeLibraryRecurse(lib_t *maplib, x86emu_t *emu, int idx, char *freed, library_t* owner) {
|
||||
if (freed[idx]) return; // Already freed
|
||||
|
||||
freed[idx] = 1; // Avoid infinite loops
|
||||
library_t *lib = maplib->libraries[idx];
|
||||
if(lib==owner) return; // don't free owner of maplib
|
||||
freed[idx] = 1; // Avoid infinite loops
|
||||
printf_log(LOG_DEBUG, "Unloading %s\n", lib->name);
|
||||
for (int i = lib->dependedby.size - 1; i >= 0; --i) {
|
||||
int j;
|
||||
@@ -47,8 +47,8 @@ static void freeLibraryRecurse(lib_t *maplib, x86emu_t *emu, int idx, char *free
|
||||
if (lib->dependedby.libs[i] == maplib->libraries[j]) break;
|
||||
}
|
||||
if (j == maplib->libsz) {
|
||||
// We cannot access the 'name' field, since we can't be sure it hasn't been freed somewhere else...
|
||||
printf_log(LOG_INFO, "Library %s (%p) needs %p, but it was not found. Ignoring.\n", lib->name, lib, lib->dependedby.libs[i]);
|
||||
// dependant lib already freed
|
||||
// library as been freed already
|
||||
continue;
|
||||
}
|
||||
if (freed[j] == 1) {
|
||||
@@ -298,10 +298,23 @@ int AddNeededLib_add(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib
|
||||
printf_log(LOG_DEBUG, "Failure to Add lib => fail\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lib->type == 1) {
|
||||
// Need to add library to the linkmap (put here so the link is ordered)
|
||||
linkmap_t *lm = addLinkMapLib(lib);
|
||||
if(!lm) {
|
||||
// Crashed already
|
||||
printf_log(LOG_DEBUG, "Failure to add lib linkmap\n");
|
||||
return 1;
|
||||
}
|
||||
lm->l_addr = (Elf32_Addr)GetElfDelta(my_context->elfs[lib->priv.n.elf_index]);
|
||||
lm->l_name = lib->name;
|
||||
lm->l_ld = GetDynamicSection(my_context->elfs[lib->priv.n.elf_index]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AddNeededLib_init(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, library_t* lib, box86context_t* box86, x86emu_t* emu)
|
||||
int AddNeededLib_init(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, int bindnow, library_t* lib, box86context_t* box86, x86emu_t* emu)
|
||||
{
|
||||
if(!maplib)
|
||||
maplib = (local)?lib->maplib:my_context->maplib;
|
||||
@@ -313,22 +326,22 @@ int AddNeededLib_init(lib_t* maplib, needed_libs_t* neededlibs, library_t* depli
|
||||
} else {
|
||||
// it's an emulated lib,
|
||||
// load dependancies and launch init sequence
|
||||
if(LoadNeededLibs(box86->elfs[mainelf], maplib, &lib->needed, lib, local, box86, emu)) {
|
||||
if(LoadNeededLibs(box86->elfs[mainelf], maplib, &lib->needed, lib, 0, bindnow, box86, emu)) {
|
||||
printf_log(LOG_DEBUG, "Failure to Add dependant lib => fail\n");
|
||||
return 1;
|
||||
}
|
||||
// some special case, where dependancies may not be correct
|
||||
if(!strcmp(GetNameLib(lib), "libCgGL.so")) {
|
||||
const char* libs[] = {"libGL.so.1"};
|
||||
AddNeededLib(maplib, &lib->needed, lib, 0, libs, 1, box86, emu);
|
||||
AddNeededLib(maplib, &lib->needed, lib, 0, 0, libs, 1, box86, emu);
|
||||
}
|
||||
if(!strcmp(GetNameLib(lib), "libmss.so.6")) {
|
||||
const char* libs[] = {"libSDL-1.2.so.0", "libdl.so.2"};
|
||||
AddNeededLib(maplib, &lib->needed, lib, 0, libs, 2, box86, emu);
|
||||
AddNeededLib(maplib, &lib->needed, lib, 0, 0, libs, 2, box86, emu);
|
||||
}
|
||||
|
||||
// finalize the lib
|
||||
if(FinalizeLibrary(lib, local?maplib:NULL, emu)) {
|
||||
if(FinalizeLibrary(lib, local?maplib:NULL, bindnow, emu)) {
|
||||
printf_log(LOG_DEBUG, "Failure to finalizing lib => fail\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -340,8 +353,9 @@ int AddNeededLib_init(lib_t* maplib, needed_libs_t* neededlibs, library_t* depli
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, const char** paths, int npath, box86context_t* box86, x86emu_t* emu)
|
||||
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, int bindnow, const char** paths, int npath, box86context_t* box86, x86emu_t* emu)
|
||||
{
|
||||
box86_mapclean = 0;
|
||||
if(!neededlibs) {
|
||||
neededlibs = alloca(sizeof(needed_libs_t));
|
||||
memset(neededlibs, 0, sizeof(needed_libs_t));
|
||||
@@ -357,7 +371,7 @@ int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, in
|
||||
int idx_end = neededlibs->size;
|
||||
// add dependant libs and init them
|
||||
for (int i=idx; i<idx_end; ++i)
|
||||
if(AddNeededLib_init(maplib, neededlibs, deplib, local, neededlibs->libs[i], box86, emu)) {
|
||||
if(AddNeededLib_init(maplib, neededlibs, deplib, local, bindnow, neededlibs->libs[i], box86, emu)) {
|
||||
printf_log(LOG_INFO, "Error initializing needed lib %s\n", neededlibs->libs[i]->name);
|
||||
if(!allow_missing_libs) return 1;
|
||||
}
|
||||
@@ -481,25 +495,6 @@ int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, u
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if(version==0) { //check if a default version has been defined
|
||||
const char* default_ver = ExistDefault(my_context->versym, name);
|
||||
if(default_ver) {
|
||||
if(GetGlobalSymbolStartEnd_internal(maplib, name, start, end, self, 2, default_ver)) {
|
||||
if(start && end && *end==*start) { // object is of 0 sized, try to see an "_END" object of null size
|
||||
uintptr_t start2, end2;
|
||||
char* buff = (char*)malloc(strlen(name) + strlen("_END") + 1);
|
||||
strcpy(buff, name);
|
||||
strcat(buff, "_END");
|
||||
if(GetGlobalSymbolStartEnd_internal(maplib, buff, &start2, &end2, self, 2, default_ver)) {
|
||||
if(end2>*end && start2==end2)
|
||||
*end = end2;
|
||||
}
|
||||
free(buff);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// some special case symbol, defined inside box86 itself
|
||||
if(!strcmp(name, "gdk_display")) {
|
||||
*start = (uintptr_t)my_GetGTKDisplay();
|
||||
@@ -513,6 +508,10 @@ int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, u
|
||||
printf_log(LOG_INFO, "Using global g_threads_got_initialized for gthread2 (%p:%p)\n", start, *(void**)start);
|
||||
return 1;
|
||||
}
|
||||
// check with default version...
|
||||
const char* defver;
|
||||
if(version==0 && (defver=GetDefaultVersion(my_context->defver, name)))
|
||||
return GetGlobalSymbolStartEnd(maplib, name, start, end, self, 2, defver);
|
||||
// not found...
|
||||
return 0;
|
||||
}
|
||||
@@ -535,6 +534,10 @@ elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name, int version, co
|
||||
return maplib->context->elfs[idx];
|
||||
}
|
||||
}
|
||||
// check with default version...
|
||||
const char* defver;
|
||||
if(version==0 && (defver=GetDefaultVersion(my_context->defver, name)))
|
||||
return GetGlobalSymbolElf(maplib, name, 2, defver);
|
||||
// nope, not found
|
||||
return NULL;
|
||||
}
|
||||
@@ -548,6 +551,10 @@ int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* st
|
||||
if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
|
||||
if(*start || *end)
|
||||
return 1;
|
||||
// check with default version...
|
||||
const char* defver;
|
||||
if(version==0 && (defver=GetDefaultVersion(my_context->defver, name)))
|
||||
return GetGlobalNoWeakSymbolStartEnd(maplib, name, start, end, 2, defver);
|
||||
// nope, not found
|
||||
return 0;
|
||||
}
|
||||
@@ -560,6 +567,10 @@ int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name, int version, c
|
||||
if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, &start, &end, version, vername, 1))
|
||||
if(start || end)
|
||||
return 1;
|
||||
// check with default version...
|
||||
const char* defver;
|
||||
if(version==0 && (defver=GetDefaultVersion(my_context->defver, name)))
|
||||
return IsGlobalNoWeakSymbolInNative(maplib, name, 2, defver);
|
||||
// nope, not found
|
||||
return 0;
|
||||
|
||||
@@ -583,45 +594,15 @@ int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, ui
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername)
|
||||
{
|
||||
if(maplib->context->elfs[0]==self) {
|
||||
if(GetSymbolStartEnd(maplib->localsymbols, name, start, end, version, vername, 1))
|
||||
if(*start || *end)
|
||||
return 1;
|
||||
} else {
|
||||
for(int i=0; i<maplib->libsz; ++i) {
|
||||
if(GetElfIndex(maplib->libraries[i])!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i])]==self))
|
||||
if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
|
||||
if(*start || *end)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername)
|
||||
{
|
||||
if(maplib->context->elfs[0]==self) {
|
||||
if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end, version, vername, 1))
|
||||
if(*start || *end)
|
||||
return 1;
|
||||
} else {
|
||||
for(int i=0; i<maplib->libsz; ++i) {
|
||||
if(GetElfIndex(maplib->libraries[i])!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i])]==self))
|
||||
if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
|
||||
if(*start || *end)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// check with default version...
|
||||
const char* defver;
|
||||
if(version==0 && (defver=GetDefaultVersion(my_context->defver, name)))
|
||||
return GetLocalSymbolStartEnd(maplib, name, start, end, self, 2, defver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, const char** libname, void** base)
|
||||
const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, const char** libname, void** base, library_t** lib)
|
||||
{
|
||||
// first, search in self...
|
||||
const char* ret = NULL;
|
||||
@@ -630,8 +611,7 @@ const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, c
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)p);
|
||||
if(h) {
|
||||
ret = FindNearestSymbolName(h, p, &offs, &size);
|
||||
}
|
||||
if(h) {
|
||||
|
||||
if(start)
|
||||
*start = (void*)offs;
|
||||
if(sz)
|
||||
@@ -640,6 +620,26 @@ const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, c
|
||||
*libname = ElfName(h);
|
||||
if(base)
|
||||
*base = GetBaseAddress(h);
|
||||
if(lib) {
|
||||
if(h == my_context->elfs[0])
|
||||
*lib = NULL; // main elf
|
||||
else {
|
||||
for(int i=0; i<my_context->maplib->libsz; ++i) {
|
||||
int idx = GetElfIndex(my_context->maplib->libraries[i]);
|
||||
if((idx!=-1) && (my_context->elfs[idx]==h)) {
|
||||
*lib = my_context->maplib->libraries[i];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<my_context->local_maplib->libsz; ++i) {
|
||||
int idx = GetElfIndex(my_context->local_maplib->libraries[i]);
|
||||
if((idx!=-1) && (my_context->elfs[idx]==h)) {
|
||||
*lib = my_context->local_maplib->libraries[i];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// TODO: find if cyclic references exists (should also fix MapLibAddMapLib)
|
||||
|
||||
+132
-11
@@ -9,6 +9,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <link.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "library.h"
|
||||
@@ -197,7 +198,9 @@ static void initNativeLib(library_t *lib, box86context_t* context) {
|
||||
if(strcmp(lib->name, wrappedlibs[i].name)==0) {
|
||||
if(wrappedlibs[i].init(lib, context)) {
|
||||
// error!
|
||||
printf_log(LOG_NONE, "Error initializing native %s (last dlerror is %s)\n", lib->name, dlerror());
|
||||
const char* error_str = dlerror();
|
||||
if(error_str) // don't print the message if there is no error string from last error
|
||||
printf_log(LOG_NONE, "Error initializing native %s (last dlerror is %s)\n", lib->name, error_str);
|
||||
return; // non blocker...
|
||||
}
|
||||
printf_log(LOG_INFO, "Using native(wrapped) %s\n", lib->name);
|
||||
@@ -209,10 +212,31 @@ static void initNativeLib(library_t *lib, box86context_t* context) {
|
||||
lib->getlocal = NativeLib_GetLocal;
|
||||
lib->type = 0;
|
||||
// Call librarian to load all dependant elf
|
||||
if(AddNeededLib(context->maplib, &lib->needed, lib, 0, (const char**)lib->priv.w.neededlibs, lib->priv.w.needed, context, NULL)) { // probably all native, not emulated, so that's fine
|
||||
if(AddNeededLib(context->maplib, &lib->needed, lib, 0, 0, (const char**)lib->priv.w.neededlibs, lib->priv.w.needed, context, NULL)) { // probably all native, not emulated, so that's fine
|
||||
printf_log(LOG_NONE, "Error: loading a needed libs in elf %s\n", lib->name);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
printf_log(LOG_DEBUG, "No dlinfo on Android %s\n", lib->name);
|
||||
#else
|
||||
linkmap_t *lm = addLinkMapLib(lib);
|
||||
if(!lm) {
|
||||
// Crashed already
|
||||
printf_log(LOG_DEBUG, "Failure to add lib %s linkmap\n", lib->name);
|
||||
break;
|
||||
}
|
||||
struct link_map real_lm;
|
||||
#ifndef RTLD_DI_LINKMAP
|
||||
#define RTLD_DI_LINKMAP 2
|
||||
#endif
|
||||
if(dlinfo(lib->priv.w.lib, RTLD_DI_LINKMAP, &real_lm)) {
|
||||
printf_log(LOG_DEBUG, "Failed to dlinfo lib %s\n", lib->name);
|
||||
}
|
||||
lm->l_addr = real_lm.l_addr;
|
||||
lm->l_name = real_lm.l_name;
|
||||
lm->l_ld = real_lm.l_ld;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -299,6 +323,24 @@ static void initEmulatedLib(const char* path, library_t *lib, box86context_t* co
|
||||
}
|
||||
}
|
||||
|
||||
static const char* essential_libs[] = {
|
||||
"libc.so.6", "libpthread.so.0", "librt.so.1", "libGL.so.1", "libGL.so", "libX11.so.6",
|
||||
"libasound.so.2", "libdl.so.2", "libm.so.6",
|
||||
"libXxf86vm.so.1", "libXinerama.so.1", "libXrandr.so.2", "libXext.so.6", "libXfixes.so.3", "libXcursor.so.1",
|
||||
"libXrender.so.1", "libXft.so.2", "libXi.so.6", "libXss.so.1", "libXpm.so.4", "libXau.so.6", "libXdmcp.so.6",
|
||||
"libX11-xcb.so.1", "libxcb.so.1", "libxcb-xfixes.so.0", "libxcb-shape.so.0", "libxcb-shm.so.0", "libxcb-randr.so.0",
|
||||
"libxcb-image.so.0", "libxcb-keysyms.so.1", "libxcb-xtest.so.0", "libxcb-glx.so.0", "libxcb-dri2.so.0", "libxcb-dri3.so.0",
|
||||
"libXtst.so.6", "libXt.so.6", "libXcomposite.so.1", "libXdamage.so.1", "libXmu.so.6", "libxkbcommon.so.0",
|
||||
"libxkbcommon-x11.so.0", "libpulse-simple.so.0", "libpulse.so.0", "libvulkan.so.1", "libvulkan.so",
|
||||
"ld-linux-x86-64.so.2", "crashhandler.so", "libtcmalloc_minimal.so.0", "libtcmalloc_minimal.so.4"
|
||||
};
|
||||
static int isEssentialLib(const char* name) {
|
||||
for (int i=0; i<sizeof(essential_libs)/sizeof(essential_libs[0]); ++i)
|
||||
if(!strcmp(name, essential_libs[i]))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern char* libGL;
|
||||
library_t *NewLibrary(const char* path, box86context_t* context)
|
||||
{
|
||||
@@ -330,12 +372,18 @@ library_t *NewLibrary(const char* path, box86context_t* context)
|
||||
}
|
||||
}
|
||||
int notwrapped = FindInCollection(lib->name, &context->box86_emulated_libs);
|
||||
int essential = isEssentialLib(lib->name);
|
||||
if(!notwrapped && box86_prefer_emulated && !essential)
|
||||
notwrapped = 1;
|
||||
int precise = (!box86_prefer_wrapped && !essential && path && path[0]=='/')?1:0;
|
||||
if(!notwrapped && precise && strstr(path, "libtcmalloc_minimal.so"))
|
||||
precise = 0; // allow native version for tcmalloc_minimum
|
||||
// check if name is libSDL_sound-1.0.so.1 but with SDL2 loaded, then try emulated first...
|
||||
if(!notwrapped && !strcmp(lib->name, "libSDL_sound-1.0.so.1") && my_context->sdl2lib)
|
||||
notwrapped = 1;
|
||||
// And now, actually loading a library
|
||||
// look for native(wrapped) libs first
|
||||
if(!notwrapped)
|
||||
if(!notwrapped && !precise)
|
||||
initNativeLib(lib, context);
|
||||
// then look for a native one
|
||||
if(lib->type==-1)
|
||||
@@ -366,7 +414,7 @@ int AddSymbolsLibrary(lib_t *maplib, library_t* lib, x86emu_t* emu)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x86emu_t* emu)
|
||||
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, int bindnow, x86emu_t* emu)
|
||||
{
|
||||
if(!lib)
|
||||
return 0;
|
||||
@@ -376,11 +424,11 @@ int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x86emu_t* emu)
|
||||
lib->priv.n.finalized = 1;
|
||||
elfheader_t *elf_header = my_context->elfs[lib->priv.n.elf_index];
|
||||
// finalize relocations
|
||||
if(RelocateElf(my_context->maplib, local_maplib, elf_header)) {
|
||||
if(RelocateElf(my_context->maplib, local_maplib, bindnow, elf_header)) {
|
||||
printf_log(LOG_NONE, "Error: relocating symbols in elf %s\n", lib->name);
|
||||
return 1;
|
||||
}
|
||||
RelocateElfPlt(my_context->maplib, local_maplib, elf_header);
|
||||
RelocateElfPlt(my_context->maplib, local_maplib, bindnow, elf_header);
|
||||
#ifdef HAVE_TRACE
|
||||
if(trace_func) {
|
||||
if (GetGlobalSymbolStartEnd(local_maplib, trace_func, &trace_start, &trace_end, elf_header, -1, NULL)) {
|
||||
@@ -434,11 +482,11 @@ int ReloadLibrary(library_t* lib, x86emu_t* emu)
|
||||
}
|
||||
// can close the file now
|
||||
fclose(f);
|
||||
if(RelocateElf(lib->context->maplib, lib->maplib, elf_header)) {
|
||||
if(RelocateElf(lib->context->maplib, lib->maplib, 0, elf_header)) {
|
||||
printf_log(LOG_NONE, "Error: relocating symbols in elf %s\n", lib->name);
|
||||
return 1;
|
||||
}
|
||||
RelocateElfPlt(lib->context->maplib, lib->maplib, elf_header);
|
||||
RelocateElfPlt(lib->context->maplib, lib->maplib, 0, elf_header);
|
||||
// init (will use PltRelocator... because some other libs are not yet resolved)
|
||||
RunElfInit(elf_header, emu);
|
||||
}
|
||||
@@ -448,6 +496,13 @@ int ReloadLibrary(library_t* lib, x86emu_t* emu)
|
||||
void InactiveLibrary(library_t* lib)
|
||||
{
|
||||
lib->active = 0;
|
||||
#ifdef DYNAREC
|
||||
// free Dynablocks associated with this lib
|
||||
if(lib->type==1) {
|
||||
elfheader_t *elf_header = lib->context->elfs[lib->priv.n.elf_index];
|
||||
cleanDBFromAddressRange((uintptr_t)GetBaseAddress(elf_header), GetBaseSize(elf_header), 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Free1Library(library_t **lib, x86emu_t* emu)
|
||||
@@ -528,7 +583,7 @@ int IsSameLib(library_t* lib, const char* path)
|
||||
}
|
||||
int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local)
|
||||
{
|
||||
if(!name[0] || !lib->active)
|
||||
if(!name[0] || !lib || !lib->active)
|
||||
return 0;
|
||||
khint_t k;
|
||||
// check first if already in the map
|
||||
@@ -554,7 +609,7 @@ int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uin
|
||||
}
|
||||
int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local)
|
||||
{
|
||||
if(!name[0] || !lib->active)
|
||||
if(!name[0] || !lib || !lib->active)
|
||||
return 0;
|
||||
khint_t k;
|
||||
// get a new symbol
|
||||
@@ -580,7 +635,7 @@ int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* star
|
||||
}
|
||||
int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local)
|
||||
{
|
||||
if(!name[0] || !lib->active)
|
||||
if(!name[0] || !lib || !lib->active)
|
||||
return 0;
|
||||
khint_t k;
|
||||
// check first if already in the map
|
||||
@@ -707,6 +762,14 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
|
||||
strcat(newname, name);
|
||||
symbol = dlsym(lib->priv.w.lib, newname);
|
||||
}
|
||||
if(!symbol)
|
||||
symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, name);
|
||||
if(!symbol && lib->priv.w.altprefix) {
|
||||
char newname[200];
|
||||
strcpy(newname, lib->priv.w.altprefix);
|
||||
strcat(newname, name);
|
||||
symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, newname);
|
||||
}
|
||||
if(!symbol) {
|
||||
printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", name, lib->name);
|
||||
return 0;
|
||||
@@ -760,6 +823,14 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
|
||||
strcat(newname, name);
|
||||
symbol = dlsym(lib->priv.w.lib, newname);
|
||||
}
|
||||
if(!symbol)
|
||||
symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, name);
|
||||
if(!symbol && lib->priv.w.altprefix) {
|
||||
char newname[200];
|
||||
strcpy(newname, lib->priv.w.altprefix);
|
||||
strcat(newname, name);
|
||||
symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, newname);
|
||||
}
|
||||
if(!symbol) {
|
||||
printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", name, lib->name);
|
||||
return 0;
|
||||
@@ -778,6 +849,8 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
|
||||
symbol = dlsym(lib->priv.w.lib, kh_value(lib->symbol2map, k).name);
|
||||
if(!symbol)
|
||||
symbol = dlsym(RTLD_DEFAULT, kh_value(lib->symbol2map, k).name); // search globaly maybe
|
||||
if(!symbol)
|
||||
symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, kh_value(lib->symbol2map, k).name);
|
||||
if(!symbol) {
|
||||
printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", kh_value(lib->symbol2map, k).name, lib->name);
|
||||
return 0;
|
||||
@@ -795,6 +868,8 @@ int getSymbolInMaps(library_t*lib, const char* name, int noweak, uintptr_t *addr
|
||||
{
|
||||
if(!lib->active)
|
||||
return 0;
|
||||
if(version==-2) // don't send global native symbol for a version==-2 search
|
||||
return 0;
|
||||
// check in datamaps (but no version, it's not handled there)
|
||||
if(getSymbolInDataMaps(lib, name, noweak, addr, size))
|
||||
return 1;
|
||||
@@ -838,6 +913,52 @@ lib_t* GetMaplib(library_t* lib)
|
||||
return lib->maplib;
|
||||
}
|
||||
|
||||
|
||||
linkmap_t* getLinkMapLib(library_t* lib)
|
||||
{
|
||||
linkmap_t* lm = my_context->linkmap;
|
||||
while(lm) {
|
||||
if(lm->l_lib == lib)
|
||||
return lm;
|
||||
lm = lm->l_next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
linkmap_t* addLinkMapLib(library_t* lib)
|
||||
{
|
||||
if(!my_context->linkmap) {
|
||||
my_context->linkmap = (linkmap_t*)calloc(1, sizeof(linkmap_t));
|
||||
my_context->linkmap->l_lib = lib;
|
||||
return my_context->linkmap;
|
||||
}
|
||||
linkmap_t* lm = my_context->linkmap;
|
||||
while(lm->l_next)
|
||||
lm = lm->l_next;
|
||||
lm->l_next = (linkmap_t*)calloc(1, sizeof(linkmap_t));
|
||||
lm->l_next->l_lib = lib;
|
||||
lm->l_next->l_prev = lm;
|
||||
return lm->l_next;
|
||||
}
|
||||
void removeLinkMapLib(library_t* lib)
|
||||
{
|
||||
linkmap_t* lm = getLinkMapLib(lib);
|
||||
if(!lm) return;
|
||||
if(lm->l_next)
|
||||
lm->l_next->l_prev = lm->l_prev;
|
||||
if(lm->l_prev)
|
||||
lm->l_prev->l_next = lm->l_next;
|
||||
free(lm);
|
||||
}
|
||||
|
||||
void AddMainElfToLinkmap(elfheader_t* elf)
|
||||
{
|
||||
linkmap_t* lm = addLinkMapLib(NULL); // main elf will have a null lib link
|
||||
|
||||
lm->l_addr = (Elf32_Addr)GetElfDelta(elf);
|
||||
lm->l_name = my_context->fullpath;
|
||||
lm->l_ld = GetDynamicSection(elf);
|
||||
}
|
||||
|
||||
static int is_neededlib_present(needed_libs_t* needed, library_t* lib)
|
||||
{
|
||||
if(!needed || !lib)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef __LIBRARY_PRIVATE_H_
|
||||
#define __LIBRARY_PRIVATE_H_
|
||||
#include <stdint.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
@@ -105,4 +106,19 @@ typedef struct map_onedata_s {
|
||||
|
||||
int getSymbolInMaps(library_t*lib, const char* name, int noweak, uintptr_t *addr, uint32_t *size, int version, const char* vername, int local); // Add bridges to functions
|
||||
|
||||
typedef struct linkmap_s {
|
||||
// actual struct link_map
|
||||
Elf32_Addr l_addr;
|
||||
char* l_name;
|
||||
Elf32_Dyn* l_ld;
|
||||
struct linkmap_s *l_next, *l_prev;
|
||||
// custom
|
||||
library_t* l_lib;
|
||||
|
||||
} linkmap_t;
|
||||
|
||||
linkmap_t* getLinkMapLib(library_t* lib);
|
||||
linkmap_t* addLinkMapLib(library_t* lib);
|
||||
void removeLinkMapLib(library_t* lib);
|
||||
|
||||
#endif //__LIBRARY_PRIVATE_H_
|
||||
Loaded 100 of 393 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user