Compare commits

..
2180 changed files with 56152 additions and 398190 deletions

No files matched your search

-18
View File
@@ -1,18 +0,0 @@
---
BasedOnStyle: WebKit
AlignTrailingComments: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
ColumnLimit: 0
IndentWidth: 4
SortIncludes: false
MaxEmptyLinesToKeep: 2
IndentCaseLabels: true
AlignConsecutiveMacros: true
WhitespaceSensitiveMacros: ['QUOTE']
IfMacros: ['IFX', 'IFXORNAT', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF', 'IF_UNALIGNED', 'IF_ALIGNED']
UseTab: Never
IndentPPDirectives: None
---
-99
View File
@@ -1,99 +0,0 @@
### Manual build Box64 with Github Action
name: Custom build Box64
on:
workflow_dispatch:
inputs:
platform:
description: 'Target platform name'
required: true
default: 'GENERIC_ARM'
type: choice
options:
- X64
- GENERIC_ARM
- PHYTIUM
- RK3326
- RK3399
- RK3588
- RPI4ARM64
- RPI5ARM64
- SD845
- SD888
- ADLINK
- TEGRAX1
- ARM64
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 Box64 Repository"
uses: actions/checkout@v4
- name: "Environment preparation"
run: |
sudo apt-get update
if [[ ${{ github.event.inputs.platform }} != 'X64' && ${{ github.event.inputs.platform }} != 'GENERIC_ARM' ]]; then
echo "BOX64_PLATFORM_MARCRO=-D${{ github.event.inputs.platform }}=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
else
if [[ ${{ github.event.inputs.platform }} == 'X64' ]]; then
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
else
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
fi
fi
- name: "Display Build info"
run: |
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
echo "CMake C Compiler: ${{ env.BOX64_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 Box64"
run: |
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }} ${{ env.BOX64_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@v4
with:
name: box64-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
path: build/box64
-327
View File
@@ -1,327 +0,0 @@
### Auto build Box64 and release its binary with Github Action
name: Build and Release Box64
on:
workflow_dispatch:
release:
push:
paths:
- "**/*.c"
- "**/*.h"
- "**/*.S"
- "**/*.py"
- "CMakeLists.txt"
- "**/*.yml"
pull_request:
types: [assigned, opened, synchronize, reopened]
paths:
- "**/*.c"
- "**/*.h"
- "**/*.S"
- "**/*.py"
- "CMakeLists.txt"
- "**/*.yml"
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC]
type: [Release, Trace, StaticBuild, Box32]
os: [ubuntu-latest, ubuntu-22.04-arm]
exclude:
- platform: ANDROID
type: StaticBuild
- platform: TERMUX
type: StaticBuild
- platform: X64
type: StaticBuild
- platform: ANDROID
type: Box32
- platform: TERMUX
type: Box32
- platform: X64
os: ubuntu-22.04-arm
- platform: RISCV
os: ubuntu-22.04-arm
- platform: RK3588
os: ubuntu-latest
- platform: ARM64
os: ubuntu-latest
- platform: ANDROID
os: ubuntu-22.04-arm
- platform: TERMUX
os: ubuntu-22.04-arm
- platform: LARCH64
os: ubuntu-22.04-arm
- platform: ANDROID_GLIBC
os: ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- name: "Checkout Box64 Repository"
uses: actions/checkout@v4
- name: "Environment preparation"
run: |
sudo apt-get update
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
sudo apt-get -y install git cmake make python3 patchelf
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
sudo apt-get -y install p7zip
wget https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
unzip android-ndk-r26b-linux.zip
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
git clone https://github.com/termux/termux-docker.git
sudo cp -rf termux-docker/system/arm /system
sudo chown -R $(whoami):$(whoami) /system
sudo chmod 755 -R /system
elif [[ ${{ matrix.platform }} == 'ANDROID_GLIBC' ]]; then
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-DARM64=1 -DWINLATOR_GLIBC=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
else
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
fi
if [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
wget https://mirrors.utermux.dev/termux/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1_aarch64.deb
7z x libandroid-sysv-semaphore_0.1_aarch64.deb
tar -xf data.tar.xz
sudo cp -rf data /
sudo chmod 755 -R /data
sudo chown -R $(whoami):$(whoami) /data
echo "CFLAGS=-L/data/data/com.termux/files/usr/lib" >> $GITHUB_ENV
echo "IS_TERMUX=1" >> $GITHUB_ENV
echo "QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib" >> $GITHUB_ENV
else
echo "IS_TERMUX=0" >> $GITHUB_ENV
fi
else
if [[ ${{ matrix.platform }} == 'X64' ]]; then
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
sudo mkdir /usr/local/larch
wget -O- -q https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
sudo ln -sf /usr/local/larch/target /usr/loongarch64-linux-gnu
sudo cp -r /usr/local/larch/loongarch64-unknown-linux-gnu/lib/* /usr/loongarch64-linux-gnu/lib64/
for i in objdump objcopy strip; do
sudo ln -sf /usr/local/larch/bin/loongarch64-unknown-linux-gnu-$i /usr/bin/loongarch64-linux-gnu-$i
done
echo '/usr/local/larch/bin/loongarch64-unknown-linux-gnu-gcc -L/usr/local/larch/loongarch64-unknown-linux-gnu "$@"' | sudo tee /usr/bin/loongarch64-linux-gnu-gcc
echo '/usr/local/larch/bin/loongarch64-unknown-linux-gnu-g++ -L/usr/local/larch/loongarch64-unknown-linux-gnu "$@"' | sudo tee /usr/bin/loongarch64-linux-gnu-g++
sudo chmod 755 /usr/bin/loongarch64-linux-gnu-{gcc,g++}
echo BOX64_PLATFORM_MARCRO="-DLARCH64=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
else
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
fi
fi
if [[ ${{ matrix.type }} == 'Release' ]]; then
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
echo BOX64_BOX32=0 >> $GITHUB_ENV
elif [[ ${{ matrix.type }} == 'StaticBuild' ]]; then
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
echo BOX64_STATICBUILD=1 >> $GITHUB_ENV
echo BOX64_BOX32=0 >> $GITHUB_ENV
elif [[ ${{ matrix.type }} == 'Box32' ]]; then
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
echo BOX64_BOX32=1 >> $GITHUB_ENV
else
echo BOX64_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
echo BOX64_HAVE_TRACE=1 >> $GITHUB_ENV
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
echo BOX64_BOX32=0 >> $GITHUB_ENV
fi
- name: "Get XuanTie QEMU Cache Key"
if: matrix.platform == 'RISCV'
id: get-xuantie-qemu-cache-key
run: |
echo "key=f2dfdd13014d51f957c7172acc2e791cb42dc400" >> $GITHUB_OUTPUT
- name: "Cache XuanTie QEMU"
if: matrix.platform == 'RISCV'
id: cache-xuantie-qemu
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/xuantie_qemu_install
key: ${{ runner.os }}-${{ steps.get-xuantie-qemu-cache-key.outputs.key }}-xuantie-qemu
- name: "Checkout XuanTie QEMU"
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
uses: actions/checkout@v3
with:
repository: revyos/qemu
path: xuantie_qemu
ref: f2dfdd13014d51f957c7172acc2e791cb42dc400
- name: "Build XuanTie QEMU for XTheadVector"
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
run: |
cd xuantie_qemu
./configure --prefix=$GITHUB_WORKSPACE/xuantie_qemu_install --target-list=riscv64-linux-user --disable-system
make -j$(nproc)
make install
- name: "Display Build info"
run: |
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
echo "Build type: ${{ env.BOX64_BUILD_TYPE }}"
echo "Trace Enabled: ${{ env.BOX64_HAVE_TRACE }}"
echo "StaticBuild Enabled: ${{ env.BOX64_STATICBUILD }}"
echo "Box32 Enabled: ${{ env.BOX64_BOX32 }}"
- name: "Build Box64"
run: |
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }}\
-DTERMUX=${{ env.IS_TERMUX }}\
${{ env.BOX64_PLATFORM_MARCRO }}\
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
-DSTATICBUILD=${{ env.BOX64_STATICBUILD }}\
-DBOX32=${{ env.BOX64_BOX32 }}\
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON\
-DCI=${{ matrix.platform != 'ANDROID' }}
make -j$(nproc) VERBOSE=1
- name: "Test Box64"
run: |
if [[ ${{ matrix.platform }} != 'X64' ]]; then
mkdir qemu9
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-9.0.2-1-x86_64.pkg.tar.zst | tar -I zstd -C qemu9 -xf -
sudo cp qemu9/usr/bin/* /usr/bin/
fi
cd build
export CTEST_OPTIONS="-j$(nproc) --timeout 120 --output-on-failure --repeat until-pass:20"
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
export INTERPRETER=qemu-riscv64-static
export QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/
ctest $CTEST_OPTIONS
QEMU_CPU=rv64,v=false BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest $CTEST_OPTIONS
QEMU_CPU=rv64,v=true,vlen=128,vext_spec=v1.0 ctest $CTEST_OPTIONS
QEMU_CPU=rv64,v=true,vlen=256,vext_spec=v1.0 ctest $CTEST_OPTIONS
QEMU_CPU=thead-c906 ctest $CTEST_OPTIONS
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 QEMU_CPU=rv64,v=true,vlen=128,vext_spec=v1.0 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 QEMU_CPU=rv64,v=true,vlen=256,vext_spec=v1.0 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 QEMU_CPU=thead-c906 ctest $CTEST_OPTIONS -E nocosim
export INTERPRETER=$GITHUB_WORKSPACE/xuantie_qemu_install/bin/qemu-riscv64
QEMU_CPU=c910v ctest $CTEST_OPTIONS
BOX64_DYNAREC_TEST=1 QEMU_CPU=c910v ctest $CTEST_OPTIONS -E nocosim
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
export INTERPRETER=qemu-loongarch64-static
export QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/
BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
export INTERPRETER=qemu-aarch64-static
export QEMU_LD_PREFIX=/system/lib64
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
ctest $CTEST_OPTIONS
elif [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
export INTERPRETER=qemu-aarch64-static
export QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
export QEMU_LD_PREFIX=/system/lib64:/data/data/com.termux/files/usr/lib
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
ctest $CTEST_OPTIONS
else
ctest -j$(nproc)
fi
- name: "Get short Git commit"
id: git-info
run: echo "SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: "Get Box64 Version"
run: echo "BOX64_VERSION=$(cat src/box64version.h | grep BOX64_MAJOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_MINOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_REVISION | cut -d " " -f 3)" >> $GITHUB_ENV
- name: "Packaging WCP file for Winlator"
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
run: |
cd build
cat <<EOF > profile.json
{
"type": "Box64",
"versionName": "latest-${SHORT_COMMIT}",
"versionCode": 1,
"description": "Box64-latest-${SHORT_COMMIT}. Built from [https://github.com/ptitSeb/box64].",
"files": [
{
"source": "box64",
"target": "\${localbin}/box64"
}
]
}
EOF
patchelf --set-interpreter /data/data/com.winlator/files/imagefs/usr/lib/ld-linux-aarch64.so.1 ./box64
tar --zstd -cf box64-latest.wcp box64 profile.json
- name: "Package Rat File for MiceWine"
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
run: |
cd build
mkdir -p files/usr/bin
cp box64 files/usr/bin
echo "name=Box64 (CI Build)" > pkg-header
echo "category=Box64" >> pkg-header
echo "version=${BOX64_VERSION}-${SHORT_COMMIT}" >> pkg-header
echo "architecture=aarch64" >> pkg-header
echo "vkDriverLib=" >> pkg-header
7z -tzip -mx=5 a box64-latest.rat files pkg-header
- name: "Upload Artifact"
uses: actions/upload-artifact@v4
with:
name: box64-${{ matrix.platform }}-${{ matrix.type }}
path: build/box64
- name: "Upload WCP file"
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
uses: actions/upload-artifact@v4
with:
name: box64-latest-${{ matrix.type }}-wcp
path: build/box64-latest.wcp
- name: "Upload Rat File"
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
uses: actions/upload-artifact@v4
with:
name: box64-MiceWine-${{ matrix.type }}
path: build/box64-latest.rat
+5 -28
View File
@@ -55,35 +55,12 @@ dkms.conf
build/
build*/
.vscode
.cache
.gdb_history
src/git_head.h
backup/
# Wrapper helper
/wrapperhelper/bin
/wrapperhelper/makedir
/wrapperhelper/obj
/wrapperhelper/sanaddress
/wrapperhelper/sanleak
/wrapperhelper/sanundefined
/wrapperhelper/src/machine.gen
/wrapperhelper/*.h
!/wrapperhelper/example-libc.h
# macOS
.DS_Store
# Archives
*.7z
*.deb
*.eopkg
*.gz
*.rar
*.rpm
*.tar*
*.xbps
*.xz
*.zip
*.zst
*.zstd
# LLVMprivateGenerator
/LLVMprivateGenerator/*
!/LLVMprivateGenerator/Makefile
!/LLVMprivateGenerator/main.cpp
!/LLVMprivateGenerator/registered_structs.cpp
Regular → Executable
View File
File mode changed.
Regular → Executable
+162 -1345
View File
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
all: dumpSigs
dumpSigs: main.o registered_structs.o
g++ -g3 -std=gnu++17 -fno-rtti main.o registered_structs.o -o dumpSigs "-L$(LLVM_install_dir)/lib" -lclang-cpp -lclangTooling -Wl,-rpath "-Wl,$(LLVM_install_dir)/lib"
main.o: main.cpp
g++ -g3 -std=gnu++17 -fno-rtti -c main.cpp -Wfatal-errors "-I$(LLVM_install_dir)/include" -o main.o
registered_structs.o: registered_structs.cpp
g++ -g3 -std=gnu++17 -fno-rtti -c registered_structs.cpp -Wfatal-errors -o registered_structs.o
clean:
$(RM) dumpSigs main.o registered_structs.o
+458
View File
@@ -0,0 +1,458 @@
#include <algorithm>
#include <fstream>
#include <iostream>
#include <numeric>
#include <unordered_map>
#include <utility>
#include <vector>
#include <llvm/Support/raw_ostream.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Decl.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/PrettyPrinter.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
clang::MangleContext *mangler = nullptr;
std::unordered_map<std::string, std::pair<std::string, bool>> funMap;
std::vector<std::string> funList;
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig);
clang::QualType getPointedType(const clang::QualType q) {
if (const clang::PointerType *p = q->getAs<clang::PointerType>())
return getPointedType(p->getPointeeType());
else if (const clang::ReferenceType *r = q->getAs<clang::ReferenceType>())
return getPointedType(r->getPointeeType());
else
return q;
}
std::string record2name(const clang::RecordDecl &q, const clang::QualType *qorig) {
std::string s = q.getNameAsString();
if (s == "") {
if (!qorig) return "????.!";
if (const clang::TypedefType *tt = (*qorig)->getAs<clang::TypedefType>()) {
// Typedef
if (clang::TypedefNameDecl *td = tt->getDecl()) {
return td->getNameAsString();
} else {
return "<typedef with no declaration>";
}
} else {
return std::string("<unknown type ") + (*qorig)->getTypeClassName() + ">";
}
} else {
return s;
}
}
char ptr2char(const std::string &str) __attribute__((const));
const char *ptr2str(const std::string &str) __attribute__((const));
char type2char(const clang::QualType &qual /* Canonical */, const clang::QualType *qorig) {
if (qual->isBuiltinType()) {
switch (static_cast<const clang::BuiltinType&>(*qual).getKind()) {
case clang::BuiltinType::Kind::Void:
return 'v';
case clang::BuiltinType::Kind::Bool:
return 'i';
case clang::BuiltinType::Kind::Char_U:
return 'C';
case clang::BuiltinType::Kind::Char_S:
return 'c';
case clang::BuiltinType::Kind::Char8:
return 'c';
case clang::BuiltinType::Kind::UChar:
return 'C';
case clang::BuiltinType::Kind::SChar:
return 'c';
case clang::BuiltinType::Kind::WChar_U:
return 'W';
case clang::BuiltinType::Kind::UShort:
return 'W';
case clang::BuiltinType::Kind::WChar_S:
return 'w';
case clang::BuiltinType::Kind::Char16:
return 'w';
case clang::BuiltinType::Kind::Short:
return 'w';
case clang::BuiltinType::Kind::UInt:
return 'u';
case clang::BuiltinType::Kind::Char32:
return 'i';
case clang::BuiltinType::Kind::Int:
return 'i';
case clang::BuiltinType::Kind::ULong:
return 'L';
case clang::BuiltinType::Kind::Long:
return 'l';
case clang::BuiltinType::Kind::ULongLong:
return 'U';
case clang::BuiltinType::Kind::LongLong:
return 'I';
case clang::BuiltinType::Kind::UInt128:
return 'H';
case clang::BuiltinType::Kind::Int128:
return 'H';
case clang::BuiltinType::Kind::Float:
return 'f';
case clang::BuiltinType::Kind::Double:
return 'd';
case clang::BuiltinType::Kind::LongDouble:
return 'D';
case clang::BuiltinType::Kind::NullPtr:
return 'p'; // nullptr_t
case clang::BuiltinType::Kind::Half:
case clang::BuiltinType::Kind::BFloat16:
case clang::BuiltinType::Kind::ShortAccum:
case clang::BuiltinType::Kind::Accum:
case clang::BuiltinType::Kind::LongAccum:
case clang::BuiltinType::Kind::UShortAccum:
case clang::BuiltinType::Kind::UAccum:
case clang::BuiltinType::Kind::ULongAccum:
case clang::BuiltinType::Kind::ShortFract:
case clang::BuiltinType::Kind::Fract:
case clang::BuiltinType::Kind::LongFract:
case clang::BuiltinType::Kind::UShortFract:
case clang::BuiltinType::Kind::UFract:
case clang::BuiltinType::Kind::ULongFract:
case clang::BuiltinType::Kind::SatShortAccum:
case clang::BuiltinType::Kind::SatAccum:
case clang::BuiltinType::Kind::SatLongAccum:
case clang::BuiltinType::Kind::SatUShortAccum:
case clang::BuiltinType::Kind::SatUAccum:
case clang::BuiltinType::Kind::SatULongAccum:
case clang::BuiltinType::Kind::SatShortFract:
case clang::BuiltinType::Kind::SatFract:
case clang::BuiltinType::Kind::SatLongFract:
case clang::BuiltinType::Kind::SatUShortFract:
case clang::BuiltinType::Kind::SatUFract:
case clang::BuiltinType::Kind::SatULongFract:
case clang::BuiltinType::Kind::Float16:
case clang::BuiltinType::Kind::Float128:
case clang::BuiltinType::Kind::Overload:
case clang::BuiltinType::Kind::BoundMember:
case clang::BuiltinType::Kind::PseudoObject:
case clang::BuiltinType::Kind::Dependent:
case clang::BuiltinType::Kind::UnknownAny:
case clang::BuiltinType::Kind::ARCUnbridgedCast:
case clang::BuiltinType::Kind::BuiltinFn:
case clang::BuiltinType::Kind::ObjCId:
case clang::BuiltinType::Kind::ObjCClass:
case clang::BuiltinType::Kind::ObjCSel:
#define IMAGE_TYPE(it, id, si, a, s) case clang::BuiltinType::Kind::id:
#include <clang/Basic/OpenCLImageTypes.def>
#undef IMAGE_TYPE
case clang::BuiltinType::Kind::OCLSampler:
case clang::BuiltinType::Kind::OCLEvent:
case clang::BuiltinType::Kind::OCLClkEvent:
case clang::BuiltinType::Kind::OCLQueue:
case clang::BuiltinType::Kind::OCLReserveID:
case clang::BuiltinType::Kind::IncompleteMatrixIdx:
case clang::BuiltinType::Kind::OMPArraySection:
case clang::BuiltinType::Kind::OMPArrayShaping:
case clang::BuiltinType::Kind::OMPIterator:
#define EXT_OPAQUE_TYPE(et, id, e) case clang::BuiltinType::Kind::id:
#include <clang/Basic/OpenCLExtensionTypes.def>
#define SVE_TYPE(n, id, si) case clang::BuiltinType::Kind::id:
#include <clang/Basic/AArch64SVEACLETypes.def>
#define PPC_VECTOR_TYPE(n, id, s) case clang::BuiltinType::Kind::id:
#include <clang/Basic/PPCTypes.def>
#undef EXT_OPAQUE_TYPE
#undef SVE_TYPE
#undef PPC_VECTOR_TYPE
return '!';
default:
return ':';
}
} else if (qual->isEnumeralType()) {
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
if (!ed) {
return 'i';
} else {
return type2char(ed->getIntegerType().getCanonicalType(), qorig);
}
} else if (qual->isFunctionPointerType()) {
return '@';
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
const clang::QualType &pointed = getPointedType(qual);
if (isTypeTrivial(pointed, qorig)) {
return 'p';
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
clang::RecordDecl *rc = rct->getDecl();
if (!rc) {
return '!';
} else if (!rc->isCompleteDefinition()) {
return 'p';
} else {
std::string str;
if (qorig) {
const clang::QualType qpted = getPointedType(*qorig);
str = record2name(*rc, &qpted);
} else {
str = record2name(*rc, nullptr);
}
char ret = ptr2char(str);
if (ret) return ret;
else {
return '!';
}
}
} else {
return '!';
}
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
clang::RecordDecl *rc = rct->getDecl();
if (!rc) {
return '?';
} else if (rc->getNameAsString() == "__builtin_va_list") {
// va_list
return 'A';
} else {
return '?';
}
} else {
return '?';
}
}
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig) {
const char c = type2char(q, qorig);
#define GO(chr) || (c == chr)
return (c == 'v')
GO('i') GO('u')
GO('I') GO('U')
GO('l') GO('L')
GO('f') GO('d')
GO('D') GO('K')
GO('0') GO('1')
GO('C') GO('c')
GO('W') GO('w')
GO('H')
GO('p');
#undef GO
}
bool isTypeValid(const clang::QualType &q, const clang::QualType *qorig) {
const char c = type2char(q, qorig);
if (c == 'A') return false;
if (c == 'V') return false;
return ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
}
const std::string type2string(const clang::QualType &qual, const clang::QualType *qorig) {
if (qual->isBuiltinType()) {
return std::string("(builtin) ") + static_cast<const clang::BuiltinType&>(*qual).getName(clang::PrintingPolicy{{}}).data();
} else if (qual->isFunctionPointerType()) {
return "Callback (function pointer)";
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
std::string prefix = qual->isAnyPointerType() ? "Pointer to " : "Reference to ";
const clang::QualType &pointed = getPointedType(qual);
if (isTypeTrivial(pointed, qorig)) {
return prefix + "trivial object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
clang::RecordDecl *rc = rct->getDecl();
if (!rc) {
return prefix + "unknown record";
} else if (!rc->isCompleteDefinition()) {
return prefix + "incomplete record " + rc->getNameAsString();
} else {
std::string str;
if (qorig) {
const clang::QualType qpted = getPointedType(*qorig);
str = record2name(*rc, &qpted);
} else {
str = record2name(*rc, nullptr);
}
const char *ret = ptr2str(str);
if (ret[0] != '\0') {
return prefix + ret;
} else {
if (mangler && mangler->shouldMangleDeclName(rc)) {
std::string mangled;
{
llvm::raw_string_ostream strstr{mangled};
mangler->mangleName(rc, strstr);
}
return prefix + "unknown record " + str + " (=== " + mangled + ")";
} else {
return prefix + "unknown record " + str;
}
}
}
} else {
return prefix + "non-trivial or typedef'ed object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
//return "Pointer (maybe to callback)";
}
} else if (qual->isEnumeralType()) {
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
if (!ed) {
return "Enumeration with unknown underlying integer type (assuming int)";
} else {
return "Enumeration with underlying type " + type2string(ed->getIntegerType().getCanonicalType(), nullptr);
}
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
clang::RecordDecl *rc = rct->getDecl();
if (!rc) {
return "Unknown record";
} else if (rc->getNameAsString() == "__builtin_va_list") {
return "va_list";
} else {
return "Unknown record " + std::string(rc->getName().data());
}
} else {
return std::string("??? ") + qual->getTypeClassName();
}
}
class Visitor : public clang::RecursiveASTVisitor<Visitor> {
public:
clang::ASTContext &context;
bool shouldVisitTemplateInstantiations() const /* override */ { return true; }
Visitor(clang::CompilerInstance &ci) : context(ci.getASTContext()) {
if (!mangler) {
mangler = clang::ItaniumMangleContext::create(context, ci.getDiagnostics());
}
}
~Visitor() {
if (mangler) {
delete mangler;
mangler = nullptr;
}
}
bool VisitDecl(clang::Decl *decl) /* override */ {
std::cerr << std::flush;
if (!decl) return true;
if ((decl->getKind() >= clang::Decl::Kind::firstFunction) && (decl->getKind() <= clang::Decl::Kind::lastFunction)) {
clang::DeclaratorDecl *ddecl = static_cast<clang::DeclaratorDecl*>(decl);
std::cout << "Function detected!\n";
std::string funName{ddecl->getName()};
auto niceprint = [](const std::string &infotype, const auto &dat){ std::cout << " " << infotype << ": " << dat << "\n"; };
niceprint("Function name", funName);
if (mangler && mangler->shouldMangleDeclName(ddecl)) {
std::string mangled;
{
llvm::raw_string_ostream strstr{mangled};
mangler->mangleName(ddecl, strstr);
}
niceprint("Function mangled name", mangled);
funName = std::move(mangled);
}
bool valid;
std::string funTypeStr{""};
if (ddecl->getFunctionType()->isFunctionNoProtoType()) {
const clang::FunctionNoProtoType *funType = static_cast<const clang::FunctionNoProtoType*>(ddecl->getFunctionType());
const auto &retType = funType->getReturnType();
niceprint("Function return type", type2string(retType, &retType));
niceprint("Canonical function return type",
type2string(retType.getCanonicalType(), &retType) +
" (" + type2char(retType.getCanonicalType(), &retType) + ")");
niceprint("Is sugared", funType->isSugared());
if (funType->isSugared()) {
clang::QualType qft{funType, 0};
niceprint("Desugared", type2string(funType->desugar(), &qft));
}
funTypeStr = type2char(retType.getCanonicalType(), &retType) + std::string("Fv");
valid = isTypeValid(retType.getCanonicalType(), &retType);
} else {
const clang::FunctionProtoType *funType = static_cast<const clang::FunctionProtoType*>(ddecl->getFunctionType());
const auto &retType = funType->getReturnType();
niceprint("Function return type", type2string(retType, &retType));
niceprint("Canonical function return type",
type2string(retType.getCanonicalType(), &retType)
+ " (" + type2char(retType.getCanonicalType(), &retType) + ")");
niceprint("Parameter count", funType->getNumParams());
for (const clang::QualType &type : funType->getParamTypes()) {
niceprint(" " + type2string(type, &type),
type2string(type.getCanonicalType(), &type) + " (" + type2char(type.getCanonicalType(), &type) + ")");
}
niceprint("Variadic function", funType->isVariadic() ? "yes" : "no");
funTypeStr =
type2char(retType.getCanonicalType(), &retType) +
((funType->getNumParams() == 0)
? std::string("Fv") : std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), std::string("F"),
[](const std::string &acc, const clang::QualType &qual){ return acc + type2char(qual.getCanonicalType(), &qual); }));
if (funType->isVariadic()) funTypeStr += "V";
valid = !funType->isVariadic() &&
std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), isTypeValid(retType.getCanonicalType(), &retType),
[](bool acc, const clang::QualType &qual){ return acc && isTypeValid(qual.getCanonicalType(), &qual); });
}
niceprint("Conclusion", "");
niceprint("Function final name", funName);
niceprint("Function type", funTypeStr);
niceprint("Valid function type", valid ? "yes" : "no");
std::cout << "\n";
funMap[funName] = std::make_pair(funTypeStr, valid);
funList.push_back(funName);
}
return true;
}
};
class Consumer : public clang::ASTConsumer {
public:
Visitor visitor;
Consumer(clang::CompilerInstance &ci) : visitor(ci) {
}
void HandleTranslationUnit(clang::ASTContext &context) override {
visitor.TraverseDecl(context.getTranslationUnitDecl());
}
};
class Action : public clang::ASTFrontendAction {
public:
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef inFile) override {
return std::make_unique<Consumer>(ci);
}
};
int main(int argc, const char **argv) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " (filenames) -- [-I...]" << std::endl;
return 2;
}
/*int fakeargc = argc + 1;
const char **fakeargv = new const char*[fakeargc];
memcpy(fakeargv, argv, argc * sizeof(char*));
fakeargv[fakeargc - 1] = "--";*/
llvm::cl::OptionCategory opcat{""};
clang::tooling::CommonOptionsParser op{argc, argv, opcat};
std::vector<std::string> paths; for (int i = 1; i < argc; ++i) paths.push_back(argv[i]);
clang::tooling::ClangTool tool{op.getCompilations(), paths};
tool.run(clang::tooling::newFrontendActionFactory<Action>().get());
std::cout << "Done, outputing output.h" << std::endl;
std::sort(funList.begin(), funList.end());
std::fstream file{"output.h", std::ios_base::out};
for (const std::string &funName : funList) {
if (!funMap[funName].second) {
file << "//";
}
file << "GO(" << funName << ", " << funMap[funName].first << ")\n";
}
return 0;
}
+267
View File
@@ -0,0 +1,267 @@
#include <string>
#define ALL START() \
/* libc */ \
STRUCT("_IO_FILE", "a FILE") \
STRUCT("_G_fpos_t", "a file position") \
STRUCT("sockaddr", "a socket address") \
STRUCT("itimerspec", "an itimerspec") \
STRUCT("timespec", "a timespec") \
STRUCT("itimerval", "an itimerval") \
STRUCT("timeval", "a timeval") \
STRUCT("timex", "a timex") \
STRUCT("timezone", "a timezone") \
STRUCT("dirent", "a dirent") \
STRUCT("dirent64", "a dirent64") \
STRUCT("__dirstream", "a dir stream") \
STRUCT("tm", "a time structure (tm)") \
STRUCT("cmsghdr", "a cmsghdr") \
STRUCT("msghdr", "a msghdr") \
STRUCT("rpcent", "an rpcent") \
STRUCT("random_data", "a random_data structure") \
STRUCT("drand48_data", "a drand48_data structure") \
STRUCT("termios", "a termios") \
STRUCT("iovec", "an iovec") \
STRUCT("file_handle", "a file handle") \
STRUCT("lconv", "an lconv") \
STRUCT("__locale_struct", "a locale structure") \
STRUCT("aliasent", "an alias") \
STRUCT("fstab", "an fstab") \
STRUCT("group", "a group") \
STRUCT("hostent", "a hostent") \
STRUCT("protoent", "a protoent") \
STRUCT("passwd", "a password") \
STRUCT("spwd", "an spwd") \
STRUCT("ttyent", "a ttyent") \
STRUCT("utmp", "an utmp structure") \
STRUCT("utmpx", "an utmpx structure") \
STRUCT("ifaddrs", "an ifaddrs structure") \
STRUCT("statfs", "a statfs structure") \
STRUCT("statfs64", "a statfs64 structure") \
STRUCT("statvfs", "a statvfs structure") \
STRUCT("statvfs64", "a statvfs64 structure") \
STRUCT("timeb", "a timeb structure") \
STRUCT("_ftsent", "an _ftsent structure") \
STRUCT("sysinfo", "a sysinfo structure") \
STRUCT("rlimit", "an rlimit structure") \
STRUCT("rlimit64", "an rlimit64 structure") \
STRUCT("rusage", "an rusage structure") \
STRUCT("entry", "an entry structure") \
STRUCT("pollfd", "a pollfd structure") \
STRUCT("re_pattern_buffer", "a re_pattern_buffer structure") \
STRUCT("sembuf", "a sembuf structure") \
STRUCT("tms", "a tms structure") \
STRUCT("utsname", "an utsname structure") \
STRUCT("utimbuf", "an utimbuf structure") \
STRUCT2("__va_list_tag", "__va_list_tag (aka, a va_list)", 'A') \
/* ncurses */ \
STRUCT("_win_st", "a _win_st structure") \
STRUCT("MEVENT", "an MEVENT structure") \
TYPEDEF("cchar_t", "a cchar_t") \
/* zlib */ \
STRUCT("gz_header_s", "a gz_header_s structure") \
STRUCT("gzFile_s", "a gzFile_s structure") \
STRUCT("z_stream_s", "a z_stream_s structure") \
\
END()
#define START()
#define STRUCT(s, ret) if (str == s) { return 'p'; } else
#define STRUCT2(s, ret, c) if (str == s) { return c; } else
#define TYPEDEF(s, ret) if (str == s) { return 'p'; } else
#define END() { return 0; }
char ptr2char(const std::string &str) {
/*if ((str == "_IO_FILE")
|| (str == "_G_fpos_t")
|| (str == "sockaddr")
|| (str == "itimerspec")
|| (str == "timespec")
|| (str == "itimerval")
|| (str == "timeval")
|| (str == "timex")
|| (str == "timezone")
|| (str == "dirent")
|| (str == "dirent64")
|| (str == "__dirstream")
|| (str == "tm")
|| (str == "cmsghdr")
|| (str == "msghdr")
|| (str == "rpcent")
|| (str == "random_data")
|| (str == "drand48_data")
|| (str == "termios")
|| (str == "iovec")
|| (str == "file_handle")
|| (str == "lconv")
|| (str == "__locale_struct")
|| (str == "aliasent")
|| (str == "fstab")
|| (str == "group")
|| (str == "hostent")
|| (str == "protoent")
|| (str == "passwd")
|| (str == "spwd")
|| (str == "ttyent")
|| (str == "utmp")
|| (str == "utmpx")
|| (str == "ifaddrs")
|| (str == "statfs")
|| (str == "statfs64")
|| (str == "statvfs")
|| (str == "timeb")
|| (str == "_ftsent")
|| (str == "sysinfo")
|| (str == "rlimit")
|| (str == "rlimit64")
|| (str == "rusage")
|| (str == "entry")
|| (str == "pollfd")
|| (str == "re_pattern_buffer")
|| (str == "sembuf")
|| (str == "tms")
|| (str == "utsname")
|| (str == "utimbuf")
// ncurses
|| (str == "_win_st")
|| (str == "cchar_t")
) {
// FILE*, fpos_t*, ...
return 'p';
} else if (str == "__va_list_tag") {
return 'A';
} else {
return 0;
}*/
ALL
}
#undef END
#undef TYPEDEF
#undef STRUCT2
#undef STRUCT
#undef START
#define START()
#define STRUCT(s, ret) if (str == s) { return ret; } else
#define STRUCT2(s, ret, c) if (str == s) { return ret; } else
#define TYPEDEF(s, ret) if (str == s) { return ret; } else
#define END() return "";
const char *ptr2str(const std::string &str) {
/*if (str == "_IO_FILE") {
return "a FILE";
} else if (str == "_G_fpos_t") {
return "a file position";
} else if (str == "sockaddr") {
return "a socket address";
} else if (str == "itimerspec") {
return "an itimerspec";
} else if (str == "timespec") {
return "a timespec";
} else if (str == "itimerval") {
return "an itimerval";
} else if (str == "timeval") {
return "a timeval";
} else if (str == "timex") {
return "a timex";
} else if (str == "timezone") {
return "a timezone";
} else if (str == "dirent") {
return "a dirent";
} else if (str == "dirent64") {
return "a dirent64";
} else if (str == "__dirstream") {
return "a dir stream";
} else if (str == "tm") {
return "a time structure (tm)";
} else if (str == "cmsghdr") {
return "a cmsghdr";
} else if (str == "msghdr") {
return "a msghdr";
} else if (str == "rpcent") {
return "an rpcent";
} else if (str == "random_data") {
return "a random_data structure";
} else if (str == "drand48_data") {
return "a drand48_data structure";
} else if (str == "termios") {
return "a termios";
} else if (str == "iovec") {
return "an iovec";
} else if (str == "file_handle") {
return "a file handle";
} else if (str == "lconv") {
return "an lconv";
} else if (str == "__locale_struct") {
return "a locale structure";
} else if (str == "aliasent") {
return "an alias";
} else if (str == "fstab") {
return "an fstab";
} else if (str == "group") {
return "a group";
} else if (str == "hostent") {
return "a hostent";
} else if (str == "protoent") {
return "a protoent";
} else if (str == "passwd") {
return "a password";
} else if (str == "spwd") {
return "an spwd";
} else if (str == "ttyent") {
return "a ttyent";
} else if (str == "utmp") {
return "an utmp structure";
} else if (str == "utmpx") {
return "an utmpx structure";
} else if (str == "ifaddrs") {
return "an ifaddrs structure";
} else if (str == "statfs") {
return "a statfs structure";
} else if (str == "statfs64") {
return "a statfs64 structure";
} else if (str == "statvfs") {
return "a statvfs structure";
} else if (str == "statvfs64") {
return "a statvfs64 structure";
} else if (str == "timeb") {
return "a timeb structure";
} else if (str == "_ftsent") {
return "an _ftsent structure";
} else if (str == "sysinfo") {
return "a sysinfo structure";
} else if (str == "rlimit") {
return "an rlimit structure";
} else if (str == "rlimit64") {
return "an rlimit64 structure";
} else if (str == "rusage") {
return "an rusage structure";
} else if (str == "entry") {
return "an entry structure";
} else if (str == "pollfd") {
return "a pollfd structure";
} else if (str == "re_pattern_buffer") {
return "a re_pattern_buffer structure";
} else if (str == "sembuf") {
return "a sembuf structure";
} else if (str == "tms") {
return "a tms structure";
} else if (str == "utsname") {
return "an utsname structure";
} else if (str == "utimbuf") {
return "an utimbuf structure";
} else if (str == "__va_list_tag") {
return "__va_list_tag (aka, a va_list)";
// ncurses
} else if (str == "_win_st") {
return "a _win_st structure";
} else if (str == "cchar_t") {
return "a cchar_t";
} else return "";*/
ALL
}
#undef END
#undef TYPEDEF
#undef STRUCT2
#undef STRUCT
#undef START
-109
View File
@@ -1,109 +0,0 @@
![Official logo](docs/img/Box64Logo.png "Official Logo")
# Box64: Linux Userspace x86-64 Emulator with a Twist
[Changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
![Build Status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main) ![Stars](https://img.shields.io/github/stars/ptitSeb/box64) ![Forks](https://img.shields.io/github/forks/ptitSeb/box64) ![Contributors](https://img.shields.io/github/contributors/ptitSeb/box64) ![Pull Requests](https://img.shields.io/github/issues-pr/ptitSeb/box64) ![Issues](https://img.shields.io/github/issues/ptitSeb/box64)
---
Box64 enables running x86_64 Linux programs, including games, on non-x86_64 Linux systems such as Arm (64-bit little-endian host system required).
Check out Box64 in action on YouTube:
- [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
- [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
- [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
Box64 leverages native system libraries (libc, libm, SDL, OpenGL), offering ease of integration and surprising performance in many applications. For performance benchmarks, check [this analysis](https://box86.org/index.php/2021/06/game-performances/).
With DynaRec for ARM64, RV64 and LA64 platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](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/).
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
_Logo and icon by @grayduck - Thank you!_
---
## 📖 Usage
Box64 offers environment variables to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
---
## 🚀 Compiling and Installation
- [Compilation Instructions](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
- [Bundle x86 Libraries](https://github.com/ptitSeb/box64/blob/main/docs/BUNDLE-X86-LIBS.md)
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
---
## 🔄 Version History
See the [Changelog](docs/CHANGELOG.md) for version updates.
---
## 🖥️ Platform Compatibility Notes
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86.
**Notes**
1. Box32 mode is in the making, which aims to support 32-bit binaries on Box64, you can enable it at build time, but do not expect everything to work. There is actually a few things that work, many that don't. It's a known issue, no need to create tickets about it for now.
2. Some installers may default to x86 on 64-bit host OSes, causing compatibility issues. Workaround: Use a fake `uname` that returns "x86_64" for `-m`.
---
## ⚙️ Configuration
Box64 has configuration files located in `/etc/box64.box64rc` and `~/.box64rc`, both formatted as `.ini` files. If you don’t want to use the default `/etc/box64.box64rc` file, copy it to `~/.box64rc` to ensure compatibility.
Settings priority: `~/.box64rc` > `/etc/box64.box64rc` > Command line.
---
## 📄 Additional Platform-Specific Notes
### Unity Game Emulation
- Many Unity games require OpenGL 3+, which may be challenging on ARM/RISC-V SBCs.
- **Tip for Pi4 and Pi5 Users**: Set `MESA_GL_VERSION_OVERRIDE=3.2` with `BOX64_DYNAREC_STRONGMEM=1` to prevent freezes and enable strong memory mode.
- **Using Panfrost**: For better compatibility on ARM, enable `PAN_MESA_DEBUG=gl3` to force higher OpenGL profiles. This can help if a game starts but quits unexpectedly before showing any content.
### GTK Programs
Box64 wraps GTK libraries, supporting both gtk2 and gtk3.
### Steam
Steam requires Box86 due to its 32-bit client app, but uses 64-bit local server binaries. Systems with less than 6GB RAM may need a swap file for optimal performance.
### Wine
Box64 supports Wine64 and Proton. For 32-bit components, Box86 is required. Systems with both Box64 and Box86 can run 32- and 64-bit Windows programs.
**Note**: You can use Wine WOW64 build to run x86 Windows programs in Box64-only environments, this is still experimental, but it works in most cases.
### Vulkan
Box64 wraps Vulkan libraries.
----
Final word
----
I want to thank everyone who has contributed to box64 development.
There are many ways to contribute: code contribution, financial, hardware and advertisement!
So, in no particular order, I want to thank:
* For their major code contribution: rajdakin, mogery, ksco, xctan
* For their major financial contribution: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* For their continuous advertisements for the box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
And I also thank the many other people who participated even once in this project.
(If you use Box64 in your project, please don't forget to mention it!)
-108
View File
@@ -1,108 +0,0 @@
![图标](docs/img/Box64Logo.png "图标")
# Box64:Linux 用户空间 x86-64 模拟器(支持原生库)
[更新日志](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
![Build Status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main) ![Stars](https://img.shields.io/github/stars/ptitSeb/box64) ![Forks](https://img.shields.io/github/forks/ptitSeb/box64) ![Contributors](https://img.shields.io/github/contributors/ptitSeb/box64) ![Pull Requests](https://img.shields.io/github/issues-pr/ptitSeb/box64) ![Issues](https://img.shields.io/github/issues/ptitSeb/box64)
---
Box64 可以在非 x86_64 Linux 主机系统(比如 Arm)上运行 x86_64 Linux 程序(比如游戏),目前仅支持 64 位小端主机系统。
在 YouTube 上查看 Box64 的运行效果:
- [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
- [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
- [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
Box64 可以使用本机原生的系统库(libc、libm、SDL、OpenGL),有着易于集成的特性和令人惊讶的性能。如需性能基准测试,请查看[此分析](https://box86.org/index.php/2021/06/game-performances/)。
借助适用于 ARM64,RV64 以及 LA64 平台的 DynaRec,Box64 的速度比单独使用解释器快 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/)。
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
_Logo 由 @grayduck 制作,感谢!_
---
## 📖 使用方法
Box64 提供了环境变量来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
---
## 🚀 编译和安装
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
---
## 🔄 版本历史
请参阅[变更日志](docs/CHANGELOG.md)了解版本更新说明。
---
## 🖥️ 平台兼容性说明
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文​​件,请使用 Box86。
**注意事项**
1. Box32 模式正在制作中,旨在支持 Box64 上运行 32 位二进制文​​件,敬请期待!
2. 某些安装程序可能会将 64 位的主机操作系统判定为 x86 导致兼容性问题。解决方法:使用假的 `uname` ,并使它在运行参数为 `-m` 时返回 `x86_64`。
---
## ⚙️ 配置
Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini` 格式的文件。如果您不想使用默认的 `/etc/box64.box64rc` 文件,请将其复制到 `~/.box64rc` 以确保兼容性。
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
---
## 📄 特定平台的其他说明
### Unity 游戏
- 许多 Unity 游戏需要 OpenGL 3+,这对 ARM/RISC-V SBC 来说可能具有挑战性。
- **对 Pi4 和 Pi5 用户的提示**:设置 `MESA_GL_VERSION_OVERRIDE=3.2` 和 `BOX64_DYNAREC_STRONGMEM=1` 以防止卡死并启用强内存模式。
- **Panfrost**:为了在 ARM 上实现更好的兼容性,启用 `PAN_MESA_DEBUG=gl3` 以强制更高的 OpenGL Profile。如果游戏可以启动但在显示任何内容之前意外退出,这个设置可能会有所帮助。
### GTK 程序
Box64 包装了 GTK 库,支持 gtk2 和 gtk3。
### Steam
由于 Steam 客户端应用是 32 位的,需要使用 Box86,但其本地服务器是 64 位的二进制文件。对于内存少于 6GB 的系统,可能需要使用交换文件以获得最佳性能。
### Wine
Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box64 和 Box86 的系统可以运行 32 位和 64 位的 Windows 程序。
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
### Vulkan
Box64 包装了 Vulkan 库。
----
结语
----
我要感谢所有为 box64 开发做出贡献的人。
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
以下感谢不分先后:
* 代码贡献:rajdakin, mogery, ksco, xctan
* 财务支持:[Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
* 硬件捐赠和 LoongArch 迁移:[xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
* 硬件捐赠:[ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
我还要感谢很多人,即使他们只参与了一次本项目。
(如果你的项目中使用了Box64,请不要忘记提及!)
-117
View File
@@ -1,117 +0,0 @@
![Official logo](docs/img/Box64Logo.png "Official Logo")
Емулятор простіра користувача x86_64 із родзинкою
[Дивитись журнал змін](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Повідомити про помилку](https://github.com/ptitSeb/box64/issues/new)
![build](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main) ![stars](https://img.shields.io/github/stars/ptitSeb/box64) ![forks](https://img.shields.io/github/forks/ptitSeb/box64) ![contributors](https://img.shields.io/github/contributors/ptitSeb/box64) ![prs](https://img.shields.io/github/issues-pr/ptitSeb/box64) ![issues](https://img.shields.io/github/issues/ptitSeb/box64)
----
Box64 дозволяє запускати x86_64 Linux програми (наприклад, ігри) на системах Linux відмінних від x86_64, наприклад ARM (хост-система має мати 64-розрядний порядок редагування).
Ви можете знайти багато відео про Box64 в YouTube каналах [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) або [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
Оскільки Box64 використовує рідні версії деяких «системних» бібліотек, таких як libc, libm, SDL і OpenGL, його легко інтегрувати та використовувати з більшістю програм, а продуктивність у багатьох випадках може бути напрочуд високою. Подивіться на цей стендовий аналіз для прикладу [тут](https://box86.org/index.php/2021/06/game-performances/).
Box64 інтегрується з DynaRec (динамічний рекомпілятор) для платформ ARM64 і RV64 забезпечуючи підвищення швидкості в 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/).
Деякі внутрішні коди операцій x64 використовують частини «Бібліотеки емулятора Realmode X86», дивіться [x64primop.c](src/emu/x64primop.c) для детальної інформації про авторські права.
<img src="docs/img/Box64Icon.png" width="96" height="96">
Логотип і піктограма зроблені @grayduck, дякую!
----
Використання
----
Є кілька змінних середовища для керування поведінкою Box64.
Дивіться [тут](docs/USAGE.md) для перегляду всіх змінних середовища та того, що вони роблять.
Примітка: Dynarec від Box64 використовує механізм із захистом пам’яті та обробником сигналу помилки сегментів для обробки JIT коду. Простіше кажучи, якщо ви хочете використовувати GDB для налагодження запущеної програми, яка використовує JIT-код (наприклад, mono/Unity3D), ви все одно матимете багато «звичайних» помилок сегментів. Пропонується використовувати щось на зразок `handle SIGSEGV nostop` в GDB, щоб не зупинятися на кожній помилці сегмента, і, можливо, поставити точку зупину всередині `my_memprotectionhandler` в `signals.c`, якщо ви хочете перехопити помилки сегментів.
----
Компіляція/Встановлення
----
> Інструкцію зі складання Box64 можна знайти [тут](docs/COMPILE.md).\
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/X64WINE.md).
----
Історія версій/Журнал змін
----
Історія версій доступна [тут](docs/CHANGELOG.md).
----
Примітки щодо 32 бітних платформ
----
Оскільки Box64 працює шляхом прямого перекладу викликів функцій з x86_64 на хост-систему, хост-система (та, на якій працює Box64) повинна мати 64-розрядні бібліотеки. Box64 не містить 64-біт <-> 32-біт перекладу.
Також розумійте що Box64 запускатиме лише 64-розрядні двійкові Linux файли. Для 32-розрядних двійкових файлів вам потрібен Box86 (з усіма хитрощами з мультиархітектурною системою або корінними правами). Зауважте, що багато інсталяторів (на основі mojo) повертаються до "x86" при виявленні ОС ARM64, і тому намагатимуться використовувати Box86 для налаштування, навіть якщо існує версія x86_64. Ви можете зламати свій шлях за допомогою фальшивого "uname", який повертає "x86_64", коли аргумент "-m"
----
Примітки щодо конфігурації Box64
----
Обидва файли мають однаковий синтаксис і в основному є файлами ini. Розділ у квадратних дужках визначає назву процесу, а решта — встановлють змінну середовища. Подивіться [використання](USAGE.md), щоб дізнатися, які параметри можна завдати. Box64 поставляється з файлом за замовчуванням, який слід встановити для кращої стабільності. Файл знаходиться в `system/box64.box64rc` і має бути встановлен в `/etc/box64.box64rc`. Якщо з певних причин ви не хочете встановлювати цей файл у `/etc`, принаймні скопіюйте його в `~/.box64rc` або гра може не працювати належним чином. Зауважте, що пріоритетом є: `~/.bashrc` > `/etc/box64.box64rc` > командний рядок
Таким чином, ваші налаштування в `~/.bashrc` можуть замінити налаштування з вашого командного рядка...
----
Примітки щодо емуляції ігор Unity
----
Запуск ігор Unity має працювати, але ви також повинні зауважити, що для багатьох ігор Unity3D потрібен OpenGL 3+, який може бути складно забезпечити на ARM SBC (одноплатних комп’ютерах). Крім того, багато нових ігор Unity3D (наприклад, KSP) використовують стиснуті текстури BC7, які не підтримуються багатьма інтегрованими GPU ARM.
Підказка: на Pi4 і Pi5 використовуйте `MESA_GL_VERSION_OVERRIDE=3.2` з `BOX64_DYNAREC_STRONGMEM=1`, щоб запобігти зависанням і ввімкнути режим сильної пам’яті, і використовуйте Panfrost `PAN_MESA_DEBUG=gl3`, щоб використовувати вищий профіль, якщо гра починається, а потім завершується, перш ніж щось показати.
----
Примітки щодо програм GTK
----
Бібліотеки GTK2 і GTK3 тепер використовуються в Box64.
----
Примітки щодо Steam
----
Зауважте, що Steam є гібридом 32-біт / 64-біт. Вам ПОТРІБЕН box86, щоб запустити Steam, оскільки клієнта є 32-розрядною двійковою програмою. Він також використовує 64-розрядні двійкові файли локального сервера, і цей процес steamwebhelper тепер є обов’язковим навіть у «малому режимі». І цей процес з’їсть багато оперативної пам’яті, таким чином машині з 6 Гб оперативної пам’яті знадобиться файл підкачки для використання Steam.
----
Примітки щодо Wine
----
Wine64 підтримується Box64, Proton теж. Майте на увазі, що 64-розрядний Wine також містить 32-розрядні компоненти щоб мати можливість запускати 32-розрядні програми Windows. Для 32-розрядних програм потрібен Box86, і вони не працюватимуть без нього. У системі, де присутні і працюють Box64, і Box86, 64-розрядне встановлення Wine може запускати як 32-розрядні, так і 64-розрядні програми Windows (просто використовуйте `wine` і `wine64` відповідно).
Зауважте, що новий 32-бітний PE в 64-бітному процесі, який Wine зараз реалізує у Wine 7+ тепер підтримується, але підтримка є досить молодою тому можуть виникнути деякі проблеми.
----
Примітки щодо Vulkan
----
Box64 використовує бібліотеки Vulkan, але зауважте що він тестувався з картою AMD Radeon RX550 і драйвером Freedreno, тому деякі розширення можуть бути відсутні залежно від вашої відеокарти.
----
Останнє слово
----
Я хочу подякувати всім, хто зробив внесок у розвиток box64.
Є багато способів зробити внесок: внесок коду, фінансовий внесок, апаратне забезпечення та реклама!
Отже, без особливого порядку, я хочу подякувати:
* За основний внесок у код: rajdakin, mogery, ksco, xctan
* За великий фінансовий внесок: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
* За внесок у апаратне забезпечення: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
* За безперервну рекламу Box64: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/Команда [TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
(Якщо ви використовуєте Box64 у своєму проекті, будь ласка, не забудьте згадати про це!)
-38
View File
@@ -1,38 +0,0 @@
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm,686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm,9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm,d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm,13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm,fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm,e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm,9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm,abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm,0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
1 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
2 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm 49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
3 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm 75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
4 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
5 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
6 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
7 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm 64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
8 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm 16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
9 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
10 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb 625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
11 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm 686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
12 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm 9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
13 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
14 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
15 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm 4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
16 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
17 https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg 5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
18 https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
19 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm 9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
20 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm 83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
21 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm 66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
22 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
23 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
24 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
25 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm 9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
26 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm 2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
27 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm 2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
28 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm 25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
29 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm 792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
30 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
31 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
32 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm 3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
33 https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm 13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
34 https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
35 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
36 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm 9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
37 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
38 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm 0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
-93
View File
@@ -1,93 +0,0 @@
#!/bin/bash
set -x
extract_pkg_auto() {
# Example x86_64 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb
# Example x86 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb
if echo "${1}" | grep -q -P ".deb$"; then
echo "DEB (Debian) package detected."
ar x "$(basename "${1}")"
tar --extract --file data.tar*
# Example x86_64 package name: curl-gnutls-8.1.2-44-1-x86_64.eopkg
# Example x86 package name: curl-gnutls-32bit-8.1.2-44-1-x86_64.eopkg
elif echo "${1}" | grep -q -P ".eopkg$"; then
echo "EOPKG (Solus Linux) package detected."
unzip -o "$(basename "${1}")"
tar --extract --file install.tar.xz
# Example x86_64 package name: bluez-libs-5.63-1.el8.x86_64.rpm
# Example x86 package name: bluez-libs-5.63-1.el8.i686.rpm
elif echo "${1}" | grep -q -P ".rpm$"; then
echo "RPM (Fedora) detected."
rpm2cpio "$(basename "${1}")" | cpio -idmv
# Example x86_64 package name: libjpeg-turbo-3.0.1_1.x86_64.xbps
# Example x86 package name: libjpeg-turbo-32bit-3.0.1_1.x86_64.xbps
elif echo "${1}" | grep -q -P ".xbps$"; then
echo "XBPS (Void Linux) package detected."
tar --extract --file "$(basename "${1}")"
else
echo "Unknown package."
echo "Unsupported package type."
exit 1
fi
}
box64_dir=$(pwd)
dir_tmp_local="$(mktemp --directory)"
cd "${dir_tmp_local}"
for line in $(cat "${box64_dir}/box64-bundle-x86-libs.csv");
do pkg_url="$(echo "${line}" | cut -d, -f1)"
pkg_checksum_expected="$(echo "${line}" | cut -d, -f2)"
pkg_name="$(basename "${pkg_url}")"
curl --silent --location --remote-name "${pkg_url}"
pkg_checksum_actual="$(sha256sum ${pkg_name} | awk '{print $1}')"
if [[ "${pkg_checksum_expected}" -ne "${pkg_checksum_actual}" ]];
then echo "Invalid checksum for ${pkg_name}"
echo "Expected: ${pkg_checksum_expected}"
echo "Actual: ${pkg_checksum_actual}"
exit 1
fi
extract_pkg_auto "${pkg_name}"
done
# Start preperation of bundles.
mkdir -p \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu" \
"${dir_tmp_local}/bundle-pkgs" \
# Copy Debian family libraries.
cp --archive "${dir_tmp_local}"/usr/lib/i386-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
cp --archive "${dir_tmp_local}"/usr/lib/x86_64-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
# Copy Fedora family libraries.
cp --archive "${dir_tmp_local}"/usr/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
cp --archive "${dir_tmp_local}"/usr/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
# Copy Solus and Void Linux family libraries.
cp --archive "${dir_tmp_local}"/usr/lib32/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
# Create "<LIBRARY_FILE>.so" symlinks.
for dir_lib in \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
# If two or more libraries of the same name exist, this will symlink the oldest version.
# Pipe this into a reverse sort `| sort -r` to symlink the newest version.
do for lib in $(ls -1 "${dir_lib}")
# Example output: libbluetooth.so
do lib_base="$(echo "${lib}" | cut -d. -f1,2)"
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null
then ln -s "${lib}" "${dir_lib}/${lib_base}"
fi
done
done
mv "${dir_tmp_local}"/*.deb "${dir_tmp_local}/bundle-pkgs/"
mv "${dir_tmp_local}"/*.eopkg "${dir_tmp_local}/bundle-pkgs/"
mv "${dir_tmp_local}"/*.rpm "${dir_tmp_local}/bundle-pkgs/"
tar --directory "${dir_tmp_local}/bundle-libs" --create --file "${box64_dir}/box64-bundle-x86-libs.tar.gz" .
tar --directory "${dir_tmp_local}/bundle-pkgs" --create --file "${box64_dir}/box64-bundle-x86-pkgs.tar.gz" .
# Clean up.
cd -
rm -r -f "${dir_tmp_local}"
-248
View File
@@ -1,248 +0,0 @@
box64 (0.3.4) unstable; urgency=low
* This version is Faster and more compatible
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
* => On ARM64, Box64 now support more DRM types than before.
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
* Please check CHAGELOG.md for more details
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
box64 (0.3.2) unstable; urgency=low
* Introduced Box32 to run 32bits apps on 64bits OS
* => Box32 is a build option for Box64, and is disabled by default
* => Optionnal binfmt integration available for Box32
* => Wrapped some basics libs, including graphics and sounds so a few games already works
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
* => Available on the 3 Dynarec backend, with different implementations
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* +> Can lead to large speedup on certain cases
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
* Some bugfix and improvment in the Signal handler and internal memory tracking
* Improvment to TRAP signal generation and Handling
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
* Improved some x87 operations, like long double handling and infinity comparisons...
* Dynarec: ARM64 fixes to a few opcodes
* Dynarec: RV64 fixes to many opcodes
* Dynarec: LA64 fixes to a few opcodes
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
* ElfLoader: Improved object fetching
* New build profile for SD865 and ORYON
* Changed the installation folder of x86 libs to avoid conflict with linux distro
* Added a few syscalls
* Some more Vulkan extensions wrapped
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
box64 (0.3.0) unstable; urgency=low
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
* Dynarec: ARM64 some fixes to a few opcodes
* Dynarec: LA64 many new opcodes added, and fixes.
* Dynarec: RV64 some new opcodes added, many fixes.
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
* Dynarec: RV64 improved LOCK CMPXCHG handling
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
* ElfLoader: Added a new type of relocation
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
box64 (0.2.8) unstable; urgency=low
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
* Reworked X11 Callback handling, for better stability
* Reworked exit and the load/unload of libs and symbol resolution
* Some more profiles in box64rc
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
* => should improve games stability
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
* Dynarec: RV64 lots of opcoded added.
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
* Dynarec: Better handling of large block in the dynarec
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
box64 (0.2.6) unstable; urgency=low
* X64Libs: Updated libstdc++ & libgcc_s
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
* Dynarec: More opcodes on ARM64 & RV64
* Dynarec: Fixed some flags propagation issues inside blocks
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
* Dynarec: RV64: Many fixes, making Wow64 apps running
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
* CPU: Added full support for SSE4.2
* CPU: Added full support for SHA extension
* ElfLoader: rework how elf memory is handled
* Emulation: Added some more syscalls
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
* Wrapping: Removed faked libunwind wrapping
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
* OS: Added profile to build for Android and Termux.
* OS: New option to use mold for a high speed link
* => More hadware support, more functions wrapped for an improve compatibity
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
* => Some work also to reduce the memory footprint
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
box64 (0.2.4) unstable; urgency=low
* Added Dynarec for RISC-V
* Added partial 32 bits support (WoW64 works)
* Changed cpuid to display box64
* Fixed steam, again
* Improved hacked version for overridden malloc/free functions
* More wrapped libs
* More wrapped functions and syscalls
* Reduced memory footprint
* Added support for the BIND_NOW flags in ELF files
* Added RTLD_NOLOAD support
* Fixed some typos and general cleanup, again
* Added a cosimulation mode (to compare the behaviour of the dynarec with the interpreter)
* Added FASTNAN/FASTROUND handling for more opcodes
* Better float/double/long double handling
* Better dlopen/dlclose handling
* More games in the rc file
* Added BOX64_DYNAREC_MISSING to show only missing opcode, independantly of the log level
* Added BOX64_RESERVE_HIGH to reserve addresses above 47bits
* Improved multitreading support
* Ukrainian translation of the README
* => Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
* => Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
box64 (0.2.2) unstable; urgency=low
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
* Improved memory protection tracking and signal handling, again
* Simplified mutex handling (faster, cleaner)
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
* Added d3dadaptor9 wrapping
* More wrapped libs (especially on the gtk familly)
* Improved/fixed some Syscall handling
* Refactored Strong Memory Model emulation (faster and more accurate)
* Added some more opcode to ARM64 Dynarec, and fixed some other
* Some fixes to flags handling in the Dynarec on some special cases
* Refactor library loading/unloading, with refcount.
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
* Improved mmap mapping, espcially with MAP_32BITS flag
* More wrapped functions and syscalls
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
* More support on the RV64 port
* More support to build under musl environment
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
box64 (0.2.0) unstable; urgency=low
* Wrapped more vulkan function, dxvk 2.0 now works
* Added support for overridden malloc/free functions
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
* Improved elf loader
* Improved dlsym handling with RTLD_NEXT
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
* Added BOX64_ROLLING_LOG to have details log only on crash
* Work on alignment for some of pthread structures
* More wrapped libraries in the gtk family
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
* Improved TLS Size handling (Unity3D games now works)
* More PageSize Compile options
* Improved execv family of function to have better box64 integration
* Added support for wrapped libfuse so AppImage works
* Adjusted the binfmt integration so AppImage are automaticaly picked
* Improved FAudio, SDL2, GL (and more) wrapping
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
* Improved Signal Handling and memory protection traking
* Some signature fixes to some wrapped functions (in libc)
* Added more syscalls
* Added a lot of new opcodes to the ARM64 Dynarec
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
* Fix typos and arch type string by @archanox in #321
* Fix grammar by @Jai-JAP in #326
* Enable 64k page size by @martinmanyhats in #334
* Align address when call mprotect by @wannacu in #336
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
* add 18.04 tegra X1 github actions by @theofficialgman in #345
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
* Add SW64 base support by @wannacu in #382
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
* Create X64WINE.md by @WheezyE in #423
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
* Malloc override by @ptitSeb in #437
* Remove dynablocklist by @ptitSeb in #438
* Fix Pkgbuilds by @Jai-JAP in #452
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
box64 (0.1.8) unstable; urgency=low
* Added an option to get generated -NAN on SSE2 operation
* Many small fixes and improvement to get SteamPlay (i.e. proton) working (along with box86)
* Added some workaround for program calling uname to mimic x86_64 system
* Added some granularity to mmap, 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
* - make adding new architecture easier, by sharing as much infrastructure as possible
* Improved elfloader
* Improved some tests
* Improved a bit the "Hotpage" handling and messages
* Added more dynarec opcodes
* A few fixes in some Dynarec opcodes
* A bit more optimisation in some Dynarec opcodes
* Don't quit on unsupported syscall, return -1 / ENOSYS error
* Added some more Syscall
* Wrapped Vulkan library. Vulkan and dxvk now supported!
* Support building on PPC64LE (interpreter only)
* Added support for Risc-V (interpreter only)
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
-1
View File
@@ -1 +0,0 @@
11
-14
View File
@@ -1,14 +0,0 @@
Source: box64
Section: utils
Priority: optional
Maintainer: Ryan Fortner <[email protected]>
Build-Depends: cmake, debhelper (>=11~), python3
Standards-Version: 4.1.4
Homepage: https://github.com/ptitSeb/box64
Package: box64
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: Linux Userspace x86_64 Emulator with a twist, targeted at ARM Linux devices
Box86 lets you run x86_64 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 64bit little-endian).
-26
View File
@@ -1,26 +0,0 @@
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.
-1
View File
@@ -1 +0,0 @@
box64: no-manual-page
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DARM_DYNAREC=1 \
-DNOGIT=1
override_dh_shlibdeps:
dh_shlibdeps --exclude=libgcc_s.so.1 \
--exclude=libpng12.so.0 \
--exclude=libstdc++.so.5 \
--exclude=libstdc++.so.6 \
--exclude=libmbedcrypto.so.7 \
--exclude=libssl.so.1.1 \
--exclude=libunwind.so.8 \
--exclude=libmbedtls.so.14 \
--exclude=libcrypto.so.1.1 \
--exclude=libmbedx509.so.1 \
--exclude=libcrypto.so.1.0.0 \
--exclude=libssl.so.1.0.0 \
--exclude=box64-bash
-1
View File
@@ -1 +0,0 @@
3.0 (quilt)
-5
View File
@@ -1,5 +0,0 @@
Bug-Database: https://github.com/ptitSeb/box64/issues
Bug-Submit: https://github.com/ptitSeb/box64/issues/new
Repository: https://github.com/ptitSeb/box64.git
Repository-Browse: https://github.com/ptitSeb/box64
Security-Contact: [email protected]
-1
View File
@@ -1 +0,0 @@
version=3
-66
View File
@@ -1,66 +0,0 @@
# Bundling x86 Libraries
The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-bundle x86_64 and x86 libraries for use with Box64/Box32 and Box86. These libraries improve Box emulation. This bundle provides a much smaller size compared to using a full root file system of an operating system.
## Usage
### Administrator
Install required dependencies for the bundle script.
- Debian
```
sudo apt-get update
sudo apt-get install coreutils curl binutils rpm2cpio tar zstd
```
Run `box64-bundle-x86-libs.sh`. This will create two archives:
- `box64-bundle-x86-libs.tar.gz` = All of the extracted library files in the directory structure of `usr/lib/box64-i386-linux-gnu` and `usr/lib/box64-x86_64-linux-gnu`.
- `box64-bundle-x86-pkgs.tar.gz` = All of the Linux distribution packages used to extract the library files. This is only created for preservation purposes and is otherwise unused.
Extract the library archive. Box will automatically search these paths for library files to emulate.
```
sudo tar --extract --file box64-bundle-x86-libs.tar.gz --directory /
```
### Developer
Add new packages to the `box64-bundle-x86-libs.csv` file in the format of `<PACKAGE_URL>,<SHA256_CHECKSUM>`.
Supported packages:
- DEB (Debian)
- EOPKG (Solus)
- RPM (Fedora)
- XBPS (Void Linux)
Preference of operating system packages that provide a library:
1. RPMs from AlmaLinux 9 provide 10 years of updates.
2. DEBs from Debian 11 provide 5 years of updates.
3. EOPKG from Solus provide old variants of obscure 32-bit libraries.
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
5. Other (whereever a library is packaged)
For finding package names that contian a specific library file, use the [pkgs.org](https://pkgs.org/) website. Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
- DEB
- `apt-file <LIBRARY_FILE>`
- EOPKG
- Does not support file search. Use pkgs.org instead.
- RPM
- `dnf provides <LIBRARY_FILE>`
- XBPS
- `xbps-query --repository --ownedby <LIBRARY_FILE>`
Once the package name is found, find the exact URL for downloading it.
- DEB = Explore "main" and "contrib". Search for packages with the name "deb11" in it. Use the "amd64.deb" and "i386.deb" packages.
- https://archive.debian.org/debian/pool/
- EOPKG = Use the "`<VERSION>-<RELEASE>-x86_64.eopkg`" and "`32bit-<VERSION>-<RELEASE>-x86_64.eopkg`" packages.
- https://cdn.getsol.us/repo/shannon/
- RPM = Navigate to the "`<MAJOR>.<MINOR>`" version directory first. Then explore "AppStream" and "BaseOS". Use the "x86_64.rpm" and "i686.rpm" packages.
- https://repo.almalinux.org/almalinux/
- XBPS = There are too many files in the repository to display on a web browser. Use pkgs.org instead to find the exact URL for downloading it.
- https://repo-default.voidlinux.org/current/
Download the package and then find the checksum with the `sha256sum` command.
Major Linux distributions such as AlmaLinux and Debian provide archives of packages. Rolling distributions such as Arch Linux, Solus, and Void Linux do not. In those cases, use the [Internet Archive](https://web.archive.org/) to archive any rolling release package used by Box by using the "Save Page Now" feature. If the error "Save Page Now browser crashed" appears, it can be safely ignored. The archive will still have been saved.
+4 -258
View File
@@ -1,259 +1,5 @@
v0.3.4
Current Version
======
* This version is Faster and more compatible:
=> The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
=> On ARM64, Box64 now support more DRM types than before.
=> BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
* Added support to emulate Windows Syscall (needs Proton and a 48bits address space for now)
* Added BOX64_DYNAREC_DIRTY to have a faster (but less safe) way to handle code that write in it's current page
* Added a few rarely used opcodes
* Added experimental support for GDBJIT, that allow an x86/x86_64 program to be debugged on ARM/RV64/LA64 platform with x86 regs and opcode view (might generate a lot of file tho)
* Added support for Perf tools in a similar way if GDBJIT, to have an x86 fine view of the performances
* Reworked undefined flags for common operations, to be similar to real CPU
* Reworked cpuid handling, adding BOX64_CPUTYPE support to select Intel/AMD emulation (no 3DNow! support on AMD for now)
* Reworked ucontext link to be closer to the real thing (and make it more simple)
* Improved memory traking, file descriptor backed memory map, and detect wine loaded dll
* Introduced settings per library and dll (mostly for Dynarec)
* Wrapper: More functions addes, and some fixes too
* BOX32: Many fixes around pthreads wrapping
* BOX32: More functions wrapped.
* BOX32: More libraies wrapped.
* BOX32: Some reworks on how high memory (higher than 32bits) is masked, and can be used for Dynarec blocks.
* Dynarec: The usual batch of fixes, improvments and opcodes additions on all 3 supported backend
* Dynarec: Some fixes to NativeFlags handling, both on ARM64 and RV64
* Dynarec: Added optimized REP MOVSB (expected for default CPUTYPE=0, according to new cpuid return)
* Dynarec: LA64: more opcoded addes, using hardware extensions like AES
* Dynarec: RV64: More work on using RVV 1.0 and xTheadVector extension to emulate SSE/SSE2+ opcodes
* Dynarec: RV64: Added informations on flags when building blocks, to be used when a signal happens to rebuild a x86 context more accurate
* Dynarec: ARM64: Reworked undefined flags for common operations, to be similar to real CPU
* Dynarec: ARM64: Added informations on flags and xmm/ymm/x87 register when building blocks, to be used when a signal happens to rebuild a x86 context 100% accurate
* TRACE: Reworked how trace for wrapped function call is printed.
* TRACE: Reworked logs to prefix each line with a (optionaly colored) BOX32 or BOX64
* COSIM: Some rework on cosim to limit false negative, especialy when handling x87 operations
* LA64: Added limited support for ABI 1.0
* CI: github CI now also generate MiceWine .rat archive, along with Winlator .wcp archive and regular linux builds.
* RCFile: Added many new games profiles (both for speed improvment or for compatibilty)
v0.3.2
======
* Introduced Box32 to run 32bits apps on 64bits OS
=> Box32 is a build option for Box64, and is disabled by default
=> Optionnal binfmt integration available for Box32
=> Wrapped some basics libs, including graphics and sounds so a few games already works
=> Work In Progress, many issues remain to be fixed, but some Linux games are playable
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
=> Available on the 3 Dynarec backend, with different implementations
=> ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
+> Can lead to large speedup on certain cases
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
* Some bugfix and improvment in the Signal handler and internal memory tracking
* Improvment to TRAP signal generation and Handling
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
* Improved some x87 operations, like long double handling and infinity comparisons...
* Dynarec: ARM64 fixes to a few opcodes
* Dynarec: RV64 fixes to many opcodes
* Dynarec: LA64 fixes to a few opcodes
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
* ElfLoader: Improved object fetching
* New build profile for SD865 and ORYON
* Changed the installation folder of x86 libs to avoid conflict with linux distro
* Added a few syscalls
* Some more Vulkan extensions wrapped
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
v0.3.0
======
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
=> BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
=> BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
=> ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
* Dynarec: ARM64 some fixes to a few opcodes
* Dynarec: LA64 many new opcodes added, and fixes.
* Dynarec: RV64 some new opcodes added, many fixes.
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
* Dynarec: RV64 improved LOCK CMPXCHG handling
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
* ElfLoader: Added a new type of relocation
v0.2.8
======
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
* Reworked X11 Callback handling, for better stability
* Reworked exit and the load/unload of libs and symbol resolution
* Some more profiles in box64rc
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
=> Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
=> should improve games stability
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
* Dynarec: RV64 lots of opcoded added.
=> Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
=> Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
* Dynarec: Better handling of large block in the dynarec
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
=> It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
v0.2.6
======
* X64Libs: Updated libstdc++ & libgcc_s
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
* Dynarec: More opcodes on ARM64 & RV64
* Dynarec: Fixed some flags propagation issues inside blocks
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
* Dynarec: RV64: Many fixes, making Wow64 apps running
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
* CPU: Added full support for SSE4.2
* CPU: Added full support for SHA extension
* ElfLoader: rework how elf memory is handled
* Emulation: Added some more syscalls
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
* Wrapping: Removed faked libunwind wrapping
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
* OS: Added profile to build for Android and Termux.
* OS: New option to use mold for a high speed link
=> More hadware support, more functions wrapped for an improve compatibity
=> More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
=> Some work also to reduce the memory footprint
v0.2.4
======
* Added Dynarec for RISC-V
* Added partial 32 bits support (WoW64 works)
* Changed cpuid to display box64
* Fixed steam, again
* Improved hacked version for overridden malloc/free functions
* More wrapped libs
* More wrapped functions and syscalls
* Reduced memory footprint
* Added support for the BIND_NOW flags in ELF files
* Added RTLD_NOLOAD support
* Fixed some typos and general cleanup, again
* Added a cosimulation mode (to compare the behaviour of the dynarec with the interpreter)
* Added FASTNAN/FASTROUND handling for more opcodes
* Better float/double/long double handling
* Better dlopen/dlclose handling
* More games in the rc file
* Added BOX64_DYNAREC_MISSING to show only missing opcode, independantly of the log level
* Added BOX64_RESERVE_HIGH to reserve addresses above 47bits
* Improved multitreading support
* Ukrainian translation of the README
=> Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
=> Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
v0.2.2
======
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
=> Steam Large mode and new BigPicture are working
=> Heroic Launcher is working
* Added rcfile handling: box64 now read `/etc/box64.box64rc` and `~/.box64rc` and apply per process parameters
=> Every program can be finetuned, for speed or just to make them work
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
* Improved memory protection tracking and signal handling, again
* Box64 now return a custom name for the CPU instal of P4, build with Box64 and the cpu name it's running on
* Simplified mutex handling (faster, cleaner)
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
* Added d3dadapter9 wrapping
=> gallium nine is now supported on box64 too
* More wrapped libs (especially on the gtk familly)
* Improved/fixed some Syscall handling
* Refactored Strong Memory Model emulation (faster and more accurate)
* Added some more opcode to ARM64 Dynarec, and fixed some other
* Some fixes to flags handling in the Dynarec on some special cases
* Refactor library loading/unloading, with refcount.
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
* Improved mmap mapping, espcially with MAP_32BITS flag
* More wrapped functions and syscalls
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
* More support on the RV64 port
* More support to build under musl environment
v0.2.0
======
* Wrapped more vulkan function, dxvk 2.0 now works
* Added support for overridden malloc/free functions
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
* Improved elf loader
* Improved dlsym handling with RTLD_NEXT
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
* Added BOX64_ROLLING_LOG to have details log only on crash
* Work on alignment for some of pthread structures
* More wrapped libraries in the gtk family
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
* Improved TLS Size handling (Unity3D games now works)
* More PageSize Compile options
* Improved `execv` family of function to have better box64 integration
* Added support for wrapped libfuse so AppImage works
* Adjusted the binfmt integration so AppImage are automaticaly picked
* Improved FAudio, SDL2, GL (and more) wrapping
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
* Improved Signal Handling and memory protection traking
* Some signature fixes to some wrapped functions (in libc)
* Added more syscalls
* Added a lot of new opcodes to the ARM64 Dynarec
=> Lot's of new games stat working, to name a few: Surviving Mars, Piczle Cross Adventure (using Proton experimental), UT2004, Obduction, Machinarium, Silicon Zero, Hacknet, Absolute Drift, Art of Rally, Dota2
=> Some apps also runs now, like TeamSpeak 3 Client and Server or Discord
=> The bash integration is usefull for device with no binfmt integration or for script that check the machine it's running on
v0.1.8
======
* Added an option to get generated -NAN on SSE2 operation
* Many small fixes and improvement to get SteamPlay (i.e. proton) working (along with box86)
* Added some workaround for program calling uname to mimic x86_64 system
* Added some granularity to mmap, 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
* make adding new architecture easier, by sharing as much infrastructure as possible
* Improved elfloader
* Improved some tests
* Improved a bit the "Hotpage" handling and messages
* Added more dynarec opcodes
* A few fixes in some Dynarec opcodes
* A bit more optimisation in some Dynarec opcodes
* Don't quit on unsupported syscall, return -1 / ENOSYS error
* Added some more Syscall
* Wrapped Vulkan library. Vulkan and dxvk now supported!
* Support building on PPC64LE (interpreter only)
* Added support for Risc-V (interpreter only)
v0.1.6
======
* Introduce "HotPage", to temporarily disable Dynarec on a page were writing is also occuring (can help speed up C# code)
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
* Introduce BOX64_DYNAREC_STRONGMEM for the (Arm) dynarec to emulate StrngMemory Model (needed by some games, like RimWorld)
* More functions wrapped
* Improve speed of the custom allocator used by dynarec and Hash (speedup loading)
* Added a workaround for streamwebhelper to not load it
@@ -263,7 +9,7 @@ v0.1.6
* Some residual fixes on thread attribute handling
* Better handling of app that want 32bits jumps, like unity3d/mono (thanks mogery)
* More ARM hardware option in CMake (Phytium, NX...)
* Added loongarch64 support (interpreter only)
* Added loongarch64 support (interpretor only)
* Some fixes to elfloader
* Added a mecanism to cancel a Dynarec block construction if it triggers a segfault (instead of a crash)
@@ -286,7 +32,7 @@ v0.1.4
v0.1.2
======
* OpenSource!
* A few more opcode added to the Interpreter and the Dynarec
* A few more opcode added to the Interpretor and the Dynarec
* Improved Native Function calling
* Added some function to limit allocated memory to 47bits space (for Wine)
* Improved and Fixed the functions to limit allocated memory to 32bits space
@@ -300,7 +46,7 @@ v0.1.0
* Some fixes to a few function signature
* Improvement to Signal handling, and internal mutex handling
* A few fixes to some dynarec opcodes
* A few fixes to some interpreter opcodes
* A few fixes to some interpretor opcodes
v0.0.8
======
Regular → Executable
+72 -264
View File
@@ -1,333 +1,141 @@
Compiling/Installing
Compiling
----
#### for RK3399
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-build-packages) for alternatives.
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-compiling)
## Per-platform compiling instructions
### The general approach
Using a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. ${OPTIONS}
make -j4
mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
- You can use `make -j1`, `make -j2` with less jobs to prevent running out of memory
- You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on a Linux Kernel mixed with Android, like on RK3588.
#### Example of generic ARM64 build for linux platforms
#### for PI4
Warning, you need a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -D ARM_DYNAREC=ON -D CMAKE_BUILD_TYPE=RelWithDebInfo
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
----
#### for RK3399
On a 64bit OS:
```
-D RK3399=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for RK3588 / RK3588S
On a 64bit OS:
```
-D RK3588=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for Raspberry Pi 3
On a 64bit OS:
If building on the Pi, you will also need a large swap (3 GB+)
[optionally reduce GPU memory to a minimum (e.g. 16 MB) using `raspi-config`
(and reboot) before starting the build]:
You can use e.g. '`make -j4`' to speed up the build, but on a Pi 3 with 1GB memory you will likely
run out of memory at some point and need to run the build again.
Still, this can be faster if your build is attended.
```
-D RPI3ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for Raspberry Pi 4
On a 64bit OS:
```
-D RPI4ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for Raspberry Pi 5
```
-D RPI5ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for TEGRA X1
On a 64bit OS:
Using a 64bits OS:
```
-D TEGRAX1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
#### for Jetson Xavier/T194
#### for Snapdragon 845
On a 64bit OS:
Using a 64bits OS:
```
-D TEGRA_T194=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DSD845=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
#### for Jetson Orin/T234
On a 64bit OS:
Note: use gcc-11 or higher, older gcc doesn't know cortex-a78ae
```
-D TEGRA_T234=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for ODROID N2/N2+
On a 64bit OS:
```
-D ODROIDN2=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for Snapdragon
On a 64bit OS:
```
-D SD845=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
or
```
-D SD888=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
Depending on how recent your Snapdragon is
----
#### for Phytium
On a 64bit OS:
Using a 64bits OS:
```
-D PHYTIUM=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
#### for ADLink machines
On a 64bit OS:
If it's the first install, you also need:
```
-D ADLINK=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for M1
Only test on Asahi with Fedora, using the default "16K page" kernel
```
-D M1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
sudo systemctl restart systemd-binfmt
```
#### for LoongArch
On a 64bit OS:
Using a 64bits OS:
```
-D LARCH64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DLARCH64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
#### for RISC-V
#### for Other ARM64 Linux platforms
On a 64bit OS:
```
-D RV64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for PowerPC 64 LE
On a 64bit OS:
```
-D PPC64LE=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for LX2160A
On a 64bit OS:
```
-D LX2160A=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
#### for Termux
You must have ARM64 machine to build box64.
##### in CHRoot/PRoot
```
-D ARM64=1 -DCMAKE_C_COMPILER=gcc -DBAD_SIGNAL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
```
##### in Termux (Native)
Note: Box64 in native termux is experimental and won't run linux binaries!
You also need `libandroid-sysv-semaphore` and `libandroid-spawn` libraries.
```
-D TERMUX=1 -DCMAKE_C_COMPILER=clang -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
#### for x86_64 Linux
```
-D LD80BITS=1 -D NOALIGN=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
```
If you encounter some linking errors, try using `NOLOADADDR=ON` (`cmake -D NOLOADADDR=ON; make -j$(nproc)`).
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
----
If you encounter some linking errors, try activating `NOLOADADDR` (`cmake -DNOLOADADDR=ON; make -j$(nproc)`).
### Use ccmake
### use ccmake
Alternatively, you can **use the curses-based ccmake (or any other gui frontend for cmake)** to select which platform to use interactively.
Alternatively, you can **use the curses-bases ccmake (or any other gui frontend for cmake)** to select wich platform to use interactively.
### Customize your build
#### Use ccache when present
*Use ccache if you have it*
Add `-DUSE_CCACHE=1` option if you have ccache and plan to touch the sources.
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
#### Include debug information
*To have some debug info*
Add `-DCMAKE_BUILD_TYPE=RelWithDebInfo` option for an optimized build with debug information embedded. That way, if you want to debug a crash or analyze performance, you have symbols.
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
#### Build with trace
*To have a Trace Enabled build*
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime to get x86 trace. Use version v3.2.1, as later versions have changed the API and no longer work with box64.
To have a trace enabled build ( ***the interpretor will be slightly slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
#### Build ARM DynaRec
*To have ARM Dynarec*
Add `-DARM_DYNAREC=1` option to enable DynaRec on ARM machines.
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`.
#### Save memory at run time
*Not building from a git clone*
You can use `-DSAVE_MEM` to have a build that will try to save some memory. For now, it only increases the jumptable from 4 levels to 5. The added granularity avoids wasting space, but adds one more read from memory when jumping between blocks.
#### Build outside of a git repo
Box64 uses git SHA1 to show last commit in version number, use `-DNOGIT=1` option when building outside of a git repo (for example, downloading a release source code zip from github).
#### Use faster linker
Add `-DWITH_MOLD=1` option when GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
#### Build a statically linked box64
You can now build box64 statically linked, with `-DSTATICBUILD` to use inside of a x86_64 chroot. Note that this version of box64 will only have the minimal wrapped libs, such as libc, libm and libpthread. Other libs (like libGL or libvulkan, SDL2, etc...) will use x86_64 versions. A static build is intended to be used in a docker image, or in a headless server. It is highly experimental, but feedback is always welcome.
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box64 print).
----
## Testing
A few tests are included with box64.
They can be launched using the `ctest` command.
The tests are very basic and only test some functionality for now.
Testing
----
## Debian Packaging
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you want in `debian/rules`.
## Pre-built packages
### Debian-based Linux
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
```
# check if .list file already exists
if [ -f /etc/apt/sources.list.d/box64.list ]; then
sudo rm -f /etc/apt/sources.list.d/box64.list || exit 1
fi
# check if .sources file already exists
if [ -f /etc/apt/sources.list.d/box64.sources ]; then
sudo rm -f /etc/apt/sources.list.d/box64.sources || exit 1
fi
# download gpg key from specified url
if [ -f /usr/share/keyrings/box64-archive-keyring.gpg ]; then
sudo rm -f /usr/share/keyrings/box64-archive-keyring.gpg
fi
sudo mkdir -p /usr/share/keyrings
wget -qO- "https://pi-apps-coders.github.io/box64-debs/KEY.gpg" | sudo gpg --dearmor -o /usr/share/keyrings/box64-archive-keyring.gpg
# create .sources file
echo "Types: deb
URIs: https://Pi-Apps-Coders.github.io/box64-debs/debian
Suites: ./
Signed-By: /usr/share/keyrings/box64-archive-keyring.gpg" | sudo tee /etc/apt/sources.list.d/box64.sources >/dev/null
sudo apt update
sudo apt install box64-generic-arm -y
```
## Cross-compiling
----
### Set Up the Cross-Compiler
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
### Run CMake with Cross-Compilation Options
Follow the per-platform compilation instructions to configure the CMake options for your target architecture.
In particular, you must specify the cross-compiler. For example:
```
-DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc # Or whichever cross-compiler you use
```
### Running tests with QEMU (optional)
To do a quick check, run:
```
qemu-riscv64 -L path/to/your/riscv64/sysroot box64 --help
```
You can run `dirname $(find -name libc.so.6)` to determine whether sysroot is provided by the prebuilt GNU toolchain or not.
To run CTest-based tests under QEMU:
```
ctest -j$(nproc)
```
### Installing on the Target Machine
After successfully cross-compiling, copy the box64 executable to your RISC-V device. Note that simply copying the binary does not automatically install Box64’s shared libraries. Because `make install` does not run on the target during cross-compilation, libraries required for emulation may be missing.
To fix this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target. Place them into the proper library search paths, for example:
- `/usr/lib/box64-x86_64-linux-gnu/` (for x86_64)
- `/usr/lib/box64-i386-linux-gnu/` (for i386)
A few tests are included.
They can be launched with `ctest`
They are very basic and don't test much for now.
+114
View File
@@ -0,0 +1,114 @@
# box64
![Official logo](img/Box64Logo.png "Official Logo")
Linux Userspace x86_64 Emulator with a twist
----
![box64 build status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main)
[中文](README_CN.md)
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
You can find many more Box64 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
Because Box64 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/).
Box64 integrates a DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than only using the interpreter. Some high level information on how the Dynarec work can be found [here](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/).
Some x64 internal opcodes use parts of "Realmode X86 Emulator Library", see [x64primop.c](../src/emu/x64primop.c) for copyright details
<img src="img/Box64Icon.png" width="96" height="96">
Logo and Icon made by @grayduck, thanks!
----
Usage
----
There are a few environment variables to control the behaviour of Box64.
See [here](USAGE.md) for all environment variables and what they do.
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
----
Compiling/Installation
----
> Compilation instructions can be found [here](COMPILE.md)
----
Version history
----
The change log is available [here](CHANGELOG.md)
----
Notes about 32-bit platforms
----
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bits libraries. Box64 doesn't include any 64-bits <-> 32-bits translation.
So understand that box64 will only runs 64bits linux binaries. For 32bits binaries, you need box86 (with all the multiarch or proot trickery it imply on 64bits OS).
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when argument is "-m"
----
Notes about Unity game emulation
----
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not always emulated in a 100% accurate way).
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
So, not all Unity games work and can require a high OpenGL profile, but many actualy works now
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game start then quit before showing anything.
----
Notes about GTK programs
----
GTK libraries are not wrapped yet on box64 (contrary to box86). Many games use gtk (setup too), like Unity game for the Screen Selection dialog. While Unity game can run without that dialog (using default setup), many just can't. For now, you'll need o put the set of gtk x86_64 libraries in the game folder (or some other folder known by box64) to get gtk support. GTK Wrapping is planned on box64.
----
Notes about Steam
----
Not that Steam is an hybrid 32bits / 64bits. You NEED box86 to run steam, as the client app is a 32bits binaries. It also use a 64bits local server binaries, but like most stuff using libcef/chromium. it's not working correctly on box64 for now.
So: no Steam for now on box64.
----
Notes about Wine
----
Wine 64bits is supported on box64. Be aware that 64bits wine also include 32bits componant, to be able to run 32bits windws programs. The 32bits will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64bits setup can run both 32bits and 64bits windows program (just use `wine` and `wine64` respectivelly)
----
Notes about Vulkan
----
Box64 Does not wrap Vulkan libraries yet. It's planned, but for now, vulkan program will not run on box64.
----
Final word
----
I want to thank everyone who has contributed to box64 developpement.
There are many ways to contribute: code contribution, financial, hardware and advertisement!
So, in no particular order, I want to thank:
* For their major code contribution: rajdakin, mogery
* For their major financial contribution: FlyingFathead, stormchaser3000
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/)
* For their continous advertisement of box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
And I also thank the many other people who participated even once in the project.
(If you use Box64 in your project, please don't forget to mention it!)
+119
View File
@@ -0,0 +1,119 @@
# box64
![Official logo](img/Box64Logo.png "Official Logo")
Linux上用户空间的x86_64应用模拟器
----
![box64 build status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main)
[English](README.md)
在ARM或其他非X86_64架构的Linux操作系统上,使用Box64可以运行x86_64 Linux程序(例如游戏),请注意,主机系统需要**64位小端**。
您可以在Youtube的[MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)、[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)或[The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)频道找到更多Box64视频。
Box64使用了一些“系统”库的原生版本,例如libc、libm、SDL和OpenGL,所以它很容易与大多数应用程序集成和使用,并且在很多情况下性能会出奇的高。点击[此处](https://box86.org/index.php/2021/06/game-performances/)查看示例的基准测试分析。
Box64为ARM64平台集成了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/)找到。
注:DynaRec需要针对不同平台编写一部分汇编代码,目前仅支持ARM64。
一些x64内部操作码使用“Realmode X86 Emulator Library”的部分内容,请参阅[x64primop.c](../src/emu/x64primop.c)了解版权详情
<img src="img/Box64Icon.png" width="96" height="96">
Logo和图标由grayduck制作,感谢!
----
使用方法
----
若干环境变量可以设置Box64的行为。
点击[这里](USAGE.md)了解所有的环境变量和它们的作用。
请注意:Box64的Dynarec提供了一种机制来处理JIT代码,包含内存保护和段错误信号处理程序。简单地说,如果您想用GDB来调试一个使用JIT代码的运行程序(比如mono/Unity3D),您仍然会触发很多“正常”的段错误。建议在GDB中使用类似于`handle SIGSEGV nostop`的东西,不要在每个段错误时都停止,如果您想捕获段错误,可以在`signals.c`中的`my_memprotectionhandler`中放置一个断点。
----
编译/安装
----
> 编译说明可以在[这里](COMPILE.md)查看。
----
版本历史
----
版本日志在[这里](CHANGELOG.md)。
----
32位平台的注意事项
----
Box64的工作原理是直接将函数调用从x86_64转换到主机系统,主机系统(Box64运行的系统)需要有64位的库。Box64并不包括任何64位<->32位的转换。
所以请理解,Box64只能运行64位的Linux二进制文件。对于32位的二进制文件,需要Box86(在64位的操作系统上需要所有的multiarch库或一些proot技巧)。
请注意,许多(基于mojo的)安装程序,即使存在x86_64版本,但在检测到架构为ARM64时会退回到"x86",这时会尝试使用(如果有)box86进行安装。这时你可以使用一个假的"uname",当它的参数为"-m"时返回"x86_64"。
----
关于Unity游戏模拟的注意事项
----
当前Unity游戏模拟是一件碰运气的事情。Unity使用Mono(它的信号表示,并不总能100%成功模拟)。
您还应该注意,一些Unity3D游戏需要OpenGL 3+,目前在ARM SBC(单板计算机)上提供OpenGL 3+是很棘手的。
所以,并不是所有的Unity游戏都能工作,而且可能需要很高的OpenGL配置,但现在很多游戏都能工作。
提示:如果游戏开始后在显示任何东西之前退出,在Pi4上使用`MESA_GL_VERSION_OVERRIDE=3.2`,在Panfrost上使用`PAN_MESA_DEBUG=gl3`来使用更高的配置文件。
----
关于GTK程序的注意事项
----
GTK库尚未封装在Box64内(与Box86相反)。许多游戏(包括设置)都使用gtk,例如Unity游戏的屏幕选择对话框。有些Unity游戏可以在没有该对话框的情况下运行(使用默认设置),还有一些不能。您需要将一套gtk x86_64库放在游戏目录(或其他一些Box64识别的目录)中以获得gtk支持。Box64有计划封装GTK原生库。
----
关于Steam的注意事项
----
Steam并不是32位/64位混合的,而是32位的,因此您需要Box86才能运行Steam。Steam也使用64位的本地服务器程序,但像大多数使用libcef/chromium的程序一样,在box64上暂时无法正常工作。
所以:目前在box64上无法运行Steam。
----
关于Wine的注意事项
----
box64支持64位Wine,但请注意,64位的Wine还包含32位的组件,以便能够运行32位的Windws程序。32位程序需要Box86,没有它就不能运行。在Box64和Box86共存的系统上,设置64位Wine可以同时运行32位和64位windows程序(只需分别使用 `wine` 和 `wine64`)。
----
关于Vulkan注意事项
----
Box64尚未封装原生Vulkan库,有计划这么做,但目前,vulkan程序不能在box64上运行。
----
结语
----
我要感谢所有为 box64 开发做出贡献的人。
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
以下感谢不分先后:
* 代码贡献:rajdakin, mogery
* 财务帮助:FlyingFathead, stormchaser3000
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/)
* 硬件捐赠和LoongArch迁移:[xiaoji](https://www.linuxgame.cn)
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
我还要感谢很多人,即使他们只参与了一次本项目。
(如果你的项目中使用了Box64,请不要忘记提及!)
Regular → Executable
+152 -695
View File
@@ -1,695 +1,152 @@
<!--- This file is generated by gen.py, do not edit it directly. -->
Usage
----
There are many environment variables to control Box64's behaviour, which will be listed below by category.
### Configuration files
In addition to environment variables, by default, Box64 also looks for 2 places for rcfile: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
Settings priority follows this order (from highest to lowest): `~/.box64rc` > `/etc/box64.box64rc` > environment variables.
Example configuration:
```
[factorio]
BOX64_DYNAREC_SAFEFLAGS=0
BOX64_DYNAREC_BIGBLOCK=2
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
```
This configuration will apply the specified settings application-wide to any executable named `factorio`.
### Advanced usage
1. **Wildcard Matching**
Asterisks (`*`) can be used for basic pattern matching in application names. For instance, `[*setup*]` will match any program containing "setup" in its name. Note this implements simple wildcard matching rather than full regex support.
2. **Custom Configuration File**
The `BOX64_RCFILE` environment variable can specify an alternative configuration file instead of the default `/etc/box64.box64rc`.
3. **Per-File Settings**
Sections starting with `/` apply to specific files. For example:
```
[/d3d9.dll]
BOX64_DYNAREC_SAFEFLAGS=0
```
These settings will only affect the `d3d9.dll` file. This syntax also works for **emulated** Linux libraries, e.g., `[/libstdc++.so.6]`.
----
## Libraries
### BOX64_ADDLIBS
Add extras to the needed libraries list, rarely needed.
* XXXX: Add library XXXX to the needed libraries list.
* XXXX:YYYY:ZZZZ: Add library XXXX, YYYY and ZZZZ to the needed libraries list.
### BOX64_ALLOWMISSINGLIBS
Allow missing libraries to be ignored.
* 0: Do not allow missing libraries. [Default]
* 1: Allow missing libraries.
### BOX64_EMULATED_LIBS
Force the use of emulated libraries.
* XXXX: Force the use of emulated library XXXX.
* XXXX:YYYY:ZZZZ: Force the use of emulated libraries XXXX, YYYY and ZZZZ.
### BOX64_LD_LIBRARY_PATH
Path to look for x86_64 libraries.
* XXXX: Add path XXXX to the library path.
### BOX64_LD_PRELOAD
Force loading libraries with the binary.
* XXXX: Force the loading of library XXXX.
* XXXX:YYYY: Force the loading of libraries XXXX and YYYY.
### BOX64_LIBGL
Set the name for libGL.
* libXXXX: Set the name for libGL to libXXXX.
* /path/to/libXXXX: Set the name and path for libGL to /path/to/libXXXX, you can also use SDL_VIDEO_GL_DRIVER.
### BOX64_NOGTK
Do not load wrapped GTK libraries.
* 0: Load wrapped GTK libraries. [Default]
* 1: Do not load wrapped GTK libraries.
### BOX64_NOPULSE
Do not load PulseAudio libraries (both native and x86_64).
* 0: Load PulseAudio libraries. [Default]
* 1: Do not load PulseAudio libraries.
### BOX64_NOVULKAN
Do not load Vulkan libraries.
* 0: Load Vulkan libraries. [Default]
* 1: Do not load Vulkan libraries, both native and x86_64.
### BOX64_PREFER_EMULATED
Prefer emulated libraries over native ones.
* 0: Prefer native libraries over emulated ones. [Default]
* 1: Prefer emulated libraries over native ones.
### BOX64_PREFER_WRAPPED
Prefer wrapped libs first even if the lib is specified with absolute path.
* 0: Prefer libs with absolute path over wrapped ones. [Default]
* 1: Prefer wrapped libs first even if the lib is specified with absolute path.
### BOX64_WRAP_EGL
Prefer wrapped libs for EGL and GLESv2.
* 0: Prefer emulated libs for EGL and GLESv2. [Default]
* 1: Prefer wrapped libs for EGL and GLESv2.
## Arguments
### BOX64_ARGS
Arguments to pass to the guest program, only valid if there is no existing arguments.
* XXXX: Pass argument XXXX to the program.
* XXXX YYYY ZZZZ: Pass arguments XXXX, YYYY and ZZZZ to the guest program.
### BOX64_CEFDISABLEGPU
Add -cef-disable-gpu argument to the guest program.
* 0: Does nothing. [Default]
* 1: Add -cef-disable-gpu argument to the guest program.
### BOX64_CEFDISABLEGPUCOMPOSITOR
Add -cef-disable-gpu-compositor argument to the guest program.
* 0: Does nothing. [Default]
* 1: Add -cef-disable-gpu-compositor argument to the guest program.
### BOX64_INSERT_ARGS
Prepend arguments to the command line.
* XXXX: Prepend argument XXXX to the program.
* XXXX YYYY ZZZZ: Prepend arguments XXXX, YYYY and ZZZZ to the guest program.
### BOX64_INPROCESSGPU
Add --in-process-gpu argument to the guest program.
* 0: Does nothing. [Default]
* 1: Add --in-process-gpu argument to the guest program.
### BOX64_NOSANDBOX
Add --no-sandbox argument to the guest program.
* 0: Does nothing. [Default]
* 1: Add --no-sandbox argument to the guest program.
## Compatibility
### BOX64_BASH
Path to the bash executable.
* XXXX: Use bash executable at path XXXX.
### BOX64_CPUTYPE
Specify the CPU type to emulate.
* 0: Emulate a Intel CPU Model. [Default]
* 1: Emulate a AMD CPU Model.
### BOX64_CRASHHANDLER
Use a dummy crash handler or not.
* 0: Use emulated crashhandler.so library if nedded.
* 1: Use an internal dummy (empty) crashhandler.so library. [Default]
### BOX64_DYNAREC_BLEEDING_EDGE
Detect MonoBleedingEdge and apply conservative settings.
* 0: Do not detect MonoBleedingEdge.
* 1: Detect MonoBleedingEdge and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
### BOX64_DYNAREC_DIV0
Enable or disable the generation of division-by-zero exception.
* 0: Do not generate thr division-by-zero exception. [Default]
* 1: Generate the division-by-zero exception.
### BOX64_DYNAREC_TBB
Enable or disable libtbb detection.
* 0: Do not detect libtbb.
* 1: Detect libtbb and apply conservative settings. [Default]
### BOX64_DYNAREC_X87DOUBLE
Force the use of float/double for x87 emulation.
* 0: Try to use float when possible for x87 emulation. [Default]
* 1: Only use Double for x87 emulation.
### BOX64_EXIT
Just exit, do not try to run the program.
* 0: Does nothing. [Default]
* 1: Just exit.
### BOX64_FIX_64BIT_INODES
Fix 64bit inodes.
* 0: Do not fix 64bit inodes. [Default]
* 1: Fix 64bit inodes.
### BOX64_IGNOREINT3
Ignore INT3 instructions.
* 0: Trigger a TRAP signal if a handler is present. [Default]
* 1: Skip the opcode silently.
### BOX64_JVM
Detect libjvm and apply conservative settings.
* 0: Does nothing.
* 1: Detect libjvm, and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0 when detected. [Default]
### BOX64_LIBCEF
Detect libcef and apply BOX64_MALLOC_HACK settings.
* 0: Does nothing.
* 1: Detect libcef, and apply BOX64_MALLOC_HACK=2 if detected. [Default]
### BOX64_MALLOC_HACK
Behaviour when hooking malloc operators.
* 0: Don't allow malloc operator to be redirected, rewriting code to use regular function. [Default]
* 1: Allow malloc operator to be redirected.
* 2: Like 0, but track special mmap/free (some redirected functions are inlined and cannot be redirected).
### BOX64_MAXCPU
Maximum CPU cores exposed.
* 0: Use the actual number of CPU cores. [Default]
* XXXX: Use XXXX CPU cores.
### BOX64_NORCFILES
Do not load any rc files.
* 0: Load rc files. [Default]
* 1: Do not load any rc files.
### BOX64_PATH
Path to look for x86_64 binaries.
* XXXX: Add path XXXX to the binary path.
### BOX64_RCFILE
Path to the rc file to load.
* XXXX: Load the rc file XXXX, default rc files will not be loaded.
### BOX64_RESERVE_HIGH
Reserve high memory area for the program, always enabled on Box32.
* 0: Do not reserve high memory area for the program. [Default]
* 1: Reserve high memory area for the program.
### BOX64_SDL2_JGUID
Use a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2.
* 0: Does nothing. [Default]
* 1: Use a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2.
### BOX64_SHAEXT
Expose SHAEXT (a.k.a. SHA_NI) capabilities.
* 0: Do not expose SHAEXT capabilities.
* 1: Expose SHAEXT capabilities. [Default]
### BOX64_SSE_FLUSHTO0
Behaviour of SSE Flush to 0 flags.
* 0: Just track the flag. [Default]
* 1: Apply SSE Flush to 0 flag directly.
### BOX64_SSE42
Expose SSE4.2 capabilities.
* 0: Do not expose SSE4.2 capabilities.
* 1: Expose SSE4.2 capabilities. [Default]
### BOX64_SYNC_ROUNDING
Synchronize rounding mode between x86 and native.
* 0: Do not synchronize rounding mode. [Default]
* 1: Synchronize rounding mode between x86 and native.
### BOX64_UNITYPLAYER
Detect UnityPlayer and apply conservative settings.
* 0: Does nothing.
* 1: Detect UnityPlayer, and apply BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
### BOX64_X11GLX
Force Xorg GLX extension to be present.
* 0: Do not force Xorg GLX extension to be present. [Default]
* 1: Require Xorg GLX extension when using XQueryExtension.
### BOX64_X11SYNC
Force synchronized operation on X11 display.
* 0: Do not force synchronized operation on X11 display. [Default]
* 1: Force synchronized operation on X11 display.
### BOX64_X11THREADS
Call XInitThreads when loading X11. This is mostly for old Loki games with the Loki_Compat library.
* 0: Do not call XInitThreads. [Default]
* 1: Call XInitThreads as soon as libX11 is loaded.
### BOX64_X87_NO80BITS
Behavoiur of x87 80bits long double.
* 0: Try to handle 80bits long double as precise as possible. [Default]
* 1: Use 64bits double for x87.
## Debugging
### BOX64_DLSYM_ERROR
Enable or disable the logging of dlsym errors.
* 0: Disable the logging of dlsym errors. [Default]
* 1: Enable the logging of dlsym errors.
### BOX64_DUMP
Dump elfloader debug information.
* 0: Do not dump elfloader debug information. [Default]
* 1: Dump elfloader debug information.
### BOX64_DYNAREC_DUMP
Enable DynaRec dump.
* 0: Do not dump DynaRec blocks. [Default]
* 1: Dump DynaRec blocks.
* 2: Dump DynaRec blocks with some colors.
### BOX64_DYNAREC_GDBJIT
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
* 0: Dynarec will not generate GDBJIT debuginfo. [Default]
* 1: Dynarec will generate GDBJIT debuginfo.
* 2: Dynarec will generate detailed GDBJIT debuginfo with internal state.
### BOX64_DYNAREC_LOG
Disable or enable DynaRec logs.
* 0: Disable DynaRec logs. [Default]
* 1: Enable minimal DynaRec logs.
* 2: Enable debug level DynaRec logs.
* 3: Enable verbose level DynaRec logs.
### BOX64_DYNAREC_MISSING
Print missing opcodes.
* 0: Do not print the missing opcode. [Default]
* 1: Print missing opcodes.
* 2: Print the fallback to scalar opcodes, only valid on RISC-V.
### BOX64_DYNAREC_PERFMAP
Generate map file for Linux perf tool.
* 0: Dynarec will not generate perf map. [Default]
* 1: Dynarec will generate perf map.
### BOX64_DYNAREC_TEST
Enable DynaRec execution comparison with the interpreter, very slow, only for testing.
* 0: No comparison. [Default]
* 1: Each opcode runs on interpreter and on Dynarec, regs and memory are compared and printed when they differ.
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynarec is tested (inclusive-exclusive).
### BOX64_DYNAREC_TRACE
Enable or disable DynaRec trace.
* 0: Do not trace DynaRec blocks. [Default]
* 1: Trace DynaRec blocks, will slow down the program a lot and generates huge logs.
### BOX64_JITGDB
Launch gdb or not for SIGSEGV, SIGILL, and SIGBUS.
* 0: Just print the message when the signal is caught. [Default]
* 1: Launch gdb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting. Inside gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack), then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then `set waiting=0` to exit the infinite loop.
* 2: Launch gdbserver when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1: 1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with `BOX64_JITGDB=1`.
* 3: Launch lldb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting.
### BOX64_LOAD_ADDR
Set the address where the program is loaded, only active for PIE guest programs.
* 0xXXXXXXXX: Set the address where the program is loaded.
### BOX64_LOG
Enable or disable Box64 logs.
* 0: Disable Box64 logs. [Default]
* 1: Enable minimal Box64 logs.
* 2: Enable debug level Box64 logs.
* 3: Enable verbose level Box64 logs.
### BOX64_NOBANNER
Disable the Box64 banner.
* 0: Show the Box64 banner. [Default]
* 1: Do not show the Box64 banner.
### BOX64_NOSIGSEGV
Disable the handling of SIGSEGV.
* 0: Let the x86 program set sighandler for SIGSEGV. [Default]
* 1: Disable the handling of SIGSEGV.
### BOX64_NOSIGILL
Disable the handling of SIGILL.
* 0: Let the x86 program set sighandler for SIGILL. [Default]
* 1: Disable the handling of SIGILL.
### BOX64_ROLLING_LOG
Show last few wrapped function call when a signal is caught.
* 0: Does nothing. [Default]
* 1: Show last 16 wrapped function call when a signal is caught.
* XXX: Show last XXX wrapped function call when a signal is caught.
### BOX64_SHOWBT
Show native and emulated backtrace when a signal is caught.
* 0: Does nothing. [Default]
* 1: Show native and emulated backtrace when a signal is caught.
### BOX64_SHOWSEGV
Always show SIGSEGV signal detailes.
* 0: Does nothing. [Default]
* 1: Always show SIGSEGV signal detailes.
### BOX64_TRACE_COLOR
Enable or disable colored trace output.
* 0: Disable colored trace output. [Default]
* 1: Enable colored trace output.
### BOX64_TRACE_EMM
Enable or disable EMM (i.e. MMX) trace output.
* 0: Disable EMM trace output. [Default]
* 1: Enable EMM trace output.
### BOX64_TRACE_FILE
Send all log and trace to a file instead of `stdout`.
* XXXX: Send all log and trace to file XXXX.
* XXXX%pid: Send all log and trace to file XXXX with pid appended.
* stderr: Send all log and trace to `stderr`.
### BOX64_TRACE_INIT
Same as BOX64_TRACE but starts the trace immediately.
* 0: Disable trace output. [Default]
* 1: Enable trace output. Trace starts before the initialization of dependencies.
### BOX64_TRACE_START
Start trace after N opcodes executed.
* 0: Start trace immediately. [Default]
* 1: Start trace after 1 opcode executed.
* XXXX: Start trace after XXXX opcodes executed.
### BOX64_TRACE_XMM
Enable or disable XMM (i.e. SSE) trace output.
* 0: Disable XMM trace output. [Default]
* 1: Enable XMM trace output.
### BOX64_TRACE
Only available on box64 build with trace. Adds trace of all instructions executed, along with a register dump.
* 0: Disable trace output. [Default]
* 1: Enable trace output.
* symbolname: Enable trace output for `symbolname` only.
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive).
## Performance
### BOX64_DYNAREC_ALIGNED_ATOMICS
Generate aligned atomics only (only available on Arm64 for now).
* 0: Generate unaligned atomics handling code. [Default]
* 1: Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.
### BOX64_DYNAREC_BIGBLOCK
Enable building bigger DynaRec code blocks for better performance.
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
* 1: Build Dynarec block as big as possible.
* 2: Build Dynarec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
* 3: Build Dynarec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
### BOX64_DYNAREC_CALLRET
Optimize CALL/RET opcodes.
* 0: Do not optimize CALL/RET, use jump table. [Default]
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
### BOX64_DYNAREC_DF
Enable or disable the use of deferred flags.
* 0: Disable the use of deferred flags.
* 1: Enable the use of deferred flags. [Default]
### BOX64_DYNAREC_DIRTY
Allow continue running a block that is unprotected and potentially dirty.
* 0: Do not allow continue running a block that is unprotected and potentially dirty. [Default]
* 1: Allow continue to run a dynablock that write data in the same page as code. It can gets faster in loading time of some game but can also get unexpected crashes.
### BOX64_DYNAREC_FASTNAN
Enable or disable fast NaN handling.
* 0: Precisely emulate the -NaN generation like on x86.
* 1: Do not do anything special with -NAN generation, faster. [Default]
### BOX64_DYNAREC_FASTROUND
Enable or disable fast rounding.
* 0: Generate float/double -> int rounding and use current rounding mode for float/double computation like on x86.
* 1: Do not do anything special with edge case rounding, faster. [Default]
* 2: Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
### BOX64_DYNAREC_FORWARD
Define max allowed forward value when building block.
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
### BOX64_DYNAREC_NATIVEFLAGS
Enable or disable the use of native flags.
* 0: Do not use native flags.
* 1: Use native flags when possible. [Default]
### BOX64_DYNAREC_PAUSE
Enable x86 PAUSE emulation, may help the performance of spinlocks.
* 0: Ignore x86 PAUSE instruction. [Default]
* 1: Use YIELD to emulate x86 PAUSE instruction.
* 2: Use WFI to emulate x86 PAUSE instruction.
* 3: Use SEVL+WFE to emulate x86 PAUSE instruction.
### BOX64_DYNAREC_SAFEFLAGS
Behaviour of flags emulation on CALL/RET opcodes.
* 0: Treat CALL/RET as if it never needs any flags.
* 1: Most of RETs will need flags, most of CALLs will not. [Default]
* 2: All CALL/RET will need flags.
### BOX64_DYNAREC_STRONGMEM
Enable the emulation of x86 strong memory model.
* 0: Do not try anything special. [Default]
* 1: Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
* 2: All in 1, plus memory barriers on SIMD instructions.
* 3: All in 2, plus more memory barriers on a regular basis.
### BOX64_DYNAREC_WAIT
Wait or not for the building of a DynaRec code block to be ready.
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
* 1: Wait for a DynaRec code block to be ready. [Default]
### BOX64_DYNAREC_WEAKBARRIER
Tweak the memory barriers to reduce the performance impact by strong memory emualtion.
* 0: Use regular safe barrier.
* 1: Use weak barriers to have more performance boost. [Default]
* 2: All in 1, plus disabled the last write barriers.
### BOX64_NODYNAREC
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter.
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynablock creation is forbidden (inclusive-exclusive).
### BOX64_RDTSC_1GHZ
Use hardware counter for rdtsc if available.
* 0: Use hardware counter for rdtsc opcode if available. [Default]
* 1: Use hardware counter for rdtsc if and only if precision is at least 1GHz.
## Environment
### BOX64_ENV
Add an environment variable.
* XXXX=yyyy: Add environment variable XXXX with value yyyy.
### BOX64_ENV[1-5]
Add an environment variable.
* XXXX=yyyy: Add environment variable XXXX with value yyyy.
Usage
----
There are many environment variables to control Box64 behaviour.
#### BOX64_LOG
Controls the Verbosity level of the logs
* 0: NONE : No message (except some fatal error). (Default.)
* 1: INFO : Show some minimum log (Example: librairies not found)
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
* 3: DUMP : All DEBUG plus DUMP of all ELF Info.
#### BOX64_NOBANNER
Disables Box64 printing its version and build
* 0 : Enable printing its banner. (Default.)
* 1 : Disable printing its banner.
#### BOX64_LD_LIBRARY_PATH
Path to look for x86_64 libraries. Default is current folder and `lib` in current folder.
Also, `/usr/lib/x86_64-linux-gnu` and `/lib/x86_64-linux-gnu` are added if they exist.
#### BOX64_PATH
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
#### BOX64_DLSYM_ERROR
Enables/Disables the logging of `dlsym` errors.
* 0 : Don't log `dlsym` errors. (Default.)
* 1 : Log dlsym errors.
#### BOX64_TRACE_FILE
Send all log and trace to a file instead of `stdout`
Also, if name contains `%pid` then this is replaced by the actual PID of box64 instance
Use `stderr` to use this instead of default `stdout`
#### BOX64_TRACE
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
* 0 : No trace. (Default.)
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
#### BOX64_TRACE_INIT
Use BOX64_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
* 0 : No trace. (Default.)
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
#### BOX64_TRACE_START
Only on builds with trace enabled.
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
#### BOX64_TRACE_XMM
Only on builds with trace enabled.
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
* 1 : Dump the XMM registers.
#### BOX64_TRACE_EMM
Only on builds with trace enabled.
* 0 : The EMM (i.e. XMM/x87) register will not be logged with the general and x86 registers. (Default.)
* 1 : Dump the EMM registers.
#### BOX64_TRACE_COLOR
Only on builds with trace enabled.
* 0 : The general registers will always be the default white color. (Default.)
* 1 : The general registers will change color in the dumps when they changed value.
#### BOX64_LOAD_ADDR
Try to load at 0xXXXXXX main binary (if binary is a PIE)
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
#### BOX64_NOSIGSEGV
Disable handling of SigSEGV. (Very useful for debugging.)
* 0 : Let the x86 program set sighandler for SEGV (Default.)
* 1 : Disable the handling of SigSEGV.
#### BOX64_NOSIGILL
Disable handling of SigILL (to ease debugging mainly).
* 0 : Let x86 program set sighandler for Illegal Instruction
* 1 : Disables the handling of SigILL
#### BOX64_X11THREADS
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
* 0 : Don't force call XInitThreads. (Default.)
* 1 : Call XInitThreads as soon as libX11 is loaded.
#### BOX64_X11GLX
Force libX11's GLX extension to be present.
* 0 : Do not force libX11's GLX extension to be present.
* 1 : GLX will always be present when using XQueryExtension. (Default.)
#### BOX64_DYNAREC_DUMP
Enables/disables Box64's Dynarec's dump.
* 0 : Disable Dynarec's blocks dump. (Default.)
* 1 : Enable Dynarec's blocks dump.
* 2 : Enable Dynarec's blocks dump with some colors.
#### BOX64_DYNAREC_LOG
Set the level of DynaRec's logs.
* 0 : NONE : No Logs for DynaRec. (Default.)
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
* 3 : VERBOSE : All of the above plus more.
#### BOX64_DYNAREC
Enables/Disables Box64's Dynarec.
* 0 : Disables Dynarec.
* 1 : Enable Dynarec. (Default.)
#### BOX64_DYNAREC_TRACE
Enables/Disables trace for generated code.
* 0 : Disable trace for generated code. (Default.)
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
#### BOX64_NODYNAREC
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
#### BOX64_LIBGL
* libXXXX set the name for libGL (defaults to libGL.so.1).
* /PATH/TO/libGLXXX : Sets the name and path for libGL
You can also use SDL_VIDEO_GL_DRIVER
#### BOX64_LD_PRELOAD
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
#### BOX64_EMULATED_LIBS
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
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
#### BOX64_ALLOWMISSINGLIBS
Allow Box64 to continue even if a library is missing.
* 0 : Box64 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.
#### BOX64_NOPULSE
Disables the load of pulseaudio libraries.
* 0 : Load pulseaudio libraries if found. (Default.)
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
#### BOX64_JITGDB
* 0 : Just print the Segfault message on segfault (default)
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack)
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`,
just before the printf of the Segfault message. Then simply
`set waiting=0` to exit the infinite loop.
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`.
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
-177
View File
@@ -1,177 +0,0 @@
# Installing Wine64
Running Wine64/Wine with Box64/Box86 allows x64/x86 Windows programs to run on 64-bit ARM Linux devices.
- Box64 needs `wine-amd64` to be installed **manually** on ARM64 (aarch64) devices. This will run 64-bit Windows programs (aka x86_64).
- Box86 needs `wine-i386` to be installed **manually** on ARM32 (armhf) devices (or on ARM64 with multiarch or chroot). This will run 32-bit Windows programs (aka x86).
- _Note that `wine:arm64` and `wine:armhf` will not work with Box64/Box86. Your device's package manager might try to install those if you ask it to install wine._
See installation steps below (in the [Examples](#examples) section).
## Overview
The general procedure for installing Wine64 & Wine for Box64 & Box86 is to...
- Download all the install files for the version of Wine you wish to install
- Unzip or dpkg the install files into one folder
- Move that folder to the directory that you wish Wine to run from (often `~/wine/` by default)
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries.
- Boot wine to create a new wineprefix.
- Download winetricks (which is just a complicated bash script), make it executable, then copy it to `/usr/local/bin`.
## Examples
### Installing Wine64 & Wine for Box64 & Box86 on Raspberry Pi OS from WineHQ .deb files
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/)_
This install method allows you to install different versions of Wine64/Wine. You may install any version/branch of Wine that you wish.
```
# NOTE: Can only run on aarch64 (since box64 can only run on aarch64)
# box64 runs wine-amd64, box86 runs wine-i386.
### User-defined Wine version variables ################
# - Replace the variables below with your system's info.
# - Note that we need the amd64 version for Box64 even though we're installing it on our ARM processor.
# - Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.
# - Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
local branch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386)
local version="7.1" #example: "7.1"
local id="debian" #example: debian, ubuntu
local dist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, ${VERSION_CODENAME}, etc
local tag="-1" #example: -1 (some wine .deb files have -1 tag on the end and some don't)
########################################################
# Clean up any old wine instances
wineserver -k # stop any old wine installations from running
rm -rf ~/.cache/wine # remove any old wine-mono/wine-gecko install files
rm -rf ~/.local/share/applications/wine # remove any old program shortcuts
# Backup any old wine installs
rm -rf ~/wine-old 2>/dev/null; mv ~/wine ~/wine-old 2>/dev/null
rm -rf ~/.wine-old 2>/dev/null; mv ~/.wine ~/.wine-old 2>/dev/null
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old 2>/dev/null
sudo mv /usr/local/bin/wine64 /usr/local/bin/wine-old 2>/dev/null
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old 2>/dev/null
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old 2>/dev/null
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old 2>/dev/null
# Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
LNKA="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-amd64/" #amd64-wine links
DEB_A1="wine-${branch}-amd64_${version}~${dist}${tag}_amd64.deb" #wine64 main bin
DEB_A2="wine-${branch}_${version}~${dist}${tag}_amd64.deb" #wine64 support files (required for wine64 / can work alongside wine_i386 main bin)
#DEB_A3="winehq-${branch}_${version}~${dist}${tag}_amd64.deb" #shortcuts & docs
LNKB="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-i386/" #i386-wine links
DEB_B1="wine-${branch}-i386_${version}~${dist}${tag}_i386.deb" #wine_i386 main bin
DEB_B2="wine-${branch}_${version}~${dist}${tag}_i386.deb" #wine_i386 support files (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
#DEB_B3="winehq-${branch}_${version}~${dist}${tag}_i386.deb" #shortcuts & docs
# Install amd64-wine (64-bit) alongside i386-wine (32-bit)
echo -e "Downloading wine . . ."
wget -q ${LNKA}${DEB_A1}
wget -q ${LNKA}${DEB_A2}
wget -q ${LNKB}${DEB_B1}
echo -e "Extracting wine . . ."
dpkg-deb -x ${DEB_A1} wine-installer
dpkg-deb -x ${DEB_A2} wine-installer
dpkg-deb -x ${DEB_B1} wine-installer
echo -e "Installing wine . . ."
mv wine-installer/opt/wine* ~/wine
# Download wine dependencies
# - these packages are needed for running box86/wine-i386 on a 64-bit RPiOS via multiarch
sudo dpkg --add-architecture armhf && sudo apt-get update # enable multi-arch
sudo apt-get install -y libasound2:armhf libc6:armhf libglib2.0-0:armhf libgphoto2-6:armhf libgphoto2-port12:armhf \
libgstreamer-plugins-base1.0-0:armhf libgstreamer1.0-0:armhf libldap-2.4-2:armhf libopenal1:armhf libpcap0.8:armhf \
libpulse0:armhf libsane1:armhf libudev1:armhf libusb-1.0-0:armhf libvkd3d1:armhf libx11-6:armhf libxext6:armhf \
libasound2-plugins:armhf ocl-icd-libopencl1:armhf libncurses6:armhf libncurses5:armhf libcap2-bin:armhf libcups2:armhf \
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
libxrender1:armhf libxxf86vm1 libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
# This list found by downloading...
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel_7.1~bullseye-1_i386.deb
# then `dpkg-deb -I package.deb`. Read output, add `:armhf` to packages in dep list, then try installing them on Pi aarch64.
# - these packages are needed for running box64/wine-amd64 on RPiOS (box64 only runs on 64-bit OS's)
sudo apt-get install -y libasound2:arm64 libc6:arm64 libglib2.0-0:arm64 libgphoto2-6:arm64 libgphoto2-port12:arm64 \
libgstreamer-plugins-base1.0-0:arm64 libgstreamer1.0-0:arm64 libldap-2.4-2:arm64 libopenal1:arm64 libpcap0.8:arm64 \
libpulse0:arm64 libsane1:arm64 libudev1:arm64 libunwind8:arm64 libusb-1.0-0:arm64 libvkd3d1:arm64 libx11-6:arm64 libxext6:arm64 \
ocl-icd-libopencl1:arm64 libasound2-plugins:arm64 libncurses6:arm64 libncurses5:arm64 libcups2:arm64 \
libdbus-1-3:arm64 libfontconfig1:arm64 libfreetype6:arm64 libglu1-mesa:arm64 libgnutls30:arm64 \
libgssapi-krb5-2:arm64 libjpeg62-turbo:arm64 libkrb5-3:arm64 libodbc1:arm64 libosmesa6:arm64 libsdl2-2.0-0:arm64 libv4l-0:arm64 \
libxcomposite1:arm64 libxcursor1:arm64 libxfixes3:arm64 libxi6:arm64 libxinerama1:arm64 libxrandr2:arm64 \
libxrender1:arm64 libxxf86vm1:arm64 libc6:arm64 libcap2-bin:arm64
# This list found by downloading...
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel_7.1~bullseye-1_amd64.deb
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel-amd64_7.1~bullseye-1_amd64.deb
# then `dpkg-deb -I package.deb`. Read output, add `:arm64` to packages in dep list, then try installing them on Pi aarch64.
# These packages are needed for running wine-staging on RPiOS (Credits: chills340)
sudo apt install libstb0 -y
cd ~/Downloads
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
sudo cp -TRv libfaudio/usr/ /usr/
rm libfaudio0_*~bpo10+1_i386.deb # clean up
rm -rf libfaudio # clean up
# Install symlinks
sudo ln -s ~/wine/bin/wine /usr/local/bin/wine
sudo ln -s ~/wine/bin/wine64 /usr/local/bin/wine64
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wine64 /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
```
## Installing winetricks
Winetricks is a bash script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs. You can either install it with `apt`, or manually using the steps below.
```
sudo apt-get install cabextract -y # winetricks needs this installed
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old # Backup old winetricks
cd ~/Downloads && wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks # Download
sudo chmod +x winetricks && sudo mv winetricks /usr/local/bin/ # Install
```
Whenever we run winetricks, we must tell Box86 to supress its info banner, otherwise winetricks will crash. Box86's info banner can be suppressed using the `BOX86_NOBANNER=1` environment variable before invoking winetricks (example: `BOX86_NOBANNER=1 winetricks`).
If `apt` installed a desktop menu shortcut for winetricks (or if you make your own desktop shortcut for winetricks) then you may need to edit that shortcut to include Box86's BOX86_NOBANNER=1 env var. With your favorite text editor, edit `/usr/share/applications/winetricks.desktop` and change `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`.
## Example commands
Creating a 64-bit wineprefix:
`wine64 wineboot` or `wine wineboot` (wineprefix is created in `~/.wine/`)
`WINEPREFIX="$HOME/prefix64" wine wineboot` (wineprefix is created in `~/prefix64/`) _Note: You will need to invoke `WINEPREFIX="$HOME/prefix64"` before every command to use this wineprefix._
Creating a 32-bit wineprefix:
`WINEARCH=win32 wine wineboot` (wineprefix is created in `~/.wine/`)
Fore-quitting wine:
`wineserver -k`
Running Wine Configuration:
`winecfg`
Using winetricks:
`winetricks -q corefonts vcrun2010 dotnet20sp1`
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will cause winetricks to crash.
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
## Other notes
### Wineprefixes (and Wine initialization)
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable. For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
### Transplanting wineprefixes
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
### Swapping out different versions of Wine
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will migrate a wineprefix from an older version of Wine to be usable by the newer version of Wine you just installed. You can check which version of Wine you're running with the `wine --version` command.
-784
View File
@@ -1,784 +0,0 @@
=head1 NAME
box64 - Linux Userspace x86_64 Emulator with a twist
=head1 SYNOPSIS
B<box64> [B<--help>] [B<--version>] I<executable>
=head1 DESCRIPTION
B<Box64> lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux
systems, like ARM (host system needs to be 64-bit little-endian). Since B<Box64>
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. B<Box64> integrates with DynaRec (dynamic
recompiler) for the ARM64 platform, providing a speed boost between 5 to 10
times faster than using only the interpreter.
=head1 OPTIONS
=over 8
=item B<-h,--help>
Print box64 help and quit.
=item B<-v,--version>
Print box64 version and quit.
=back
=head1 BRIEF USAGE
There are many environment variables to control B<Box64>'s behaviour. In
addition to environment variables, B<Box64> also looks for 2 places for rcfile:
F</etc/box64.box64rc> and F<~/.box64rc>, in the format of .ini files.
Settings priority: F<~/.box64rc> > F</etc/box64.box64rc> > environment variables.
Example:
[factorio]
BOX64_DYNAREC_SAFEFLAGS=0
BOX64_DYNAREC_BIGBLOCK=2
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
=head1 ENVIRONMENT VARIABLES
=over 8
=item B<BOX64_ADDLIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
Add extras to the needed libraries list, rarely needed.
* XXXX : Add library XXXX to the needed libraries list.
* XXXX:YYYY:ZZZZ : Add library XXXX, YYYY and ZZZZ to the needed libraries list.
=item B<BOX64_ALLOWMISSINGLIBS> =I<0|1>
Allow missing libraries to be ignored.
* 0 : Do not allow missing libraries. [Default]
* 1 : Allow missing libraries.
=item B<BOX64_ARGS> =I<XXXX|XXXX YYYY ZZZZ>
Arguments to pass to the guest program, only valid if there is no existing arguments.
* XXXX : Pass argument XXXX to the program.
* XXXX YYYY ZZZZ : Pass arguments XXXX, YYYY and ZZZZ to the guest program.
=item B<BOX64_BASH> =I<XXXX>
Path to the bash executable.
* XXXX : Use bash executable at path XXXX.
=item B<BOX64_CEFDISABLEGPU> =I<0|1>
Add -cef-disable-gpu argument to the guest program.
* 0 : Does nothing. [Default]
* 1 : Add -cef-disable-gpu argument to the guest program.
=item B<BOX64_CEFDISABLEGPUCOMPOSITOR> =I<0|1>
Add -cef-disable-gpu-compositor argument to the guest program.
* 0 : Does nothing. [Default]
* 1 : Add -cef-disable-gpu-compositor argument to the guest program.
=item B<BOX64_CPUTYPE> =I<0|1>
Specify the CPU type to emulate.
* 0 : Emulate a Intel CPU Model. [Default]
* 1 : Emulate a AMD CPU Model.
=item B<BOX64_CRASHHANDLER> =I<0|1>
Use a dummy crash handler or not.
* 0 : Use emulated crashhandler.so library if nedded.
* 1 : Use an internal dummy (empty) crashhandler.so library. [Default]
=item B<BOX64_DLSYM_ERROR> =I<0|1>
Enable or disable the logging of dlsym errors.
* 0 : Disable the logging of dlsym errors. [Default]
* 1 : Enable the logging of dlsym errors.
=item B<BOX64_DUMP> =I<0|1>
Dump elfloader debug information.
* 0 : Do not dump elfloader debug information. [Default]
* 1 : Dump elfloader debug information.
=item B<BOX64_DYNAREC_ALIGNED_ATOMICS> =I<0|1>
Generate aligned atomics only (only available on Arm64 for now).
* 0 : Generate unaligned atomics handling code. [Default]
* 1 : Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.
=item B<BOX64_DYNAREC_BIGBLOCK> =I<0|1|2|3>
Enable building bigger DynaRec code blocks for better performance.
* 0 : Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
* 1 : Build Dynarec block as big as possible.
* 2 : Build Dynarec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
* 3 : Build Dynarec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
=item B<BOX64_DYNAREC_BLEEDING_EDGE> =I<0|1>
Detect MonoBleedingEdge and apply conservative settings.
* 0 : Do not detect MonoBleedingEdge.
* 1 : Detect MonoBleedingEdge and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
=item B<BOX64_DYNAREC_CALLRET> =I<0|1>
Optimize CALL/RET opcodes.
* 0 : Do not optimize CALL/RET, use jump table. [Default]
* 1 : Try to optimize CALL/RET, skipping the jump table when possible.
=item B<BOX64_DYNAREC_DF> =I<0|1>
Enable or disable the use of deferred flags.
* 0 : Disable the use of deferred flags.
* 1 : Enable the use of deferred flags. [Default]
=item B<BOX64_DYNAREC_DIRTY> =I<0|1>
Allow continue running a block that is unprotected and potentially dirty.
* 0 : Do not allow continue running a block that is unprotected and potentially dirty. [Default]
* 1 : Allow continue to run a dynablock that write data in the same page as code. It can gets faster in loading time of some game but can also get unexpected crashes.
=item B<BOX64_DYNAREC_DIV0> =I<0|1>
Enable or disable the generation of division-by-zero exception.
* 0 : Do not generate thr division-by-zero exception. [Default]
* 1 : Generate the division-by-zero exception.
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2>
Enable DynaRec dump.
* 0 : Do not dump DynaRec blocks. [Default]
* 1 : Dump DynaRec blocks.
* 2 : Dump DynaRec blocks with some colors.
=item B<BOX64_DYNAREC_FASTNAN> =I<0|1>
Enable or disable fast NaN handling.
* 0 : Precisely emulate the -NaN generation like on x86.
* 1 : Do not do anything special with -NAN generation, faster. [Default]
=item B<BOX64_DYNAREC_FASTROUND> =I<0|1|2>
Enable or disable fast rounding.
* 0 : Generate float/double -> int rounding and use current rounding mode for float/double computation like on x86.
* 1 : Do not do anything special with edge case rounding, faster. [Default]
* 2 : Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|XXXX>
Define max allowed forward value when building block.
* 0 : No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
* 128 : Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
* XXXX : Allow up to XXXX bytes of gap between end of the block and the next forward jump.
=item B<BOX64_DYNAREC_GDBJIT> =I<0|1|2>
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
* 0 : Dynarec will not generate GDBJIT debuginfo. [Default]
* 1 : Dynarec will generate GDBJIT debuginfo.
* 2 : Dynarec will generate detailed GDBJIT debuginfo with internal state.
=item B<BOX64_DYNAREC_LOG> =I<0|1|2|3>
Disable or enable DynaRec logs.
* 0 : Disable DynaRec logs. [Default]
* 1 : Enable minimal DynaRec logs.
* 2 : Enable debug level DynaRec logs.
* 3 : Enable verbose level DynaRec logs.
=item B<BOX64_DYNAREC_MISSING> =I<0|1|2>
Print missing opcodes.
* 0 : Do not print the missing opcode. [Default]
* 1 : Print missing opcodes.
* 2 : Print the fallback to scalar opcodes, only valid on RISC-V.
=item B<BOX64_DYNAREC_NATIVEFLAGS> =I<0|1>
Enable or disable the use of native flags.
* 0 : Do not use native flags.
* 1 : Use native flags when possible. [Default]
=item B<BOX64_DYNAREC_PAUSE> =I<0|1|2|3>
Enable x86 PAUSE emulation, may help the performance of spinlocks.
* 0 : Ignore x86 PAUSE instruction. [Default]
* 1 : Use YIELD to emulate x86 PAUSE instruction.
* 2 : Use WFI to emulate x86 PAUSE instruction.
* 3 : Use SEVL+WFE to emulate x86 PAUSE instruction.
=item B<BOX64_DYNAREC_PERFMAP> =I<0|1>
Generate map file for Linux perf tool.
* 0 : Dynarec will not generate perf map. [Default]
* 1 : Dynarec will generate perf map.
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
Behaviour of flags emulation on CALL/RET opcodes.
* 0 : Treat CALL/RET as if it never needs any flags.
* 1 : Most of RETs will need flags, most of CALLs will not. [Default]
* 2 : All CALL/RET will need flags.
=item B<BOX64_DYNAREC_STRONGMEM> =I<0|1|2|3>
Enable the emulation of x86 strong memory model.
* 0 : Do not try anything special. [Default]
* 1 : Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
* 2 : All in 1, plus memory barriers on SIMD instructions.
* 3 : All in 2, plus more memory barriers on a regular basis.
=item B<BOX64_DYNAREC_TBB> =I<0|1>
Enable or disable libtbb detection.
* 0 : Do not detect libtbb.
* 1 : Detect libtbb and apply conservative settings. [Default]
=item B<BOX64_DYNAREC_TEST> =I<0|1|0xXXXXXXXX-0xYYYYYYYY>
Enable DynaRec execution comparison with the interpreter, very slow, only for testing.
* 0 : No comparison. [Default]
* 1 : Each opcode runs on interpreter and on Dynarec, regs and memory are compared and printed when they differ.
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where dynarec is tested (inclusive-exclusive).
=item B<BOX64_DYNAREC_TRACE> =I<0|1>
Enable or disable DynaRec trace.
* 0 : Do not trace DynaRec blocks. [Default]
* 1 : Trace DynaRec blocks, will slow down the program a lot and generates huge logs.
=item B<BOX64_DYNAREC_WAIT> =I<0|1>
Wait or not for the building of a DynaRec code block to be ready.
* 0 : Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
* 1 : Wait for a DynaRec code block to be ready. [Default]
=item B<BOX64_DYNAREC_WEAKBARRIER> =I<0|1|2>
Tweak the memory barriers to reduce the performance impact by strong memory emualtion.
* 0 : Use regular safe barrier.
* 1 : Use weak barriers to have more performance boost. [Default]
* 2 : All in 1, plus disabled the last write barriers.
=item B<BOX64_DYNAREC_X87DOUBLE> =I<0|1>
Force the use of float/double for x87 emulation.
* 0 : Try to use float when possible for x87 emulation. [Default]
* 1 : Only use Double for x87 emulation.
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
Force the use of emulated libraries.
* XXXX : Force the use of emulated library XXXX.
* XXXX:YYYY:ZZZZ : Force the use of emulated libraries XXXX, YYYY and ZZZZ.
=item B<BOX64_ENV> =I<XXXX=yyyy>
Add an environment variable.
* XXXX=yyyy : Add environment variable XXXX with value yyyy.
=item B<BOX64_ENV[1-5]> =I<XXXX=yyyy>
Add an environment variable.
* XXXX=yyyy : Add environment variable XXXX with value yyyy.
=item B<BOX64_EXIT> =I<0|1>
Just exit, do not try to run the program.
* 0 : Does nothing. [Default]
* 1 : Just exit.
=item B<BOX64_FIX_64BIT_INODES> =I<0|1>
Fix 64bit inodes.
* 0 : Do not fix 64bit inodes. [Default]
* 1 : Fix 64bit inodes.
=item B<BOX64_IGNOREINT3> =I<0|1>
Ignore INT3 instructions.
* 0 : Trigger a TRAP signal if a handler is present. [Default]
* 1 : Skip the opcode silently.
=item B<BOX64_INSERT_ARGS> =I<XXXX|XXXX YYYY ZZZZ>
Prepend arguments to the command line.
* XXXX : Prepend argument XXXX to the program.
* XXXX YYYY ZZZZ : Prepend arguments XXXX, YYYY and ZZZZ to the guest program.
=item B<BOX64_INPROCESSGPU> =I<0|1>
Add --in-process-gpu argument to the guest program.
* 0 : Does nothing. [Default]
* 1 : Add --in-process-gpu argument to the guest program.
=item B<BOX64_JITGDB> =I<0|1|2|3>
Launch gdb or not for SIGSEGV, SIGILL, and SIGBUS.
* 0 : Just print the message when the signal is caught. [Default]
* 1 : Launch gdb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting. Inside gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack), then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then `set waiting=0` to exit the infinite loop.
* 2 : Launch gdbserver when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1: 1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with `BOX64_JITGDB=1`.
* 3 : Launch lldb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting.
=item B<BOX64_JVM> =I<0|1>
Detect libjvm and apply conservative settings.
* 0 : Does nothing.
* 1 : Detect libjvm, and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0 when detected. [Default]
=item B<BOX64_LD_LIBRARY_PATH> =I<XXXX>
Path to look for x86_64 libraries.
* XXXX : Add path XXXX to the library path.
=item B<BOX64_LD_PRELOAD> =I<XXXX|XXXX:YYYY>
Force loading libraries with the binary.
* XXXX : Force the loading of library XXXX.
* XXXX:YYYY : Force the loading of libraries XXXX and YYYY.
=item B<BOX64_LIBCEF> =I<0|1>
Detect libcef and apply BOX64_MALLOC_HACK settings.
* 0 : Does nothing.
* 1 : Detect libcef, and apply BOX64_MALLOC_HACK=2 if detected. [Default]
=item B<BOX64_LIBGL> =I<libXXXX|/path/to/libXXXX>
Set the name for libGL.
* libXXXX : Set the name for libGL to libXXXX.
* /path/to/libXXXX : Set the name and path for libGL to /path/to/libXXXX, you can also use SDL_VIDEO_GL_DRIVER.
=item B<BOX64_LOAD_ADDR> =I<0xXXXXXXXX>
Set the address where the program is loaded, only active for PIE guest programs.
* 0xXXXXXXXX : Set the address where the program is loaded.
=item B<BOX64_LOG> =I<0|1|2|3>
Enable or disable Box64 logs.
* 0 : Disable Box64 logs. [Default]
* 1 : Enable minimal Box64 logs.
* 2 : Enable debug level Box64 logs.
* 3 : Enable verbose level Box64 logs.
=item B<BOX64_MALLOC_HACK> =I<0|1|2>
Behaviour when hooking malloc operators.
* 0 : Don't allow malloc operator to be redirected, rewriting code to use regular function. [Default]
* 1 : Allow malloc operator to be redirected.
* 2 : Like 0, but track special mmap/free (some redirected functions are inlined and cannot be redirected).
=item B<BOX64_MAXCPU> =I<0|XXXX>
Maximum CPU cores exposed.
* 0 : Use the actual number of CPU cores. [Default]
* XXXX : Use XXXX CPU cores.
=item B<BOX64_NOBANNER> =I<0|1>
Disable the Box64 banner.
* 0 : Show the Box64 banner. [Default]
* 1 : Do not show the Box64 banner.
=item B<BOX64_NODYNAREC> =I<0xXXXXXXXX-0xYYYYYYYY>
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter.
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where dynablock creation is forbidden (inclusive-exclusive).
=item B<BOX64_NOGTK> =I<0|1>
Do not load wrapped GTK libraries.
* 0 : Load wrapped GTK libraries. [Default]
* 1 : Do not load wrapped GTK libraries.
=item B<BOX64_NOPULSE> =I<0|1>
Do not load PulseAudio libraries (both native and x86_64).
* 0 : Load PulseAudio libraries. [Default]
* 1 : Do not load PulseAudio libraries.
=item B<BOX64_NORCFILES> =I<0|1>
Do not load any rc files.
* 0 : Load rc files. [Default]
* 1 : Do not load any rc files.
=item B<BOX64_NOSANDBOX> =I<0|1>
Add --no-sandbox argument to the guest program.
* 0 : Does nothing. [Default]
* 1 : Add --no-sandbox argument to the guest program.
=item B<BOX64_NOSIGSEGV> =I<0|1>
Disable the handling of SIGSEGV.
* 0 : Let the x86 program set sighandler for SIGSEGV. [Default]
* 1 : Disable the handling of SIGSEGV.
=item B<BOX64_NOSIGILL> =I<0|1>
Disable the handling of SIGILL.
* 0 : Let the x86 program set sighandler for SIGILL. [Default]
* 1 : Disable the handling of SIGILL.
=item B<BOX64_NOVULKAN> =I<0|1>
Do not load Vulkan libraries.
* 0 : Load Vulkan libraries. [Default]
* 1 : Do not load Vulkan libraries, both native and x86_64.
=item B<BOX64_PATH> =I<XXXX>
Path to look for x86_64 binaries.
* XXXX : Add path XXXX to the binary path.
=item B<BOX64_PREFER_EMULATED> =I<0|1>
Prefer emulated libraries over native ones.
* 0 : Prefer native libraries over emulated ones. [Default]
* 1 : Prefer emulated libraries over native ones.
=item B<BOX64_PREFER_WRAPPED> =I<0|1>
Prefer wrapped libs first even if the lib is specified with absolute path.
* 0 : Prefer libs with absolute path over wrapped ones. [Default]
* 1 : Prefer wrapped libs first even if the lib is specified with absolute path.
=item B<BOX64_RCFILE> =I<XXXX>
Path to the rc file to load.
* XXXX : Load the rc file XXXX, default rc files will not be loaded.
=item B<BOX64_RDTSC_1GHZ> =I<0|1>
Use hardware counter for rdtsc if available.
* 0 : Use hardware counter for rdtsc opcode if available. [Default]
* 1 : Use hardware counter for rdtsc if and only if precision is at least 1GHz.
=item B<BOX64_RESERVE_HIGH> =I<0|1>
Reserve high memory area for the program, always enabled on Box32.
* 0 : Do not reserve high memory area for the program. [Default]
* 1 : Reserve high memory area for the program.
=item B<BOX64_ROLLING_LOG> =I<0|1|XXX>
Show last few wrapped function call when a signal is caught.
* 0 : Does nothing. [Default]
* 1 : Show last 16 wrapped function call when a signal is caught.
* XXX : Show last XXX wrapped function call when a signal is caught.
=item B<BOX64_SDL2_JGUID> =I<0|1>
Use a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2.
* 0 : Does nothing. [Default]
* 1 : Use a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2.
=item B<BOX64_SHAEXT> =I<0|1>
Expose SHAEXT (a.k.a. SHA_NI) capabilities.
* 0 : Do not expose SHAEXT capabilities.
* 1 : Expose SHAEXT capabilities. [Default]
=item B<BOX64_SHOWBT> =I<0|1>
Show native and emulated backtrace when a signal is caught.
* 0 : Does nothing. [Default]
* 1 : Show native and emulated backtrace when a signal is caught.
=item B<BOX64_SHOWSEGV> =I<0|1>
Always show SIGSEGV signal detailes.
* 0 : Does nothing. [Default]
* 1 : Always show SIGSEGV signal detailes.
=item B<BOX64_SSE_FLUSHTO0> =I<0|1>
Behaviour of SSE Flush to 0 flags.
* 0 : Just track the flag. [Default]
* 1 : Apply SSE Flush to 0 flag directly.
=item B<BOX64_SSE42> =I<0|1>
Expose SSE4.2 capabilities.
* 0 : Do not expose SSE4.2 capabilities.
* 1 : Expose SSE4.2 capabilities. [Default]
=item B<BOX64_SYNC_ROUNDING> =I<0|1>
Synchronize rounding mode between x86 and native.
* 0 : Do not synchronize rounding mode. [Default]
* 1 : Synchronize rounding mode between x86 and native.
=item B<BOX64_TRACE_COLOR> =I<0|1>
Enable or disable colored trace output.
* 0 : Disable colored trace output. [Default]
* 1 : Enable colored trace output.
=item B<BOX64_TRACE_EMM> =I<0|1>
Enable or disable EMM (i.e. MMX) trace output.
* 0 : Disable EMM trace output. [Default]
* 1 : Enable EMM trace output.
=item B<BOX64_TRACE_FILE> =I<XXXX|XXXX%pid|stderr>
Send all log and trace to a file instead of `stdout`.
* XXXX : Send all log and trace to file XXXX.
* XXXX%pid : Send all log and trace to file XXXX with pid appended.
* stderr : Send all log and trace to `stderr`.
=item B<BOX64_TRACE_INIT> =I<0|1>
Same as BOX64_TRACE but starts the trace immediately.
* 0 : Disable trace output. [Default]
* 1 : Enable trace output. Trace starts before the initialization of dependencies.
=item B<BOX64_TRACE_START> =I<0|1|XXXX>
Start trace after N opcodes executed.
* 0 : Start trace immediately. [Default]
* 1 : Start trace after 1 opcode executed.
* XXXX : Start trace after XXXX opcodes executed.
=item B<BOX64_TRACE_XMM> =I<0|1>
Enable or disable XMM (i.e. SSE) trace output.
* 0 : Disable XMM trace output. [Default]
* 1 : Enable XMM trace output.
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
Only available on box64 build with trace. Adds trace of all instructions executed, along with a register dump.
* 0 : Disable trace output. [Default]
* 1 : Enable trace output.
* symbolname : Enable trace output for `symbolname` only.
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive).
=item B<BOX64_UNITYPLAYER> =I<0|1>
Detect UnityPlayer and apply conservative settings.
* 0 : Does nothing.
* 1 : Detect UnityPlayer, and apply BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
=item B<BOX64_WRAP_EGL> =I<0|1>
Prefer wrapped libs for EGL and GLESv2.
* 0 : Prefer emulated libs for EGL and GLESv2. [Default]
* 1 : Prefer wrapped libs for EGL and GLESv2.
=item B<BOX64_X11GLX> =I<0|1>
Force Xorg GLX extension to be present.
* 0 : Do not force Xorg GLX extension to be present. [Default]
* 1 : Require Xorg GLX extension when using XQueryExtension.
=item B<BOX64_X11SYNC> =I<0|1>
Force synchronized operation on X11 display.
* 0 : Do not force synchronized operation on X11 display. [Default]
* 1 : Force synchronized operation on X11 display.
=item B<BOX64_X11THREADS> =I<0|1>
Call XInitThreads when loading X11. This is mostly for old Loki games with the Loki_Compat library.
* 0 : Do not call XInitThreads. [Default]
* 1 : Call XInitThreads as soon as libX11 is loaded.
=item B<BOX64_X87_NO80BITS> =I<0|1>
Behavoiur of x87 80bits long double.
* 0 : Try to handle 80bits long double as precise as possible. [Default]
* 1 : Use 64bits double for x87.
=back
=cut
-134
View File
@@ -1,134 +0,0 @@
# Usage: python gen.py
import json
import os
from collections import defaultdict
script_dir = os.path.dirname(os.path.abspath(__file__))
usage_file = os.path.join(script_dir, 'usage.json')
with open(usage_file, 'r') as file:
data = json.load(file)
with open(os.path.join(script_dir, '../USAGE.md'), 'w') as md_file:
md_file.write("""<!--- This file is generated by gen.py, do not edit it directly. -->
Usage
----
There are many environment variables to control Box64's behaviour, which will be listed below by category.
### Configuration files
In addition to environment variables, by default, Box64 also looks for 2 places for rcfile: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
Settings priority follows this order (from highest to lowest): `~/.box64rc` > `/etc/box64.box64rc` > environment variables.
Example configuration:
```
[factorio]
BOX64_DYNAREC_SAFEFLAGS=0
BOX64_DYNAREC_BIGBLOCK=2
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
```
This configuration will apply the specified settings application-wide to any executable named `factorio`.
### Advanced usage
1. **Wildcard Matching**
Asterisks (`*`) can be used for basic pattern matching in application names. For instance, `[*setup*]` will match any program containing "setup" in its name. Note this implements simple wildcard matching rather than full regex support.
2. **Custom Configuration File**
The `BOX64_RCFILE` environment variable can specify an alternative configuration file instead of the default `/etc/box64.box64rc`.
3. **Per-File Settings**
Sections starting with `/` apply to specific files. For example:
```
[/d3d9.dll]
BOX64_DYNAREC_SAFEFLAGS=0
```
These settings will only affect the `d3d9.dll` file. This syntax also works for **emulated** Linux libraries, e.g., `[/libstdc++.so.6]`.
----
""")
categories = defaultdict(list)
for entry in data:
categories[entry["category"]].append(entry)
for category, entries in categories.items():
md_file.write(f"## {category}\n\n")
for entry in entries:
md_file.write(f"### {entry['name']}\n\n{entry['description']}\n\n")
for option in entry['options']:
md_file.write(f" * {option['key']}: {option['description']} {"[Default]" if option['default'] else ""}\n")
md_file.write("\n")
with open(os.path.join(script_dir, '../box64.pod'), 'w') as pod_file:
pod_file.write("""=head1 NAME
box64 - Linux Userspace x86_64 Emulator with a twist
=head1 SYNOPSIS
B<box64> [B<--help>] [B<--version>] I<executable>
=head1 DESCRIPTION
B<Box64> lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux
systems, like ARM (host system needs to be 64-bit little-endian). Since B<Box64>
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. B<Box64> integrates with DynaRec (dynamic
recompiler) for the ARM64 platform, providing a speed boost between 5 to 10
times faster than using only the interpreter.
=head1 OPTIONS
=over 8
=item B<-h,--help>
Print box64 help and quit.
=item B<-v,--version>
Print box64 version and quit.
=back
=head1 BRIEF USAGE
There are many environment variables to control B<Box64>'s behaviour. In
addition to environment variables, B<Box64> also looks for 2 places for rcfile:
F</etc/box64.box64rc> and F<~/.box64rc>, in the format of .ini files.
Settings priority: F<~/.box64rc> > F</etc/box64.box64rc> > environment variables.
Example:
[factorio]
BOX64_DYNAREC_SAFEFLAGS=0
BOX64_DYNAREC_BIGBLOCK=2
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
=head1 ENVIRONMENT VARIABLES
=over 8
""")
for entry in data:
pod_file.write(f"\n=item B<{entry['name']}> =I<{ '|'.join(option['key'] for option in entry['options']) }>\n\n{entry['description']}\n\n")
for option in entry['options']:
pod_file.write(f" * {option['key']} : {option['description']} {"[Default]" if option['default'] else ""}\n")
pod_file.write("\n")
pod_file.write("""
=back
=cut
""")
-1605
View File
File diff suppressed because it is too large. Load diff
Regular → Executable
View File
File mode changed.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Regular → Executable
View File
File mode changed.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

-45
View File
@@ -1,45 +0,0 @@
#include "gdbjit.h"
#include <stdio.h>
static char block_name_buffer[16];
static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz)
{
gdbjit_block_t* block = (gdbjit_block_t*)memory;
struct gdb_object* object = cbs->object_open(cbs);
struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, block->filename);
sprintf(block_name_buffer, "%x", block->x64start);
cbs->block_open(cbs, symtab, NULL, block->start, block->end, block_name_buffer);
cbs->line_mapping_add(cbs, symtab, block->nlines, block->lines);
cbs->symtab_close(cbs, symtab);
cbs->object_close(cbs, object);
return GDB_SUCCESS;
}
enum gdb_status unwind_frame(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs)
{
return GDB_SUCCESS;
}
struct gdb_frame_id get_frame_id(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs)
{
struct gdb_frame_id frame = {0xdeadbeef, 0};
return frame;
}
void destroy_reader(struct gdb_reader_funcs* self) {}
__attribute__((visibility("default"))) struct gdb_reader_funcs* gdb_init_reader(void)
{
static struct gdb_reader_funcs funcs = {GDB_READER_INTERFACE_VERSION, NULL, read_debug_info, unwind_frame, get_frame_id, destroy_reader};
return &funcs;
}
__attribute__((visibility("default"))) int plugin_is_GPL_compatible (void)
{
return 0;
}
-31
View File
@@ -1,31 +0,0 @@
#!/bin/bash
# create necessary directories
mkdir -p ~/steam
mkdir -p ~/steam/tmp
cd ~/steam/tmp
# download latest deb and unpack
wget https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb
ar x steam.deb
tar xf data.tar.xz
# remove deb archives, not needed anymore
rm ./*.tar.xz ./steam.deb
# move deb contents to steam folder
mv ./usr/* ../
cd ../ && rm -rf ./tmp/
# create run script
echo '#!/bin/bash
export STEAMOS=1
export STEAM_RUNTIME=1
export DBUS_FATAL_WARNINGS=0
~/steam/bin/steam $@' > steam
# make script executable and move
chmod +x steam
sudo mv steam /usr/local/bin/
echo "Script complete."
+15 -7
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-arm64-git
pkgver=r2431.60c6858
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
@@ -15,22 +15,30 @@ source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-arm64-git}"
cd "$srcdir/${pkgname%-arm64-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-arm64-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "${srcdir}/${pkgname%-arm64-git}/build"
cd "$srcdir/${pkgname%-arm64-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-arm64-git}/build"
cd "$srcdir/${pkgname%-arm64-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
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-arm64-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
conflicts=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-arm64-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-arm64-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=Debug
fi
}
build() {
cd "$srcdir/${pkgname%-arm64-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-arm64-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
}
-36
View File
@@ -1,36 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-asahi-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-asahi-git}-git" "${pkgname%-asahi-git}")
conflicts=("${pkgname%-git}" "${pkgname%-asahi-git}-git" "${pkgname%-asahi-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-asahi-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-asahi-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DM1=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-asahi-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-asahi-git}/build"
make DESTDIR="${pkgdir}/" install
}
-36
View File
@@ -1,36 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-lx2160a-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
conflicts=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-lx2160a-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-lx2160a-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-lx2160a-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-lx2160a-git}/build"
make DESTDIR="${pkgdir}/" install
}
-36
View File
@@ -1,36 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-odroid-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
conflicts=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-odroid-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-odroid-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DODROIDN2=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-odroid-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-odroid-git}/build"
make DESTDIR="${pkgdir}/" install
}
-36
View File
@@ -1,36 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-phytium-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-phytium-git}-git" "${pkgname%-phytium-git}")
conflicts=("${pkgname%-git}" "${pkgname%-phytium-git}-git" "${pkgname%-phytium-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-phytium-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-phytium-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DPHYTIUM=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-phytium-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-phytium-git}/build"
make DESTDIR="${pkgdir}/" install
}
-49
View File
@@ -1,49 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rpi-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
pkgver() {
cd "${srcdir}/${pkgname%-rpi-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rpi-git}"
# Check for Pi version number
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
_piversion=4
elif [[ ${_pimodel} =~ "Raspberry Pi 3" ]]; then
_piversion=3
else
# This RPI is not supported or this device is not a pi.
# We should cancel then the build.
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3 (2/1/0 isn't supported).\033[00m"
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"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DRPI${_piversion}ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-rpi-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-rpi-git}/build"
make DESTDIR="${pkgdir}/" install
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-rk3399-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-rk3399-git}"
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)
}
package() {
cd "$srcdir/${pkgname%-rk3399-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
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-rk3399-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-rk3399-git}"
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=Debug
fi
}
build() {
cd "$srcdir/${pkgname%-rk3399-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-rk3399-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
}
-51
View File
@@ -1,51 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rk3xxx-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
_rkmodel=`tr -d '\0' < /proc/device-tree/compatible`
pkgver() {
cd "${srcdir}/${pkgname%-rk3xxx-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rk3xxx-git}"
# Check for RockChip version number
if [[ ${_rkmodel} =~ "rk3326" ]]; then
_rksuffix=3326
elif [[ ${_rkmodel} =~ "rk3399" ]]; then
_rksuffix=3399
elif [[ ${_rkmodel} =~ "rk3588" ]]; then
_rksuffix=3588
else
# This RKxxxx is not supported or this device is not RockChip based.
# We should cancel then the build.
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RockChip model 3326/3399/3588.\033[00m"
exit 1
fi
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected RockChip verion number is: \033[01;31m${_rksuffix}\033[01m.\033[00m"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DRK${_rksuffix}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
make DESTDIR="${pkgdir}/" install
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rpi-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-rpi-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rpi-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-rpi-git}/build"
make -j$(nproc)
}
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
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rpi-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-rpi-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rpi-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=Debug
fi
}
build() {
cd "$srcdir/${pkgname%-rpi-git}/build"
make -j$(nproc)
}
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
}
-36
View File
@@ -1,36 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rv64-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('riscv64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rv64-git}-git" "${pkgname%-rv64-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rv64-git}-git" "${pkgname%-rv64-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-rv64-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rv64-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DRV64=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-rv64-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-rv64-git}/build"
make DESTDIR="${pkgdir}/" install
}
-36
View File
@@ -1,36 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-sd845-git
pkgver=r2431.60c6858
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
conflicts=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-sd845-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-sd845-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DSD845=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
}
build() {
cd "${srcdir}/${pkgname%-sd845-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-sd845-git}/build"
make DESTDIR="${pkgdir}/" install
}
+15 -7
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-tegra-git
pkgver=r2431.60c6858
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
@@ -15,22 +15,30 @@ source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-tegra-git}"
cd "$srcdir/${pkgname%-tegra-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-tegra-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "${srcdir}/${pkgname%-tegra-git}/build"
cd "$srcdir/${pkgname%-tegra-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-tegra-git}/build"
cd "$srcdir/${pkgname%-tegra-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
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-tegra-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}-git" "${pkgname%-tegra-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-tegra-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-tegra-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DTEGRAX1=1 -DCMAKE_BUILD_TYPE=Debug
fi
}
build() {
cd "$srcdir/${pkgname%-tegra-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-tegra-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
}
+16 -8
View File
@@ -1,10 +1,10 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-x64-git
pkgver=r2431.60c6858
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('x86_64')
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
makedepends=('git' 'cmake' 'make')
@@ -14,22 +14,30 @@ source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "${srcdir}/${pkgname%-x64-git}"
cd "$srcdir/${pkgname%-x64-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-x64-git}"
[[ ! -d ./build ]] && mkdir build
cmake -B build -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "${srcdir}/${pkgname%-x64-git}/build"
cd "$srcdir/${pkgname%-x64-git}/build"
make -j$(nproc)
}
package() {
cd "${srcdir}/${pkgname%-x64-git}/build"
cd "$srcdir/${pkgname%-x64-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
}
+43
View File
@@ -0,0 +1,43 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-x64-git
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
conflicts=("${pkgname%-git}" "${pkgname%-x64-git}-git" "${pkgname%-x64-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-x64-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-x64-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=Debug
fi
}
build() {
cd "$srcdir/${pkgname%-x64-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-x64-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
}
+4 -6
View File
@@ -4,8 +4,6 @@
Just download the `PKGBUILD-<your-platform>` (no need to download the whole repository), go to directory where you downloaded and type:
```sh
mv ./PKGBUILD-<your-platform> ./PKGBUILD
# use the below line if you need a DEBUG build
# sed -i 's/RelWithDebInfo/Debug/g' ./PKGBUILD
cd ..
makepkg -si
```
@@ -14,13 +12,13 @@ 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](../docs/COMPILE.md) except for LARCH64, PPC64LE and SW64.
All specified in [COMPILE.md](../COMPILE.md).
### 3. Any advantages with this solution?
This might give you some advantages like:
### 3. Any advantages with that sollution?
This might give you some advantages like those:
- automatic updates (with some AUR frontends like [`pamac-aur`](https://aur.archlinux.org/packages/pamac-aur/) or [`yay`](https://aur.archlinux.org/packages/yay));
- easily uninstall with `pacman -R` when no needed (no need other scripts nor Makefile to do this);
- your `box64` installation is recognized as a package (where it wasn't when installing with `make install`).
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box64 to .deb or .rpm installer files.
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box64 to .deb or .rpm installer files.
+225 -738
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
Regular → Executable
+3 -17
View File
@@ -11,23 +11,20 @@ endif( NOT TEST_OUTPUT )
if( NOT TEST_REFERENCE )
message( FATAL_ERROR "Require TEST_REFERENCE to be defined" )
endif( NOT TEST_REFERENCE )
if(NOT DEFINED ENV{INTERPRETER})
set(ENV{INTERPRETER} "")
endif()
set(ENV{BOX64_LOG} 0)
set(ENV{BOX64_NOBANNER} 1)
if( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
# we are inside box64 folder
set(ENV{BOX64_LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x64lib)
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x64lib)
else()
# we are inside build folder
set(ENV{BOX64_LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
endif( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
# run the test program, capture the stdout/stderr and the result var
execute_process(
COMMAND $ENV{INTERPRETER} ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
COMMAND ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
OUTPUT_FILE ${TEST_OUTPUT}
ERROR_VARIABLE TEST_ERROR
RESULT_VARIABLE TEST_RESULT
@@ -35,9 +32,6 @@ execute_process(
# if the return value is !=0 bail out
if( TEST_RESULT )
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
endif( TEST_RESULT )
@@ -49,16 +43,8 @@ execute_process(
# again, if return value is !=0 scream and shout
if( TEST_RESULT )
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
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}" )
-342
View File
@@ -1,342 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include "debug.h"
#include "box32.h"
#include "custommem.h"
#include "converter32.h"
#include "khash.h"
KHASH_MAP_INIT_INT64(to, ulong_t);
KHASH_MAP_INIT_INT(from, uintptr_t);
KHASH_MAP_INIT_STR(strings, ptr_t);
static kh_from_t* hash_from = NULL;
static kh_to_t* hash_to = NULL;
#define HASH_MSK 0xf000000f
#define HASH_VAL 0x00ffffff
#define HASH_SHIFT 4
static uint32_t hash_cnt = 1;
static pthread_rwlock_t hash_lock = {0};
static int hash_running = 0;
// locale
static kh_from_t* locale_from = NULL;
static kh_to_t* locale_to = NULL;
static kh_strings_t* const_strings = NULL;
void init_hash_helper() {
hash_from = kh_init(from);
hash_to = kh_init(to);
locale_from = kh_init(from);
locale_to = kh_init(to);
const_strings = kh_init(strings);
pthread_rwlock_init(&hash_lock, NULL);
hash_running = 1;
}
void fini_hash_helper() {
if(!hash_running)
return;
hash_running = 0;
kh_destroy(from, hash_from);
hash_from = NULL;
kh_destroy(to, hash_to);
hash_to = NULL;
hash_cnt = 1;
kh_destroy(from, locale_from);
locale_from = NULL;
kh_destroy(to, locale_to);
locale_to = NULL;
kh_destroy(strings, const_strings); //TODO: does not free memory correctly
const_strings = NULL;
pthread_rwlock_destroy(&hash_lock);
}
// Convert from hash key to original 64bits value
uintptr_t from_hash(ulong_t l) {
// easy case first
if((l&HASH_MSK)!=HASH_MSK) {
return (uintptr_t)l;
}
if(l==0xffffffff) {
return 0xffffffffffffffffll;
}
// get value from hash table second
uintptr_t ret = 0;
if(!hash_running) {
//printf_log(LOG_INFO, "Warning, from_hash used but hash not running\n");
return ret;
}
pthread_rwlock_rdlock(&hash_lock);
khint_t k = kh_get(from, hash_from, l);
if (k==kh_end(hash_from)) {
ret = (uintptr_t)l;
} else {
ret = kh_value(hash_from, k);
}
pthread_rwlock_unlock(&hash_lock);
return ret;
}
// same as from_hash
uintptr_t from_hash_d(ulong_t l) {
return from_hash(l);
}
// Convert from 64bits to hash key, creating it if needed
ulong_t to_hash(uintptr_t p) {
if((p<0x100000000LL) && ((p&HASH_MSK)!=HASH_MSK))
return (ulong_t)p;
if(p==0xffffffffffffffffll) {
return 0xffffffff;
}
ulong_t ret = 0;
if(!hash_running) {
//printf_log(LOG_INFO, "Warning, to_hash used but hash not running\n");
return ret;
}
khint_t k;
pthread_rwlock_rdlock(&hash_lock);
k = kh_get(to, hash_to, p);
if(k==kh_end(hash_to)) {
// create a new key, but need write lock!
pthread_rwlock_unlock(&hash_lock);
pthread_rwlock_wrlock(&hash_lock);
ret = HASH_MSK | (((hash_cnt++)&HASH_VAL)<<HASH_SHIFT);
int r;
k = kh_put(to, hash_to, p, &r);
kh_value(hash_to, k) = ret;
k = kh_put(from, hash_from, ret, &r);
kh_value(hash_from, k) = p;
} else {
ret = kh_value(hash_to, k);
}
pthread_rwlock_unlock(&hash_lock);
return ret;
}
// Convert from 64bits to hash key and delete the entry from both hash table
ulong_t to_hash_d(uintptr_t p) {
if((p<0x100000000LL) && ((p&HASH_MSK)!=HASH_MSK))
return (ulong_t)p;
if(p==0xffffffffffffffffll)
return 0xffffffff;
ulong_t ret = 0;
if(!hash_running) {
//printf_log(LOG_INFO, "Warning, to_hash_d used but hash not running\n");
return ret;
}
khint_t k;
pthread_rwlock_wrlock(&hash_lock);
k = kh_get(to, hash_to, p);
if(k==kh_end(hash_to)) {
/// should this be an assert?
} else {
ret = kh_value(hash_to, k);
// delete both entries
//k = kh_get(to, hash_to, p);
kh_del(to, hash_to, k);
k = kh_get(from, hash_from, ret);
kh_del(from, hash_from, k);
}
pthread_rwlock_unlock(&hash_lock);
return ret;
}
typedef struct struct_locale_s {
void* p0[13]; // struct __locale_data *
void* p1; //const unsigned short int *__ctype_b;
void* p2; //const int *__ctype_tolower;
void* p3; //const int *__ctype_toupper;
void* p4[13]; //const char*
} struct_locale_t;
// not a real structure
#define LOCALE_SIGN 0x54abcd845412LL
typedef struct struct_locale_32_s {
ptr_t p0[13];
ptr_t p1;
ptr_t p2;
ptr_t p3;
ptr_t p4[13];
uint64_t sign;
struct_locale_t* org; // save the orginal locale
// copy of the array, in case some apps use them
unsigned short int type_b[384];
int tolower[384];
int tohigher[384];
} struct_locale_32_t;
void to_struct_locale(ptr_t d, const struct_locale_t *src) {
if (!src) return;
struct_locale_32_t* dest = from_ptrv(d);
// save the original locale
dest->sign = LOCALE_SIGN;
dest->org = (void*)src;
//copy the 2 arrays
for(int i=0; i<13; ++i) {
dest->p0[i] = to_hashv(src->p0[i]);
}
for(int i=0; i<13; ++i) {
dest->p4[i] = to_cstring(src->p4[i]);
}
// copy the 3 ctype int (1st is short int, but int will do)
memcpy(dest->type_b, src->p1-128*sizeof(short), 384*sizeof(short));
memcpy(dest->tolower, src->p2-128*sizeof(int), 384*sizeof(int));
memcpy(dest->tohigher, src->p3-128*sizeof(int), 384*sizeof(int));
dest->p1 = to_ptrv(dest->type_b)+128*sizeof(short);
dest->p2 = to_ptrv(dest->tolower)+128*sizeof(int);
dest->p3 = to_ptrv(dest->tohigher)+128*sizeof(int);
}
void free_struct_locale(const struct_locale_t *src) {
for(int i=0; i<13; ++i) {
to_hash_d((uintptr_t)src->p0[i]);
}
/*for(int i=0; i<13; ++i) {
to_hash_d((uintptr_t)src->p4[i]);
}*/
}
// Convert from locale key to original 64bits value
void* from_locale(ptr_t l) {
// easy case first
if(l < 0x100) {
return from_ptrv(l);
}
if(l == 0xffffffff) {
return (void*)-1;
}
// get value from hash table second
void* ret = 0;
if(!hash_running) {
//printf_log(LOG_INFO, "Warning, from_locale used but hash not running\n");
return ret;
}
struct_locale_32_t* loc = from_ptrv(l);
if(loc->sign==LOCALE_SIGN)
return loc->org;
pthread_rwlock_rdlock(&hash_lock);
khint_t k = kh_get(from, locale_from, l);
if (k==kh_end(locale_from)) {
ret = from_ptrv(l);
} else {
ret = (void*)kh_value(locale_from, k);
}
pthread_rwlock_unlock(&hash_lock);
//from_struct_locale((struct_locale_t*)ret, l);
return ret;
}
// same as from_locale
void* from_locale_d(ptr_t l) {
return from_locale(l);
}
// Convert from 64bits to locale key, creating it if needed
ptr_t to_locale(void* p) {
if((uintptr_t)p < 0x100) {
return to_ptrv(p);
}
if(p == (void*)-1) {
return 0xffffffff;
}
ptr_t ret = 0;
if(!hash_running) {
//printf_log(LOG_INFO, "Warning, to_locale used but hash not running\n");
return ret;
}
khint_t k;
pthread_rwlock_rdlock(&hash_lock);
k = kh_get(to, locale_to, (uintptr_t)p);
int conv = 0;
if(k==kh_end(locale_to)) {
// create a new key, but need write lock!
pthread_rwlock_unlock(&hash_lock);
pthread_rwlock_wrlock(&hash_lock);
// a locale_t is 5 pointer!
void* m = calloc(1, sizeof(struct_locale_32_t)); // the 3 ctype value are also inside the locale struct
ret = to_ptrv(m);
// add to hash maps
int r;
k = kh_put(to, locale_to, (uintptr_t)p, &r);
kh_value(locale_to, k) = ret;
k = kh_put(from, locale_from, ret, &r);
kh_value(locale_from, k) = (uintptr_t)p;
conv = 1;
} else {
ret = kh_value(locale_to, k);
}
pthread_rwlock_unlock(&hash_lock);
if(conv)
to_struct_locale(ret, (struct_locale_t*)p);
return ret;
}
// Convert from 64bits to hash key and delete the entry from both hash table
ptr_t to_locale_d(void* p) {
if((uintptr_t)p < 0x100)
return to_ptrv(p);
ptr_t ret = 0;
if(!hash_running)
return ret;
khint_t k;
pthread_rwlock_wrlock(&hash_lock);
k = kh_get(to, locale_to, (uintptr_t)p);
if(k==kh_end(locale_to)) {
/// should this be an assert?
} else {
ret = kh_value(locale_to, k);
// free the memory
free_struct_locale(p);
free(from_ptrv(ret));
// delete both entries
k = kh_get(to, locale_to, (uintptr_t)p);
kh_del(to, locale_to, k);
k = kh_get(from, locale_from, ret);
kh_del(from, locale_from, k);
}
pthread_rwlock_unlock(&hash_lock);
return ret;
}
char* from_cstring(ptr_t p) {
return (char*)from_ptrv(p);
}
ptr_t to_cstring(char* p) {
if((uintptr_t)p<0x100000000LL)
return to_ptrv(p);
ptr_t ret = 0;
pthread_rwlock_rdlock(&hash_lock);
khint_t k = kh_get(strings, const_strings, p);
if(k==kh_end(const_strings)) {
// create a new key, but need write lock!
pthread_rwlock_unlock(&hash_lock);
pthread_rwlock_wrlock(&hash_lock);
ret = to_ptrv(box32_strdup(p));
int r;
k = kh_put(strings, const_strings, (char*)from_ptrv(ret), &r);
kh_value(const_strings, k) = ret;
} else
ret = kh_value(const_strings, k);
pthread_rwlock_unlock(&hash_lock);
return ret;
}
ptr_t to_cstring_d(char* p) {
if((uintptr_t)p<0x100000000LL)
return to_ptrv(p);
ptr_t ret = 0;
pthread_rwlock_wrlock(&hash_lock);
khint_t k = kh_get(strings, const_strings, p);
if(k==kh_end(const_strings)) {
// assert?
} else {
ret = kh_value(const_strings, k);
kh_del(strings, const_strings, k);
box32_free(from_ptrv(ret));
}
pthread_rwlock_unlock(&hash_lock);
return ret;
}
Regular → Executable
+131 -206
View File
@@ -5,8 +5,10 @@
#include <dlfcn.h>
#include <signal.h>
#include <sys/mman.h>
#include <pthread.h>
#ifdef DYNAREC
#include "dynarec/arm64_lock.h"
#endif
#include "box64context.h"
#include "debug.h"
#include "elfloader.h"
@@ -19,12 +21,6 @@
#include "wrapper.h"
#include "x64emu.h"
#include "signals.h"
#include "gltools.h"
#include "rbtree.h"
#include "dynarec.h"
#ifdef BOX32
#include "box32.h"
#endif
EXPORTDYN
void initAllHelpers(box64context_t* context)
@@ -33,9 +29,6 @@ void initAllHelpers(box64context_t* context)
if(inited)
return;
my_context = context;
#ifdef BOX32
init_hash_helper();
#endif
init_pthread_helper();
init_bridge_helper();
init_signal_helper(context);
@@ -51,9 +44,6 @@ void finiAllHelpers(box64context_t* context)
fini_pthread_helper(context);
fini_signal_helper();
fini_bridge_helper();
#ifdef BOX32
fini_hash_helper();
#endif
fini_custommem_helper(context);
finied = 1;
}
@@ -75,34 +65,24 @@ void free_tlsdatasize(void* p)
if(!p)
return;
tlsdatasize_t *data = (tlsdatasize_t*)p;
actual_free(data->ptr);
actual_free(p);
if(my_context)
pthread_setspecific(my_context->tlskey, NULL);
free(data->tlsdata);
free(p);
}
void x64Syscall(x64emu_t *emu);
void x86Syscall(x64emu_t *emu);
int unlockMutex()
{
int ret = unlockCustommemMutex();
int i;
#ifdef USE_CUSTOM_MUTEX
uint32_t tid = (uint32_t)GetTID();
#define GO(A, B) \
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
if(i) { \
ret|=(1<<B); \
}
#else
#define GO(A, B) \
i = checkUnlockMutex(&A); \
if(i) { \
ret|=(1<<B); \
}
#endif
GO(my_context->mutex_once, 5)
GO(my_context->mutex_once2, 6)
GO(my_context->mutex_trace, 7)
#ifdef DYNAREC
GO(my_context->mutex_dyndump, 8)
@@ -122,8 +102,10 @@ void relockMutex(int locks)
relockCustommemMutex(locks);
#define GO(A, B) \
if(locks&(1<<B)) \
mutex_trylock(&A); \
pthread_mutex_lock(&A); \
GO(my_context->mutex_once, 5)
GO(my_context->mutex_once2, 6)
GO(my_context->mutex_trace, 7)
#ifdef DYNAREC
GO(my_context->mutex_dyndump, 8)
@@ -136,70 +118,44 @@ void relockMutex(int locks)
#undef GO
}
void init_mutexes(box64context_t* context)
static void init_mutexes(box64context_t* context)
{
#ifndef DYNAREC
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&context->mutex_lock, &attr);
pthread_mutex_init(&context->mutex_once, &attr);
pthread_mutex_init(&context->mutex_once2, &attr);
pthread_mutex_init(&context->mutex_trace, &attr);
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_dyndump, &attr);
#else
pthread_mutex_init(&context->mutex_lock, &attr);
#endif
pthread_mutex_init(&context->mutex_tls, &attr);
pthread_mutex_init(&context->mutex_thread, &attr);
pthread_mutex_init(&context->mutex_bridge, &attr);
pthread_mutexattr_destroy(&attr);
#else
#ifdef USE_CUSTOM_MUTEX
native_lock_store(&context->mutex_trace, 0);
native_lock_store(&context->mutex_tls, 0);
native_lock_store(&context->mutex_thread, 0);
native_lock_store(&context->mutex_bridge, 0);
native_lock_store(&context->mutex_dyndump, 0);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&context->mutex_trace, &attr);
pthread_mutex_init(&context->mutex_tls, &attr);
pthread_mutex_init(&context->mutex_thread, &attr);
pthread_mutex_init(&context->mutex_bridge, &attr);
pthread_mutex_init(&context->mutex_dyndump, &attr);
pthread_mutexattr_destroy(&attr);
#endif
pthread_mutex_init(&context->mutex_lock, NULL);
#endif
}
void startMailbox(void);
void haltMailbox(void);
static void atfork_prepare_box64context(void)
{
// semaphores will go in undetermined state
haltMailbox();
}
static void atfork_parent_box64context(void)
{
// reinit mailbox only
init_mutexes(my_context);
startMailbox();
}
static void atfork_child_box64context(void)
{
// (re)init mutex if it was lock before the fork
// reinit mutexes and mailbox
init_mutexes(my_context);
}
void freeCycleLog(box64context_t* ctx)
{
if(BOX64ENV(rolling_log)) {
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
box_free(ctx->log_call[i]);
box_free(ctx->log_ret[i]);
}
box_free(ctx->log_call);
box_free(ctx->log_ret);
ctx->log_call = NULL;
ctx->log_ret = NULL;
}
}
void initCycleLog(box64context_t* context)
{
if(BOX64ENV(rolling_log)) {
context->log_call = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
context->log_ret = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
context->log_call[i] = (char*)box_calloc(256, 1);
context->log_ret[i] = (char*)box_calloc(128, 1);
}
}
startMailbox();
}
EXPORTDYN
@@ -212,49 +168,36 @@ box64context_t *NewBox64Context(int argc)
}
#endif
// init and put default values
box64context_t *context = my_context = (box64context_t*)box_calloc(1, sizeof(box64context_t));
box64context_t *context = my_context = (box64context_t*)calloc(1, sizeof(box64context_t));
initCycleLog(context);
context->deferredInit = 1;
context->deferedInit = 1;
context->sel_serial = 1;
init_custommem_helper(context);
context->maplib = NewLibrarian(context);
context->local_maplib = NewLibrarian(context);
context->maplib = NewLibrarian(context, 1);
context->local_maplib = NewLibrarian(context, 1);
context->versym = NewDictionnary();
context->system = NewBridge();
// Cannot use Bridge name as the map is not initialized yet
// create vsyscall
context->vsyscall = AddBridge(context->system, vFEv, box64_is32bits?x86Syscall:x64Syscall, 0, NULL);
context->vsyscall = AddBridge(context->system, vFEv, x64Syscall, 0, NULL);
// create the vsyscalls
if(box64_is32bits) {
#ifdef BOX32
addAlternate((void*)0xffffe400, from_ptrv(context->vsyscall));
#endif
} else {
context->vsyscalls[0] = AddVSyscall(context->system, 96);
context->vsyscalls[1] = AddVSyscall(context->system, 201);
context->vsyscalls[2] = AddVSyscall(context->system, 309);
// create the alternate to map at address
addAlternate((void*)0xffffffffff600000, (void*)context->vsyscalls[0]);
addAlternate((void*)0xffffffffff600400, (void*)context->vsyscalls[1]);
addAlternate((void*)0xffffffffff600800, (void*)context->vsyscalls[2]);
}
// create exit bridge
context->exit_bridge = AddBridge(context->system, NULL, NULL, 0, NULL);
context->vsyscalls[0] = AddVSyscall(context->system, 96);
context->vsyscalls[1] = AddVSyscall(context->system, 201);
context->vsyscalls[2] = AddVSyscall(context->system, 309);
// create the alternate to map at address
addAlternate((void*)0xffffffffff600000, (void*)context->vsyscalls[0]);
addAlternate((void*)0xffffffffff600400, (void*)context->vsyscalls[1]);
addAlternate((void*)0xffffffffff600800, (void*)context->vsyscalls[2]);
// get handle to box64 itself
#ifndef STATICBUILD
context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
#endif
context->dlprivate = NewDLPrivate();
context->argc = argc;
context->argv = (char**)box_calloc(context->argc+1, sizeof(char*));
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
init_mutexes(context);
pthread_atfork(NULL, NULL, atfork_child_box64context);
pthread_atfork(atfork_prepare_box64context, atfork_parent_box64context, atfork_child_box64context);
pthread_key_create(&context->tlskey, free_tlsdatasize);
@@ -263,35 +206,11 @@ box64context_t *NewBox64Context(int argc)
context->canary[getrand(4)] = 0;
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at FS:0x28, value:%08X\n", *(uint32_t*)context->canary);
// init segments
for(int i=0; i<16; i++) {
context->segtls[i].limit = (uintptr_t)-1LL;
}
context->segtls[10].key_init = 0; // 0x53 selector
context->segtls[10].present = 1;
context->segtls[8].key_init = 0; // 0x43 selector
context->segtls[8].present = 1;
context->segtls[6].key_init = 0; // 0x33 selector
context->segtls[6].present = 1;
context->segtls[5].key_init = 0; // 0x2b selector
context->segtls[5].present = 1;
context->segtls[4].key_init = 0; // 0x23 selector
context->segtls[4].present = 1;
context->segtls[4].is32bits = 1;
context->globdata = NewMapSymbols();
context->uniques = NewMapSymbols();
initAllHelpers(context);
#ifdef DYNAREC
context->db_sizes = rbtree_init("db_sizes");
#endif
return context;
}
void freeALProcWrapper(box64context_t* context);
EXPORTDYN
void FreeBox64Context(box64context_t** context)
{
@@ -301,9 +220,8 @@ void FreeBox64Context(box64context_t** context)
if(--(*context)->forked >= 0)
return;
box64context_t* ctx = *context; // local copy to do the cleaning
box64context_t* ctx = *context; // local copy to do the cleanning
//clean_current_emuthread(); // cleaning main thread seems a bad idea
if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib, NULL);
if(ctx->maplib)
@@ -313,7 +231,7 @@ void FreeBox64Context(box64context_t** context)
for(int i=0; i<ctx->elfsize; ++i) {
FreeElfHeader(&ctx->elfs[i]);
}
box_free(ctx->elfs);
free(ctx->elfs);
FreeCollection(&ctx->box64_path);
FreeCollection(&ctx->box64_ld_lib);
@@ -321,22 +239,20 @@ void FreeBox64Context(box64context_t** context)
// stop trace now
if(ctx->dec)
DeleteX64TraceDecoder(&ctx->dec);
if(ctx->dec32)
DeleteX86TraceDecoder(&ctx->dec32);
if(ctx->zydis)
DeleteX64Trace(ctx);
if(ctx->deferredInitList)
box_free(ctx->deferredInitList);
if(ctx->deferedInitList)
free(ctx->deferedInitList);
/*box_free(ctx->argv);*/
free(ctx->argv);
/*for (int i=0; i<ctx->envc; ++i)
box_free(ctx->envv[i]);
box_free(ctx->envv);*/
for (int i=0; i<ctx->envc; ++i)
free(ctx->envv[i]);
free(ctx->envv);
if(ctx->atfork_sz) {
box_free(ctx->atforks);
free(ctx->atforks);
ctx->atforks = NULL;
ctx->atfork_sz = ctx->atfork_cap = 0;
}
@@ -352,104 +268,64 @@ void FreeBox64Context(box64context_t** context)
FreeDLPrivate(&ctx->dlprivate);
box_free(ctx->fullpath);
box_free(ctx->box64path);
box_free(ctx->bashpath);
free(ctx->fullpath);
free(ctx->box64path);
FreeBridge(&ctx->system);
#ifndef STATICBUILD
freeGLProcWrapper(ctx);
freeALProcWrapper(ctx);
#ifdef BOX32
#endif
#endif
if(ctx->stack_clone)
box_free(ctx->stack_clone);
void* ptr;
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
free_tlsdatasize(ptr);
pthread_setspecific(ctx->tlskey, NULL);
}
pthread_key_delete(ctx->tlskey);
if(ctx->tlsdata)
box_free(ctx->tlsdata);
free(ctx->tlsdata);
free_neededlib(ctx->neededlibs);
ctx->neededlibs = NULL;
pthread_mutex_destroy(&ctx->mutex_once);
pthread_mutex_destroy(&ctx->mutex_once2);
pthread_mutex_destroy(&ctx->mutex_trace);
#ifdef DYNAREC
pthread_mutex_destroy(&ctx->mutex_dyndump);
#else
pthread_mutex_destroy(&ctx->mutex_lock);
#endif
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
pthread_mutex_destroy(&ctx->mutex_bridge);
free_neededlib(&ctx->neededlibs);
if(ctx->emu_sig)
FreeX64Emu(&ctx->emu_sig);
FreeMapSymbols(&ctx->globdata);
FreeMapSymbols(&ctx->uniques);
#ifdef DYNAREC
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, righter=%d\n", ctx->max_db_size, rb_get_righter(ctx->db_sizes));
rbtree_delete(ctx->db_sizes);
#endif
finiAllHelpers(ctx);
#ifdef DYNAREC
pthread_mutex_destroy(&ctx->mutex_lock);
#else
pthread_mutex_destroy(&ctx->mutex_trace);
pthread_mutex_destroy(&ctx->mutex_lock);
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
pthread_mutex_destroy(&ctx->mutex_bridge);
#endif
freeCycleLog(ctx);
box_free(ctx);
free(ctx);
}
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
int idx = 0;
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
if(idx == ctx->elfsize) {
if(idx==ctx->elfcap) {
// resize...
ctx->elfcap += 16;
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
}
ctx->elfs[idx] = head;
ctx->elfsize++;
} else {
ctx->elfs[idx] = head;
int idx = ctx->elfsize;
if(idx==ctx->elfcap) {
// resize...
ctx->elfcap += 16;
ctx->elfs = (elfheader_t**)realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
}
ctx->elfs[idx] = head;
ctx->elfsize++;
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
return idx;
}
void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
if(GetTLSBase(head)) {
// should remove the tls info
int tlsbase = GetTLSBase(head);
/*if(tlsbase == -ctx->tlssize) {
// not really correct, but will do for now
ctx->tlssize -= GetTLSSize(head);
if(!(++ctx->sel_serial))
++ctx->sel_serial;
}*/
}
for(int i=0; i<ctx->elfsize; ++i)
if(ctx->elfs[i] == head) {
ctx->elfs[i] = NULL;
return;
}
}
int AddTLSPartition(box64context_t* context, int tlssize) {
int oldsize = context->tlssize;
// should in fact first try to map a hole, but rewinding all elfs and checking filled space, like with the mapmem utilities
context->tlssize += tlssize;
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
context->tlsdata = realloc(context->tlsdata, context->tlssize);
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
// clean GS segment for current emu
@@ -462,3 +338,52 @@ int AddTLSPartition(box64context_t* context, int tlssize) {
return -context->tlssize; // negative offset
}
void add_neededlib(needed_libs_t* needed, library_t* lib)
{
if(!needed)
return;
for(int i=0; i<needed->size; ++i)
if(needed->libs[i] == lib)
return;
if(needed->size == needed->cap) {
needed->cap += 8;
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
}
needed->libs[needed->size++] = lib;
}
void free_neededlib(needed_libs_t* needed)
{
if(!needed)
return;
needed->cap = 0;
needed->size = 0;
if(needed->libs)
free(needed->libs);
needed->libs = NULL;
}
void add_dependedlib(needed_libs_t* depended, library_t* lib)
{
if(!depended)
return;
for(int i=0; i<depended->size; ++i)
if(depended->libs[i] == lib)
return;
if(depended->size == depended->cap) {
depended->cap += 8;
depended->libs = (library_t**)realloc(depended->libs, depended->cap*sizeof(library_t*));
}
depended->libs[depended->size++] = lib;
}
void free_dependedlib(needed_libs_t* depended)
{
if(!depended)
return;
depended->cap = 0;
depended->size = 0;
if(depended->libs)
free(depended->libs);
depended->libs = NULL;
}
Regular → Executable
+2 -2
View File
@@ -2,7 +2,7 @@
#define __BOX64_VERSION_H_
#define BOX64_MAJOR 0
#define BOX64_MINOR 3
#define BOX64_REVISION 4
#define BOX64_MINOR 1
#define BOX64_REVISION 5
#endif //__BOX64_VERSION_H_
Regular → Executable
+1 -1
View File
@@ -9,7 +9,7 @@
void PrintBox64Version()
{
printf_ftrace(1, "Box64%s%s v%d.%d.%d %s built on %s %s\n",
printf("Box64%s%s v%d.%d.%d %s built on %s %s\n",
#ifdef HAVE_TRACE
" with trace",
#else
Regular → Executable
+1 -16
View File
@@ -1,21 +1,6 @@
#include "box64version.h"
#ifdef NOGIT
#define GITREV "nogit"
#else
#include "git_head.h"
#endif
#ifndef __BUILD_INFO_H__
#define __BUILD_INFO_H__
void PrintBox64Version(void);
#define BOX64_BUILD_INFO_STR_HELPER(x) #x
#define BOX64_BUILD_INFO_STR(x) BOX64_BUILD_INFO_STR_HELPER(x)
#define BOX64_BUILD_INFO_STRING \
"Box64" \
" v" BOX64_BUILD_INFO_STR(BOX64_MAJOR) "." BOX64_BUILD_INFO_STR(BOX64_MINOR) "." BOX64_BUILD_INFO_STR(BOX64_REVISION) \
" " GITREV
void PrintBox64Version();
#endif //__BUILD_INFO_H__
-1577
View File
File diff suppressed because it is too large. Load diff
+821 -1840
View File
File diff suppressed because it is too large. Load diff
-56
View File
@@ -1,56 +0,0 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <stdint.h>
#include "env.h"
#ifndef MAP_FAILED
#define MAP_FAILED ((void *) -1)
#endif
#define EXPORT __attribute__((visibility("default")))
#ifdef BUILD_DYNAMIC
#define EXPORTDYN __attribute__((visibility("default")))
#else
#define EXPORTDYN
#endif
#ifndef MAP_32BIT
#define MAP_32BIT 0x40
#endif
typedef void x64emu_t;
extern void* mapallmem;
extern int box64_is32bits;
void setProtection(uintptr_t addr, size_t size, uint32_t prot);
void freeProtection(uintptr_t addr, size_t size);
void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
int internal_munmap(void* addr, unsigned long length);
void* box_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
extern int running32bits;
extern box64env_t box64env;
EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
{
void* ret;
if(!addr && ((running32bits && BOX64ENV(mmap32)) || (flags&MAP_32BIT) || box64_is32bits))
ret = box_mmap(addr, length, prot, flags | MAP_32BIT, fd, offset);
else
ret = internal_mmap(addr, length, prot, flags, fd, offset);
if(ret!=MAP_FAILED && mapallmem)
setProtection((uintptr_t)ret, length, prot);
return ret;
}
EXPORT void* mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset) __attribute__((alias("mmap64")));
EXPORT int munmap(void* addr, unsigned long length)
{
int ret = internal_munmap(addr, length);
if(!ret && mapallmem) {
freeProtection((uintptr_t)addr, length);
}
return ret;
}
-88
View File
@@ -1,88 +0,0 @@
#include <stdint.h>
#include "arm64_immenc.h"
#define one (uint64_t)1
// Returns the packed valid-N-imms-immr (1-1-6-6 bits); returns 0 if bitmask is not encodable
int convert_bitmask(uint64_t bitmask) {
if (bitmask == 0 || bitmask == ~0ULL) return 0;
uint64_t size, mask, pat;
for (size = 6; size > 1; --size) {
mask = (one << (1 << (size - 1))) - 1;
pat = bitmask & mask;
if (pat != ((bitmask >> (1 << (size - 1))) & mask)) {
break;
}
}
mask = (size >= 6) ? ~0ULL : ((one << (1 << size)) - 1);
pat = bitmask & mask;
for (uint64_t i = 1; i < 7 - size; ++i) {
uint64_t boff = i * (1 << size);
if (((bitmask >> boff) & mask) != pat) {
return 0;
}
}
int immr = 0;
uint64_t last_bit = one << ((1 << size) - 1);
if (pat & 1) {
while (pat & last_bit) {
pat = ((pat - last_bit) << 1) | 1;
++immr;
}
} else {
immr = 1 << size;
while (!(pat & 1)) {
pat >>= 1;
--immr;
}
}
if (pat & (pat + 1)) return 0;
int to = 1;
while (pat & (one << to)) ++to;
return 0x2000 + ((size == 6) << 12) + ((((0x1E << size) & 0x3F) + (to - 1)) << 6) + immr;
}
#if 0
#include <unordered_set>
int main() {
std::unordered_set<uint64_t> okvals;
uint64_t val;
for (int n = 1; n < 7; ++n) {
int imms0 = ((n == 6) ? 0xC0 : 0x80) + ((0x1E << n) & 0x3F);
for (int nones = 0; nones < (1 << n) - 1; ++nones) {
val = (one << (nones + 1)) - 1;
for (int j = 0; j < 6 - n; ++j) {
val += val << (1 << (n + j));
}
for (int immr = 0; immr < (1 << n); ++immr) {
int exp = ((imms0 + nones) << 6) + immr;
int got = convert_bitmask(val);
if (exp != got) {
printf("0x%016lX: expected %04X, got %04X\n", val, exp, got);
}
okvals.emplace(val);
val = (val >> 1) | ((val & 1) << 63);
}
}
}
#pragma omp parallel for
for (uint64_t i = 1; i < 0xFFFFFFFFFFFFFFFFu; ++i) {
int got = convert_bitmask(i);
if (!!got != (okvals.find(i) != okvals.cend())) {
printf("0x%016lX: expected %s, got %04X\n", i, (!!got ? "non0" : "0000"), got);
}
}
}
#endif
-8
View File
@@ -1,8 +0,0 @@
#ifndef __ARM64_IMMENC_H__
#define __ARM64_IMMENC_H__
#include <stdint.h>
int convert_bitmask(uint64_t bitmask);
#endif // __ARM64_IMMENC_H__
-277
View File
@@ -1,277 +0,0 @@
//arm lock helper
//there is 2 part: read and write
// write return 0 on success, 1 on fail (value has been changed)
.text
.align 4
.global arm64_lock_read_b
.global arm64_lock_write_b
.global arm64_lock_read_h
.global arm64_lock_write_h
.global arm64_lock_read_d
.global arm64_lock_write_d
.global arm64_lock_read_dd
.global arm64_lock_write_dd
.global arm64_lock_read_dq
.global arm64_lock_write_dq
.global arm64_lock_xchg_dd
.global arm64_lock_xchg_d
.global arm64_lock_xchg_h
.global arm64_lock_xchg_b
.global arm64_lock_storeifnull
.global arm64_lock_storeifnull_d
.global arm64_lock_storeifref
.global arm64_lock_storeifref_d
.global arm64_lock_storeifref2_d
.global arm64_lock_decifnot0b
.global arm64_lock_storeb
.global arm64_lock_incif0
.global arm64_lock_decifnot0
.global arm64_lock_store
.global arm64_lock_store_dd
.global arm64_lock_get_b
.global arm64_lock_get_d
.global arm64_lock_get_dd
arm64_lock_read_b:
dmb ish
// address is x0, return is x0
ldaxrb w0, [x0]
ret
arm64_lock_write_b:
// address is x0, value is x1, return is x0
mov x2, x0
stlxrb w0, w1, [x2]
dmb ish
ret
arm64_lock_read_h:
dmb ish
// address is x0, return is x0
ldaxrh w0, [x0]
ret
arm64_lock_write_h:
// address is x0, value is x1, return is x0
mov x2, x0
stlxrh w0, w1, [x2]
dmb ish
ret
arm64_lock_read_d:
dmb ish
// address is x0, return is x0
ldaxr w0, [x0]
ret
arm64_lock_write_d:
// address is x0, value is w1, return is x0
mov x2, x0
stlxr w0, w1, [x2]
dmb ish
ret
arm64_lock_read_dd:
dmb ish
// address is x0, return is x0
ldaxr x0, [x0]
ret
arm64_lock_write_dd:
// address is x0, value is x1, return is x0
mov x2, x0
stlxr w0, x1, [x2]
dmb ish
ret
arm64_lock_read_dq:
dmb ish
// address is r2, return is r0, r1
ldaxp x4, x3, [x2]
str x4, [x0]
str x3, [x1]
ret
arm64_lock_write_dq:
// address is r2, value is r0, r1, return is r0
// r0 needs to be aligned
stlxp w3, x0, x1, [x2]
mov w0, w3
dmb ish
ret
arm64_lock_xchg_dd:
dmb ish
arm64_lock_xchg_dd_0:
// address is x0, value is x1, return old value in x0
ldaxr x2, [x0]
stlxr w3, x1, [x0]
cbnz w3, arm64_lock_xchg_dd_0
mov x0, x2
ret
arm64_lock_xchg_d:
dmb ish
arm64_lock_xchg_d_0:
// address is x0, value is x1, return old value in x0
ldaxr w2, [x0]
stlxr w3, w1, [x0]
cbnz w3, arm64_lock_xchg_d_0
mov w0, w2
ret
arm64_lock_xchg_h:
dmb ish
arm64_lock_xchg_h_0:
// address is x0, value is x1, return old value in x0
ldaxrh w2, [x0]
stlxrh w3, w1, [x0]
cbnz w3, arm64_lock_xchg_h_0
mov w0, w2
ret
arm64_lock_xchg_b:
dmb ish
arm64_lock_xchg_b_0:
// address is x0, value is x1, return old value in x0
ldaxrb w2, [x0]
stlxrb w3, w1, [x0]
cbnz w3, arm64_lock_xchg_b_0
mov w0, w2
ret
arm64_lock_storeifnull:
dmb ish
1:
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
ldaxr x2, [x0]
cbnz x2, 2f
stlxr w3, x1, [x0]
cbnz w3, 1b
2:
mov x0, x2
ret
arm64_lock_storeifnull_d:
dmb ish
1:
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
ldaxr w2, [x0]
cbnz w2, 2f
stlxr w3, w1, [x0]
cbnz w3, 1b
2:
dmb ish
mov w0, w2
ret
arm64_lock_storeifref:
dmb ish
1:
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
ldaxr x3, [x0]
cmp x2, x3
bne 2f
stlxr w4, x1, [x0]
cbnz w4, 1b
mov x0, x1
ret
2:
mov x0, x3
ret
arm64_lock_storeifref_d:
dmb ish
1:
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so x1 or old value)
ldaxr w3, [x0]
cmp w2, w3
bne 2f
stlxr w4, w1, [x0]
cbnz w4, 1b
mov w0, w1
ret
2:
mov w0, w3
ret
arm64_lock_storeifref2_d:
dmb ish
1:
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
ldaxr w3, [x0]
cmp w2, w3
bne 2f
stlxr w4, w1, [x0]
cbnz w4, 1b
2:
mov w0, w3
ret
arm64_lock_decifnot0b:
dmb ish
1:
ldaxrb w1, [x0]
cmp w1, #0
beq 2f
sub w1, w1, #1
stlxrb w2, w1, [x0]
cbnz w2, 1b
2:
ret
arm64_lock_storeb:
strb w1, [x0]
dmb ish
ret
arm64_lock_decifnot0:
dmb ish
1:
ldaxr w1, [x0]
cmp w1, #0
beq 2f
sub w3, w1, #1
stlxr w2, w3, [x0]
cbnz w2, 1b
2:
mov w0, w1
ret
arm64_lock_incif0:
dmb ish
1:
ldaxr w1, [x0]
cmp w1, #0
bne 2f
add w3, w1, #1
stlxr w2, w3, [x0]
cbnz w2, 1b
2:
mov w0, w1
ret
arm64_lock_store:
str w1, [x0]
dmb ish
ret
arm64_lock_store_dd:
str x1, [x0]
dmb ish
ret
arm64_lock_get_b:
ldaxrb w0, [x0]
ret
arm64_lock_get_d:
ldaxr w0, [x0]
ret
arm64_lock_get_dd:
ldaxr x0, [x0]
ret
-84
View File
@@ -1,84 +0,0 @@
#ifndef __ARM64_LOCK__H__
#define __ARM64_LOCK__H__
#include <stdint.h>
// LDAXRB of ADDR
extern uint8_t arm64_lock_read_b(void* addr);
// STLXRB of ADDR, return 0 if ok, 1 if not
extern int arm64_lock_write_b(void* addr, uint8_t val);
// LDAXRH of ADDR
extern uint16_t arm64_lock_read_h(void* addr);
// STLXRH of ADDR, return 0 if ok, 1 if not
extern int arm64_lock_write_h(void* addr, uint16_t val);
// LDAXR of ADDR
extern uint32_t arm64_lock_read_d(void* addr);
// STLXR of ADDR, return 0 if ok, 1 if not
extern int arm64_lock_write_d(void* addr, uint32_t val);
// LDAXR of ADDR
extern uint64_t arm64_lock_read_dd(void* addr);
// STLXR of ADDR, return 0 if ok, 1 if not
extern int arm64_lock_write_dd(void* addr, uint64_t val);
// LDAXRD of ADDR
extern void arm64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
// STLXRD of ADDR, return 0 if ok, 1 if not
extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
// Atomically exchange value at [p] with val, return old p
extern uintptr_t arm64_lock_xchg_dd(void* p, uintptr_t val);
// Atomically exchange value at [p] with val, return old p
extern uint32_t arm64_lock_xchg_d(void* p, uint32_t val);
// Atomically exchange value at [p] with val, return old p
extern uint32_t arm64_lock_xchg_h(void* p, uint32_t val);
// Atomically exchange value at [p] with val, return old p
extern uint32_t arm64_lock_xchg_b(void* p, uint32_t val);
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
extern uint32_t arm64_lock_storeifnull_d(void*p, uint32_t val);
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
extern void* arm64_lock_storeifnull(void*p, void* val);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern uint32_t arm64_lock_storeifref_d(void*p, uint32_t val, uint32_t ref);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern uint32_t arm64_lock_storeifref2_d(void*p, uint32_t val, uint32_t ref);
// decrement atomically the byte at [p] (but only if p not 0)
extern void arm64_lock_decifnot0b(void*p);
// atomic store (with memory barrier)
extern void arm64_lock_storeb(void*p, uint8_t b);
// increment atomically the int at [p] only if it was 0. Return the old value of [p]
extern int arm64_lock_incif0(void*p);
// decrement atomically the int at [p] (but only if p not 0)
extern int arm64_lock_decifnot0(void*p);
// atomic store (with memory barrier)
extern void arm64_lock_store(void*p, uint32_t v);
// atomic store (with memory barrier)
extern void arm64_lock_store_dd(void*p, uint64_t v);
// atomic get (with memory barrier)
extern uint8_t arm64_lock_get_b(void*p);
// atomic get (with memory barrier)
extern uint32_t arm64_lock_get_d(void*p);
// atomic get (with memory barrier)
extern void* arm64_lock_get_dd(void*p);
#endif //__ARM64_LOCK__H__
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-278
View File
@@ -1,278 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop;
uint8_t gd, ed, wb1, wback;
int64_t j64;
int16_t i16;
int v0, v1;
int64_t fixedaddress;
int unscaled;
MAYUSE(j64);
GETREX();
/*if(rex.w && opcode!=0x0f) { // rex.w cancels "66", but not for 66 0f type of prefix
MESSAGE(LOG_DUMP, "Here!\n");
return dynarec64_64(dyn, addr-2, ip, ninst, rex, rep, ok, need_epilog);
}*/
switch(opcode) {
case 0x0F:
opcode = F8;
switch(opcode) {
case 0x2E:
// no special check...
case 0x2F:
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
ADDz_REG(x4, x4, ed);
ed = x4;
v1 = fpu_get_scratch(dyn, ninst);
VLD64(v1, ed, fixedaddress);
}
FCMPD(v0, v1);
FCOMI(x1, x2);
break;
case 0x6F:
INST_NAME("MOVDQA Gx,Ex");
nextop = F8;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX_empty(v0);
VMOVQ(v0, v1);
} else {
GETGX_empty(v0);
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
SMREAD();
ADDz_REG(x4, x4, ed);
ed = x4;
VLD128(v0, ed, fixedaddress);
}
break;
case 0x7F:
INST_NAME("MOVDQA Ex,Gx");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
VMOVQ(v1, v0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
ADDz_REG(x4, x4, ed);
ed = x4;
VST128(v0, ed, fixedaddress);
SMWRITE2();
}
break;
case 0xD6:
INST_NAME("MOVQ Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
FMOVD(v1, v0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
ADDz_REG(x4, x4, ed);
ed = x4;
VST64(v0, ed, fixedaddress);
SMWRITE();
}
break;
default:
DEFAULT;
}
break;
case 0x83:
nextop = F8;
switch((nextop>>3)&7) {
case 0: //ADD
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOVZw(x5, i16);
emit_add16(dyn, ninst, ed, x5, x2, x4);
EWBACK;
break;
case 1: //OR
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_or16c(dyn, ninst, x1, i16, x2, x4);
EWBACK;
break;
case 2: //ADC
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOVZw(x5, i16);
emit_adc16(dyn, ninst, x1, x5, x2, x4);
EWBACK;
break;
case 3: //SBB
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOVZw(x5, i16);
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
EWBACK;
break;
case 4: //AND
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_and16c(dyn, ninst, x1, i16, x2, x4);
EWBACK;
break;
case 5: //SUB
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOVZw(x5, i16);
emit_sub16(dyn, ninst, x1, x5, x2, x4);
EWBACK;
break;
case 6: //XOR
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_xor16c(dyn, ninst, x1, i16, x2, x4);
EWBACK;
break;
case 7: //CMP
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
GETEWO(x1, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(i16) {
MOVZw(x2, i16);
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
} else
emit_cmp16_0(dyn, ninst, x1, x3, x4);
break;
}
break;
case 0x89:
INST_NAME("MOV FS:Ew, Gw");
nextop = F8;
GETGD; // don't need GETGW here
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
if(rex.w) {
MOVx_REG(ed, gd);
} else {
if(ed!=gd) {
BFIx(ed, gd, 0, 16);
}
}
} else {
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(rex.w?3:1), rex.w?7:1, rex, NULL, 0, 0);
ADDz_REG(x4, x4, ed);
ed = x4;
if(rex.w) {
STx(gd, ed, fixedaddress);
} else {
STH(gd, ed, fixedaddress);
}
SMWRITE();
}
break;
case 0x8B:
INST_NAME("MOV Gw, FS:Ew");
nextop=F8;
GETGD;
if(MODREG) { // reg <= reg
ed = TO_NAT((nextop & 7) + (rex.b << 3));
if(rex.w) {
MOVx_REG(gd, ed);
} else {
if(ed!=gd) {
BFIx(gd, ed, 0, 16);
}
}
} else { // mem <= reg
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(rex.w?3:1), rex.w?7:1, rex, NULL, 0, 0);
ADDz_REG(x4, x4, ed);
ed = x4;
if(rex.w) {
LDx(gd, ed, fixedaddress);
} else {
LDH(x1, ed, fixedaddress);
BFIx(gd, x1, 0, 16);
}
}
break;
default:
DEFAULT;
}
return addr;
}
-633
View File
@@ -1,633 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
{
(void)ip; (void)rep; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop;
uint8_t gd, ed, u8;
uint8_t wback, wb1, wb2, gb1, gb2;
int16_t i16;
int64_t i64, j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(j64);
while((opcode==0xF2) || (opcode==0xF3)) {
rep = opcode-0xF1;
opcode = F8;
}
GETREX();
switch(opcode) {
case 0x01:
INST_NAME("LOCK ADD Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x5);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_add16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
UFLAG_IF {
LDADDALH(x5, x1, wback);
emit_add16(dyn, ninst, x1, x5, x3, x4);
} else {
STADDLH(x5, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
emit_add16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 0x09:
INST_NAME("LOCK OR Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x5);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_or16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
UFLAG_IF {
LDSETALH(x5, x1, wback);
emit_or16(dyn, ninst, x1, x5, x3, x4);
} else {
STSETLH(x5, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
emit_or16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 0x0F:
opcode = F8;
switch(opcode) {
case 0xB1:
INST_NAME("LOCK CMPXCHG Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
UXTHw(x6, xRAX);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
UXTHw(x1, ed);
CMPSxw_REG(x6, x1);
B_MARK(cNE);
BFIx(ed, gd, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(!ALIGNED_ATOMICH) {
if(arm64_uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
CMPSw_U12(x1, 0xF);
B_MARK3(cGE);
} else {
TSTx_mask(wback, 1, 0, 0); // mask=1
B_MARK3(cNE);
}
}
// Aligned version
if(arm64_atomics) {
MOVw_REG(x1, x6);
CASALH(x1, gd, wback);
} else {
MARKLOCK;
LDAXRH(x1, wback);
CMPSw_REG(x6, x1);
B_MARK(cNE);
// EAX == Ed
STLXRH(x4, gd, wback);
CBNZx_MARKLOCK(x4);
// done
}
if(!ALIGNED_ATOMICH) {
B_MARK_nocond;
// Unaligned version
MARK3;
LDRH_U12(x1, wback, 0);
LDAXRB(x3, wback); // dummy read, to arm the write...
SUBw_UXTB(x3, x3, x1);
CBNZw_MARK3(x3);
CMPSw_REG(x6, x1);
B_MARK(cNE);
// EAX == Ed
STLXRB(x4, gd, wback);
CBNZx_MARK3(x4);
STRH_U12(gd, wback, 0);
}
}
MARK;
SMDMB();
// Common part (and fallback for EAX != Ed)
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
BFIx(xRAX, x1, 0, 16);
break;
case 0xC1:
INST_NAME("LOCK XADD Gw, Ew");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
UXTHx(x5, gd);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
BFIx(gd, ed, 0, 16);
emit_add16(dyn, ninst, x5, gd, x3, x4);
BFIx(ed, x5, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
LDADDALH(x5, x1, wback);
} else {
MARKLOCK;
LDAXRH(x1, wback);
ADDxw_REG(x4, x1, x5);
STLXRH(x3, x4, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
IFX(X_ALL|X_PEND) {
MOVxw_REG(x2, x1);
emit_add16(dyn, ninst, x2, x5, x3, x4);
}
BFIx(gd, x1, 0, 16);
}
break;
default:
DEFAULT;
}
break;
case 0x11:
INST_NAME("LOCK ADC Ew, Gw");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x5);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_adc16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MARKLOCK;
LDAXRH(x1, wback);
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
break;
case 0x21:
INST_NAME("LOCK AND Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x5);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_and16(dyn, ninst, x6, gd, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
MVNw_REG(x3, gd);
UFLAG_IF {
LDCLRALH(x3, x1, wback);
emit_and16(dyn, ninst, x1, gd, x3, x4);
} else {
STCLRLH(x3, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
emit_and16(dyn, ninst, x1, gd, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 0x81:
case 0x83:
nextop = F8;
switch((nextop>>3)&7) {
case 0: //ADD
if(opcode==0x81) {
INST_NAME("LOCK ADD Ew, Iw");
} else {
INST_NAME("LOCK ADD Ew, Ib");
}
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MOV32w(x5, i16);
UXTHw(x6, ed);
emit_add16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
if(!ALIGNED_ATOMICH) {
if(arm64_uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
CMPSw_U12(x1, 0xF);
B_MARK(cGE);
} else {
TSTx_mask(wback, 1, 0, 0); // mask=1
B_MARK(cNE);
}
}
if(arm64_atomics) {
UFLAG_IF {
LDADDALH(x5, x1, wback);
} else {
STADDLH(x5, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
ADDw_REG(x4, x1, x5);
STLXRH(x3, x4, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
if(!ALIGNED_ATOMICH) {
B_MARK2_nocond;
MARK; // unaligned! also, not enough
LDRH_U12(x1, wback, 0);
LDAXRB(x4, wback);
SUBw_UXTB(x4, x4, x1);
CBNZw_MARK(x4);
ADDw_REG(x4, x1, x5);
STLXRB(x3, x4, wback);
CBNZx_MARK(x3);
STRH_U12(x4, wback, 0); // put the whole value
SMDMB();
}
MARK2;
UFLAG_IF {
emit_add16(dyn, ninst, x1, x5, x3, x4);
}
}
break;
case 1: //OR
if(opcode==0x81) {INST_NAME("LOCK OR Ew, Iw");} else {INST_NAME("LOCK OR Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_or16c(dyn, ninst, x6, i16, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(!i64) {MOV32w(x5, i16);}
if(arm64_atomics) {
UFLAG_IF {
LDSETALH(x5, x1, wback);
emit_or16c(dyn, ninst, x1, i16, x3, x4);
} else {
STSETLH(x5, wback);
}
} else {
i64 = convert_bitmask_w(i16);
if(!i64) {MOV32w(x5, i16);}
MARKLOCK;
LDAXRH(x1, wback);
if(i64) {
emit_or16c(dyn, ninst, x1, i16, x3, x4);
} else {
emit_or16(dyn, ninst, x1, x5, x3, x4);
}
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 2: //ADC
if(opcode==0x81) {INST_NAME("LOCK ADC Ew, Iw");} else {INST_NAME("LOCK ADC Ew, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MOV32w(x5, i16);
UXTHw(x6, ed);
emit_adc16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
MARKLOCK;
LDAXRH(x1, wback);
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
break;
case 3: //SBB
if(opcode==0x81) {INST_NAME("LOCK SBB Ew, Iw");} else {INST_NAME("LOCK SBB Ew, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MOV32w(x5, i16);
UXTHw(x6, ed);
emit_sbb16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
MARKLOCK;
LDAXRH(x1, wback);
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
break;
case 4: //AND
if(opcode==0x81) {INST_NAME("LOCK AND Ew, Iw");} else {INST_NAME("LOCK AND Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_and16c(dyn, ninst, x6, i16, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
i64 = convert_bitmask_w(i16);
if(arm64_atomics) {
MOV32w(x5, ~i16);
UFLAG_IF {
LDCLRALH(x5, x1, wback);
if(i64) {
emit_and16c(dyn, ninst, x1, i16, x3, x4);
} else {
MVNw_REG(x5, x5);
emit_and16(dyn, ninst, x1, x5, x3, x4);
}
} else {
STCLRLH(x5, wback);
}
} else {
if(!i64) {MOV32w(x5, i16);}
MARKLOCK;
LDAXRH(x1, wback);
if(i64) {
emit_and16c(dyn, ninst, x1, i16, x3, x4);
} else {
emit_and16(dyn, ninst, x1, x5, x3, x4);
}
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
}
break;
case 5: //SUB
if(opcode==0x81) {INST_NAME("LOCK SUB Ew, Iw");} else {INST_NAME("LOCK SUB Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MOV32w(x5, i16);
UXTHw(x6, ed);
emit_sub16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
if(!ALIGNED_ATOMICH) {
if(arm64_uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
CMPSw_U12(x1, 0xF);
B_MARK(cGE);
} else {
TSTx_mask(wback, 1, 0, 0); // mask=1
B_MARK(cNE);
}
}
if(arm64_atomics) {
NEGw_REG(x4, x5);
UFLAG_IF {
LDADDALH(x4, x1, wback);
} else {
STADDLH(x4, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
SUBw_REG(x4, x1, x5);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
if(!ALIGNED_ATOMICH) {
B_MARK2_nocond;
MARK; // unaligned! also, not enough
LDRH_U12(x1, wback, 0);
LDAXRB(x4, wback);
SUBw_UXTB(x4, x4, x1);
CBNZw_MARK(x4);
SUBw_REG(x4, x1, x5);
STLXRB(x3, x4, wback);
CBNZx_MARK(x3);
STRH_U12(x4, wback, 0); // put the whole value
SMDMB();
}
MARK2;
UFLAG_IF {
emit_sub16(dyn, ninst, x1, x5, x3, x4);
}
}
break;
case 6: //XOR
if(opcode==0x81) {INST_NAME("LOCK XOR Ew, Iw");} else {INST_NAME("LOCK XOR Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
if(MODREG) {
if(opcode==0x81) i16 = F16S; else i16 = F8S;
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_xor16c(dyn, ninst, x6, i16, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
i64 = convert_bitmask_w(i16);
if(arm64_atomics) {
UFLAG_IF {
LDEORALH(x5, x1, wback);
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
} else {
STEORLH(x5, wback);
}
} else {
if(!i64) {MOV32w(x5, i16);}
MARKLOCK;
LDAXRH(x1, wback);
if(i64)
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
else
emit_xor16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
}
break;
case 7: //CMP
if(opcode==0x81) {INST_NAME("(LOCK) CMP Ew, Iw");} else {INST_NAME("(LOCK) CMP Ew, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x6, (opcode==0x81)?2:1);
(void)wb1;
// No need to LOCK, this is readonly
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(i16) {
MOV32w(x5, i16);
emit_cmp16(dyn, ninst, x6, x5, x3, x4, x6);
} else {
emit_cmp16_0(dyn, ninst, ed, x3, x4);
}
break;
}
break;
case 0xFF:
nextop = F8;
switch((nextop>>3)&7)
{
case 0: // INC Ew
INST_NAME("LOCK INC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_inc16(dyn, ninst, x6, x5, x3);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
MOV32w(x3, 1);
UFLAG_IF {
LDADDALH(x3, x1, wback);
emit_inc16(dyn, ninst, x1, x3, x4);
} else {
STADDLH(x3, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
emit_inc16(dyn, ninst, x1, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 1: //DEC Ew
INST_NAME("LOCK DEC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UXTHw(x6, ed);
emit_dec16(dyn, ninst, x6, x5, x3);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
MOV32w(x3, -1);
UFLAG_IF {
LDADDALH(x3, x1, wback);
emit_dec16(dyn, ninst, x1, x3, x4);
} else {
STADDLH(x3, wback);
}
} else {
MARKLOCK;
LDAXRH(x1, wback);
emit_dec16(dyn, ninst, x1, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
return addr;
}
-93
View File
@@ -1,93 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
#include "emu/x64compstrings.h"
uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
int32_t i32;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2;
int64_t j64;
uint64_t tmp64u, tmp64u2;
int v0, v1;
int q0, q1;
int d0, d1;
int64_t fixedaddress;
int unscaled;
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(j64);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
static const int8_t round_round[] = { 0, 2, 1, 3};
#endif
switch(opcode) {
case 0x38: // SSE 4.x
opcode = F8;
switch(opcode) {
case 0xF1:
INST_NAME("CRC32 Gd, Ew");
nextop = F8;
GETEW(x1, 0);
GETGD;
if(arm64_crc32) {
CRC32CH(gd, gd, ed);
} else {
MOV32w(x2, 0x82f63b78);
for(int j=0; j<2; ++j) {
UBFXxw(x3, ed, 8*j, 8);
EORw_REG(gd, gd, x3);
for(int i=0; i<8; ++i) {
LSRw_IMM((i&1)?gd:x4, (i&1)?x4:gd, 1);
TBZ((i&1)?x4:gd, 0, 4+4);
EORw_REG((i&1)?gd:x4, (i&1)?gd:x4, x2);
}
}
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
return addr;
}
-138
View File
@@ -1,138 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
#include "emu/x64compstrings.h"
uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
int32_t i32;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2;
int64_t j64;
uint64_t tmp64u, tmp64u2;
int v0, v1;
int q0, q1;
int d0, d1;
int64_t fixedaddress;
int unscaled;
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(j64);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
static const int8_t round_round[] = { 0, 2, 1, 3};
#endif
switch(opcode) {
case 0xB8:
INST_NAME("POPCNT Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SET_DFNONE();
nextop = F8;
GETGW(x2);
GETEW(x1, 0);
v1 = fpu_get_scratch(dyn, ninst);
VEORQ(v1, v1, v1);
VMOVQDfrom(v1, 0, ed);
CNT_8(v1, v1);
UADDLV_8(v1, v1);
VMOVHto(gd, v1, 0);
IFX(X_ALL) {
IFX(X_AF|X_PF|X_SF|X_OF|X_CF) {
MOV32w(x1, (1<<F_OF) | (1<<F_SF) | (1<<F_ZF) | (1<<F_AF) | (1<<F_CF) | (1<<F_PF));
BICw(xFlags, xFlags, x1);
}
IFX(X_ZF) {
CMPSw_U12(gd, 0);
IFNATIVE(NF_EQ) {}
else {
CSETw(x1, cEQ);
BFIw(xFlags, x1, F_ZF, 1);
}
}
}
GWBACK;
break;
case 0xBC:
INST_NAME("TZCNT Gw, Ew");
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
SET_DFNONE();
nextop = F8;
GETEW(x1, 0);
GETGW(x2);
TSTxw_REG(ed, ed);
IFX(X_CF) {
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
}
RBITw(x3, ed); // reverse
CLZw(gd, x3); // x2 gets leading 0 == TZCNT
MOV32w(x3, 16);
CSELw(gd, x3, gd, cEQ); // if src is zero, use bit width as res
IFX(X_ZF) {
TSTxw_REG(gd, gd);
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
}
GWBACK;
break;
case 0xBD:
INST_NAME("LZCNT Gw, Ew");
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
SET_DFNONE();
nextop = F8;
GETEW(x1, 0);
GETGW(x2);
IFX(X_CF) {
TSTxw_REG(ed, ed);
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
}
CLZw(gd, ed);
SUBw_U12(gd, gd, 16); // sub zero cnt of high word
IFX(X_ZF) {
TSTxw_REG(gd, gd);
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
}
GWBACK;
break;
default:
DEFAULT;
}
return addr;
}
File diff suppressed because it is too large. Load diff
-161
View File
@@ -1,161 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
#define GETGm gd = ((nextop&0x38)>>3)
uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop;
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
int64_t fixedaddress;
int unscaled;
int8_t i8;
uint8_t u8;
int32_t i32;
int64_t j64, i64;
int cacheupd = 0;
int lock;
int v0, v1, s0;
MAYUSE(i32);
MAYUSE(j64);
MAYUSE(v0);
MAYUSE(v1);
MAYUSE(s0);
MAYUSE(lock);
MAYUSE(cacheupd);
if(!rex.is32bits) {
// should do a different file
DEFAULT;
return addr;
}
rep = 0;
while((opcode==0xF2) || (opcode==0xF3)) {
rep = opcode-0xF1;
opcode = F8;
}
switch(opcode) {
case 0x89:
INST_NAME("MOV Seg:Ed, Gd");
nextop=F8;
GETGD;
if(MODREG) { // reg <= reg
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
} else { // mem <= reg
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
ADDz_REG(x4, x4, ed);
STz(gd, x4, fixedaddress);
}
break;
case 0x8B:
INST_NAME("MOV Gd, Seg:Ed");
nextop=F8;
GETGD;
if(MODREG) { // reg => reg
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
} else { // mem => reg
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
ADDz_REG(x4, x4, ed);
LDz(gd, x4, fixedaddress);
}
break;
case 0x8F:
INST_NAME("POP Seg:Ed");
nextop=F8;
if(MODREG) { // reg <= reg
POP1_32(x1);
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), x1);
} else { // mem <= reg
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
POP1_32(x1);
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
ADDz_REG(x4, x4, ed);
STz(x1, x4, fixedaddress);
}
break;
case 0xA1:
INST_NAME("MOV EAX, Seg:[Od]");
i32 = F16;
grab_segdata(dyn, addr, ninst, x4, seg, 0);
if(i32<4096 && !(i32&3)) {
LDRw_U12(xRAX, x4, i32);
} else if(i32<256) {
LDURw_I9(xRAX, x4, i32);
} else {
MOV32w(x1, i32);
LDRw_REG(xRAX, x4, x1);
}
break;
case 0xA3:
INST_NAME("MOV Seg:[Od], EAX");
i32 = F16;
grab_segdata(dyn, addr, ninst, x4, seg, 0);
if(i32<4096 && !(i32&3)) {
STRw_U12(xRAX, x4, i32);
} else if(i32<256) {
STURw_I9(xRAX, x4, i32);
} else {
MOV32w(x1, i32);
STRw_REG(xRAX, x4, x1);
}
break;
case 0xFF:
nextop = F8;
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH FS:Ew");
if (MODREG) {
DEFAULT;
} else {
SMREAD();
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
ADDz_REG(x4, x4, ed);
LDW(x3, x4, fixedaddress);
PUSH1_32(x3);
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
return addr;
}
-134
View File
@@ -1,134 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
#define GETGm gd = ((nextop&0x38)>>3)
uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop;
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
int64_t fixedaddress;
int unscaled;
int8_t i8;
uint8_t u8;
int32_t i32;
int64_t j64, i64;
int cacheupd = 0;
int lock;
int v0, v1, s0;
MAYUSE(i32);
MAYUSE(j64);
MAYUSE(v0);
MAYUSE(v1);
MAYUSE(s0);
MAYUSE(lock);
MAYUSE(cacheupd);
if(!rex.is32bits) {
// should do a different file
DEFAULT;
return addr;
}
rep = 0;
while((opcode==0xF2) || (opcode==0xF3)) {
rep = opcode-0xF1;
opcode = F8;
}
switch(opcode) {
case 64:
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
break;
#define GO(NO, YES) \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
Bcond(NO, i32); \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
SKIP_SEVL(i32); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
SKIP_SEVL(i32); \
Bcond(YES, i32); \
}
case 0xE0:
INST_NAME("LOOPNZ (16bits)");
READFLAGS(X_ZF);
i8 = F8S;
UXTHw(x1, xRCX);
SUBw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 16);
CBZw_NEXT(x1); // ECX is 0, no LOOP
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
GO(cNE, cEQ);
break;
case 0xE1:
INST_NAME("LOOPZ (16bits)");
READFLAGS(X_ZF);
i8 = F8S;
UXTHw(x1, xRCX);
SUBw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 16);
CBZw_NEXT(x1); // ECX is 0, no LOOP
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
GO(cEQ, cNE);
break;
case 0xE2:
INST_NAME("LOOP (16bits)");
i8 = F8S;
UXTHw(x1, xRCX);
SUBSw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 16);
GO(cEQ, cNE);
break;
case 0xE3:
INST_NAME("JCXZ");
i8 = F8S;
TSTw_mask(xRCX, 0, 15); //mask=0xffff
GO(cNE, cEQ);
break;
#undef GO
default:
DEFAULT;
}
return addr;
}
-154
View File
@@ -1,154 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
static const char* avx_prefix_string(uint16_t p)
{
switch(p) {
case VEX_P_NONE: return "0";
case VEX_P_66: return "66";
case VEX_P_F2: return "F2";
case VEX_P_F3: return "F3";
default: return "??";
}
}
static const char* avx_map_string(uint16_t m)
{
switch(m) {
case VEX_M_NONE: return "0";
case VEX_M_0F: return "0F";
case VEX_M_0F38: return "0F38";
case VEX_M_0F3A: return "0F3A";
default: return "??";
}
}
uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2)) {
switch(opcode) {
case 0xF6:
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
nextop = F8;
GETGD;
GETED32(0);
GETVD;
if(rex.w) {
// 64bits mul
if((gd==xRDX) || (gd==ed) || (gd==vd))
gb1 = x3;
else
gb1 = gd;
UMULH(gb1, xRDX, ed);
if(gd!=vd) {MULx(vd, xRDX, ed);}
if(gb1==x3) {
MOVx_REG(gd, gb1);
}
} else {
// 32bits mul
UMULL(x3, xRDX, ed);
if(gd!=vd) {MOVw_REG(vd, x3);}
LSRx(gd, x3, 32);
}
break;
default:
DEFAULT;
}
}
else if((vex.m==VEX_M_0F) && (vex.p==VEX_P_66)) {
switch(opcode) {
case 0xD6:
INST_NAME("VMOVQ Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOV(v1, v0);
YMM0((nextop&7)+(rex.b<<3));
} else {
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff<<3, 7, rex, NULL, 0, 0);
VSTR64_U12(v0, ed, fixedaddress);
}
break;
case 0x6E:
INST_NAME("VMOVD Gx, Ed");
nextop = F8;
GETGX_empty(v0);
GETED(0);
VEORQ(v0, v0, v0); // RAZ vector
if(rex.w) {
FMOVDx(v0, ed);
} else {
FMOVSw(v0, ed);
}
YMM0(gd);
break;
default:
DEFAULT;
}
}
else {DEFAULT;}
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_missing)==1))
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || BOX64DRENV(dynarec_dump)) {
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
}
return addr;
}
-418
View File
@@ -1,418 +0,0 @@
#include <stddef.h>
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
#include <string.h>
#include "debug.h"
#include "dynablock.h"
#include "x64emu.h"
#include "emu/x64emu_private.h"
#include "x64run.h"
#include "emu/x64run_private.h"
#include "dynarec/dynablock_private.h"
#include "dynarec_arm64_arch.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_native.h"
//order might be important, so define SUPER for the right one
#define SUPER() \
GO(flags) \
GO(x87) \
GO(mmx) \
GO(sse) \
GO(ymm) \
typedef struct arch_flags_s
{
uint8_t defered:1;
uint8_t nf:1;
uint8_t eq:1;
uint8_t vf:1;
uint8_t cf:1;
uint8_t inv_cf:1;
} arch_flags_t;
#define X87_ST_D 0
#define X87_ST_F 1
#define X87_ST_I64 2
typedef struct arch_x87_s
{
int8_t delta; //up to +/-7
uint8_t x87; // 1bit is STx present
uint16_t x87_type; // 2bits per STx type
uint32_t x87_pos; //4bits per STx position (well, 3 would be enough)
} arch_x87_t;
typedef struct arch_mmx_s
{
uint8_t mmx; //1bit for each mmx reg present
} arch_mmx_t;
typedef struct arch_sse_s
{
uint16_t sse; //1bit for each sse reg present
} arch_sse_t;
typedef struct arch_ymm_s
{
uint16_t ymm0; // 1bit for ymm0
uint16_t ymm; // 1bit for each ymm present
uint64_t ymm_pos; // 4bits for position of each ymm present
} arch_ymm_t;
typedef struct arch_arch_s
{
#define GO(A) uint16_t A:1;
SUPER()
#undef GO
uint16_t unaligned:1;
uint16_t seq:10; // how many instruction on the same values
} arch_arch_t;
typedef struct arch_build_s
{
#define GO(A) uint8_t A:1;
SUPER()
#undef GO
uint8_t unaligned;
#define GO(A) arch_##A##_t A##_;
SUPER()
#undef GO
} arch_build_t;
static arch_build_t static_build[MAX_INSTS+2] = {0};
static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch)
{
memset(arch, 0, sizeof(arch_build_t));
// flags
if((dyn->insts[ninst].f_entry.dfnone==0) || dyn->insts[ninst].need_nat_flags || dyn->insts[ninst].before_nat_flags) {
arch->flags = 1;
arch->flags_.defered = dyn->insts[ninst].f_entry.dfnone==0;
uint8_t flags = dyn->insts[ninst].need_nat_flags | dyn->insts[ninst].before_nat_flags;
arch->flags_.vf = flags&NF_VF;
arch->flags_.nf = flags&NF_SF;
arch->flags_.eq = flags&NF_EQ;
arch->flags_.cf = flags&NF_CF;
if(arch->flags_.cf)
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
}
// got through all naoncache to gather regs assignments
int idx;
for(int i=0; i<32; ++i)
if(dyn->insts[ninst].n.neoncache[i].v!=-1)
switch(dyn->insts[ninst].n.neoncache[i].t) {
case NEON_CACHE_XMMW:
arch->sse = 1;
arch->sse_.sse |= 1<<dyn->insts[ninst].n.neoncache[i].n;
break;
case NEON_CACHE_MM:
arch->mmx = 1;
arch->mmx_.mmx |= 1<<dyn->insts[ninst].n.neoncache[i].n;
break;
case NEON_CACHE_YMMW:
arch->ymm = 1;
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
idx = i;
if(idx>=EMM0 && idx<=EMM0+8)
idx-=EMM0;
else
idx-=SCRATCH0-8;
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
break;
case NEON_CACHE_ST_D:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_ST_F:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_ST_I64:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_XMMR:
case NEON_CACHE_YMMR:
default:
// doing nothing, it's just a value read in memory
break;
}
// ymm0
if(dyn->insts[ninst].ymm0_out) {
arch->ymm = 1;
arch->ymm_.ymm0 = dyn->insts[ninst].ymm0_out;
}
// x87 top
if(dyn->insts[ninst].n.x87stack) {
arch->x87 = 1;
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
}
// opcode can handle unaligned
arch->unaligned = dyn->insts[ninst].unaligned;
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
}
static int sizeof_arch(arch_arch_t* arch)
{
int sz = sizeof(arch_arch_t);
#define GO(A) if(arch->A) sz+=sizeof(arch_##A##_t);
SUPER()
#undef GO
return sz;
}
static int sizeof_arch_build(arch_build_t* build)
{
int sz = sizeof(arch_arch_t);
#define GO(A) if(build->A) sz+=sizeof(arch_##A##_t);
SUPER()
#undef GO
return sz;
}
size_t get_size_arch(dynarec_arm_t* dyn)
{
arch_build_t* previous = NULL;
size_t sz = 0;
int seq = 0;
int nseq = 0;
int last = 0;
if(!dyn->size) return 0;
for(int i=0; i<dyn->size; ++i) {
arch_build_t* build = static_build+i;
last = arch_build(dyn, i, build);
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
// same sequence, increment
++seq;
} else {
seq = 0;
++nseq;
previous = build;
sz += sizeof_arch_build(build);
}
}
if(nseq==1 && !last)
return 0; //empty, no flags, no nothing
return sz;
}
static void build_next(arch_arch_t* arch, arch_build_t* build)
{
#define GO(A) arch->A = build->A;
SUPER()
#undef GO
arch->unaligned = build->unaligned;
arch->seq = 0;
void* p = ((void*)arch)+sizeof(arch_arch_t);
#define GO(A) \
if(build->A) { \
memcpy(p, &(build->A##_), sizeof(arch_ ##A##_t)); \
p+=sizeof(arch_##A##_t); \
}
SUPER()
#undef GO
}
void* populate_arch(dynarec_arm_t* dyn, void* p, size_t tot_sz)
{
arch_build_t* previous = NULL;
arch_arch_t* arch = p;
arch_arch_t* next = p;
int seq = 0;
size_t total = 0;
if(!tot_sz) return NULL;
for(int i=0; i<dyn->size; ++i) {
arch_build_t* build = static_build+i;
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
// same sequence, increment
seq++;
arch->seq = seq;
} else {
int sz = sizeof_arch_build(build);
if(total+sz>tot_sz) {
printf_log(LOG_INFO, "Warning: populate_arch oversized\n");
return NULL;
}
arch = next;
build_next(arch, build);
seq = 0;
previous = build;
total += sz;
next = (arch_arch_t*)((uintptr_t)arch+sz);
}
}
return p;
}
int getX64AddressInst(dynablock_t* db, uintptr_t x64pc); // define is signal.c
// NZCV N
#define NZCV_N 31
// NZCV Z
#define NZCV_Z 30
// NZCV C
#define NZCV_C 29
// NZCV V
#define NZCV_V 28
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
{
if(!db->arch_size || !db->arch)
return;
int ninst = getX64AddressInst(db, x64pc);
dynarec_log(LOG_INFO, "adjust_arch(...), db=%p, x64pc=%p, nints=%d", db, (void*)x64pc, ninst);
if(ninst<0) {
dynarec_log_prefix(0, LOG_INFO, "\n");
return;
}
if(ninst==0) {
dynarec_log_prefix(0, LOG_INFO, "\n");
CHECK_FLAGS(emu);
return;
}
// look for state at ninst-1
arch_arch_t* arch = db->arch;
arch_arch_t* next = arch;
#define GO(A) arch_##A##_t* A = NULL;
SUPER()
#undef GO
int i = 0;
while(i<ninst-1) {
arch = next;
i += 1+arch->seq;
dynarec_log_prefix(0, LOG_INFO, "[ seq=%d%s%s%s%s%s ] ", arch->seq, arch->flags?" Flags":"", arch->x87?" x87":"", arch->mmx?" MMX":"", arch->sse?" SSE":"", arch->ymm?" YMM":"");
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
}
int sz = sizeof(arch_arch_t);
#define GO(A) \
if(arch->A) { \
A = (arch_##A##_t*)((uintptr_t)arch + sz); \
sz+=sizeof(arch_##A##_t); \
}
SUPER()
#undef GO
if(flags) {
dynarec_log_prefix(0, LOG_INFO, " flags[%s-%s%s%s%s] ", flags->defered?"defered":"", flags->nf?"S":"", flags->vf?"O":"", flags->eq?"Z":"", flags->cf?(flags->inv_cf?"C(inv)":"C"):"");
if(flags->defered) {
CHECK_FLAGS(emu);
//return;
}
if(flags->nf) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
}
if(flags->vf) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_OF);
}
if(flags->eq) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_Z), F_ZF);
}
if(flags->cf) {
if(flags->inv_cf) {
CONDITIONAL_SET_FLAG((p->uc_mcontext.pstate&(1<<NZCV_C))==0, F_CF);
} else {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
}
}
}
struct fpsimd_context *fpsimd = NULL;
// find fpsimd struct
{
struct _aarch64_ctx * ff = (struct _aarch64_ctx*)p->uc_mcontext.__reserved;
while (ff->magic && !fpsimd) {
if(ff->magic==FPSIMD_MAGIC)
fpsimd = (struct fpsimd_context*)ff;
else
ff = (struct _aarch64_ctx*)((uintptr_t)ff + ff->size);
}
}
if(sse) {
dynarec_log_prefix(0, LOG_INFO, " sse[%x (fpsimd=%p)] ", sse->sse, fpsimd);
for(int i=0; i<16; ++i)
if(fpsimd && (sse->sse>>i)&1) {
int idx = 0;
if(i>7) {
idx = XMM8 + i - 8;
} else {
idx = XMM0 + i;
}
emu->xmm[i].u128 = fpsimd->vregs[idx];
}
}
if(ymm) {
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (fpsimd=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, fpsimd);
for(int i=0; i<16; ++i) {
if(fpsimd && (ymm->ymm>>i)&1) {
int idx = (ymm->ymm_pos>>(i*4))&0xf;
if(i>7) {
idx = SCRATCH0 + i - 8;
} else {
idx = EMM0 + i;
}
emu->ymm[i].u128 = fpsimd->vregs[idx];
}
if(ymm->ymm0&(1<<i))
emu->ymm[i].u128 = 0;
}
}
if(mmx) {
dynarec_log_prefix(0, LOG_INFO, " mmx[%x (fpsimd=%p)] ", mmx->mmx, fpsimd);
for(int i=0; i<8; ++i)
if(fpsimd && (mmx->mmx>>i)&1) {
int idx = EMM0 + i;
emu->mmx[i].q = fpsimd->vregs[idx]&0xffffffffffffffffLL;
}
}
if(x87) {
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x (fpsimd=%p)] ", x87->x87, x87->x87_pos, x87->x87_type, fpsimd);
emu->top -= x87->delta;
for(int i=0; i<8; ++i) {
if(x87->x87&(1<<i)) {
int idx = EMM0 + (x87->x87_pos>>(i*4))&0x0f;
int t = (x87->x87_type>>(i*2))&0x3;
switch (t) {
case X87_ST_F:
emu->x87[(emu->top+i)&7].d = *(float*)&fpsimd->vregs[idx];
break;
case X87_ST_I64:
emu->x87[(emu->top+i)&7].d = *(int64_t*)&fpsimd->vregs[idx];
break;
case X87_ST_D:
emu->x87[(emu->top+i)&7].d = *(double*)&fpsimd->vregs[idx];
break;
}
}
}
}
dynarec_log_prefix(0, LOG_INFO, "\n");
}
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
{
if(!db)
return 0;
if(!db->arch_size || !db->arch)
return 0;
int ninst = getX64AddressInst(db, x64pc);
if(ninst<0) {
return 0;
}
// look for state at ninst
arch_arch_t* arch = db->arch;
arch_arch_t* next = arch;
int i = -1;
while(i<ninst) {
arch = next;
i += 1+arch->seq;
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
}
return arch->unaligned;
}
-20
View File
@@ -1,20 +0,0 @@
#ifndef __DYNAREC_ARM_ARCH_H__
#define __DYNAREC_ARM_ARCH_H__
#include <stddef.h>
#include <ucontext.h>
#include "x64emu.h"
#include "box64context.h"
#include "dynarec.h"
#include "dynarec_arm64_private.h"
// get size of arch specific info (can be 0)
size_t get_size_arch(dynarec_arm_t* dyn);
//populate the array
void* populate_arch(dynarec_arm_t* dyn, void* p, size_t sz);
//adjust flags and more
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
// get if instruction can be regenerated for unaligned access
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
#endif // __DYNAREC_ARM_ARCH_H__
-79
View File
@@ -1,79 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
static const char* avx_prefix_string(uint16_t p)
{
switch(p) {
case VEX_P_NONE: return "0";
case VEX_P_66: return "66";
case VEX_P_F2: return "F2";
case VEX_P_F3: return "F3";
default: return "??";
}
}
static const char* avx_map_string(uint16_t m)
{
switch(m) {
case VEX_M_NONE: return "0";
case VEX_M_0F: return "0F";
case VEX_M_0F38: return "0F38";
case VEX_M_0F3A: return "0F3A";
default: return "??";
}
}
uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = PK(0);
rex_t rex = vex.rex;
if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_NONE))
addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_NONE))
addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_66))
addr = dynarec64_AVX_66_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_F2))
addr = dynarec64_AVX_F2_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_F3))
addr = dynarec64_AVX_F3_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_66))
addr = dynarec64_AVX_66_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_66))
addr = dynarec64_AVX_66_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2))
addr = dynarec64_AVX_F2_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_F2))
addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F3))
addr = dynarec64_AVX_F3_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else {DEFAULT;}
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_missing)==1))
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || BOX64DRENV(dynarec_dump)) {
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
}
return addr;
}
-813
View File
@@ -1,813 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
#endif
rex_t rex = vex.rex;
switch(opcode) {
case 0x10:
INST_NAME("VMOVUPS Gx,Ex");
nextop = F8;
GETG;
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
if(v0!=v1) VMOVQ(v0, v1);
if(vex.l) {
v1 = ymm_get_reg(dyn, ninst, x1, ed, 0, gd, -1, -1);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, ed, -1, -1);
if(v0!=v1) VMOVQ(v0, v1);
}
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VLDR128_U12(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
if(vex.l) {
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
VLDR128_U12(v0, ed, fixedaddress+16);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x11:
INST_NAME("VMOVUPS Ex,Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VMOVQ(v1, v0);
if(vex.l) {
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
v1 = ymm_get_reg_empty(dyn, ninst, x1, ed, gd, -1, -1);
VMOVQ(v1, v0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VSTR128_U12(v0, ed, fixedaddress);
if(vex.l) {
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
VSTR128_U12(v0, ed, fixedaddress+16);
}
SMWRITE2();
}
break;
case 0x12:
nextop = F8;
GETVX(v2, 0);
if(MODREG) {
INST_NAME("VMOVHLPS Gx, Vx, Ex");
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX_empty(v0);
if((v0!=v2) && (v0!=v1))
VMOVQ(v0, v2);
VMOVeD(v0, 0, v1, 1);
if((v0!=v2) && (v0==v1))
VMOVeD(v0, 1, v2, 1);
} else {
INST_NAME("VMOVLPS Gx, Vx, Ex");
GETGX_empty(v0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(v0!=v2)
VMOVQ(v0, v2);
VLD1_64(v0, 0, ed);
}
YMM0(gd);
break;
case 0x13:
nextop = F8;
INST_NAME("VMOVLPS Ex, Vx, Gx");
GETGX(v0, 0);
GETVX(v2, 0);
if(v1!=v2)
VMOVQ(v0, v2);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
if(v0!=v1) VMOVeD(v1, 0, v0, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
SMWRITE2();
}
break;
case 0x14:
INST_NAME("VUNPCKLPS Gx, Vx, Ex");
nextop = F8;
SMREAD();
GETGX_empty_VXEX(v0, v2, v1, 0);
VZIP1Q_32(v0, v2, v1);
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VZIP1Q_32(v0, v2, v1);
} else YMM0(gd);
break;
case 0x15:
INST_NAME("VUNPCKHPS Gx, Vx, Ex");
nextop = F8;
SMREAD();
GETGX_empty_VXEX(v0, v2, v1, 0);
VZIP2Q_32(v0, v2, v1);
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VZIP2Q_32(v0, v2, v1);
} else YMM0(gd);
break;
case 0x16:
nextop = F8;
if(MODREG) {
INST_NAME("VMOVLHPS Gx, Vx, Ex");
GETGX(v0, 1);
GETVX(v2, 0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
if(v0!=v2 && v0!=v1) VMOVQ(v0, v2);
VMOVeD(v0, 1, v1, 0);
if(v0!=v2 && v0==v1) VMOVeD(v0, 0, v2, 0);
} else {
INST_NAME("VMOVHPS Gx, Vx, Ex");
SMREAD();
GETGX(v0, 1);
GETVX(v2, 0);
if(v0!=v2) VMOVQ(v0, v2);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VLD1_64(v0, 1, ed);
}
YMM0(gd);
break;
case 0x17:
INST_NAME("VMOVHPS Ex,Gx");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
VMOVeD(v1, 0, v0, 1);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VST1_64(v0, 1, ed);
}
break;
case 0x28:
INST_NAME("VMOVAPS Gx, Ex");
nextop = F8;
GETG;
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
if(vex.l) {
GETGY_empty_EY(v0, v1);
VMOVQ(v0, v1);
}
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VLDR128_U12(v0, ed, fixedaddress);
if(vex.l) {
GETGY_empty(v0, -1, -1, -1);
VLDR128_U12(v0, ed, fixedaddress+16);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x29:
INST_NAME("VMOVAPS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VMOVQ(v1, v0);
if(vex.l) {
GETGYEY_empty(v0, v1);
VMOVQ(v1, v0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VSTR128_U12(v0, ed, fixedaddress);
if(vex.l) {
GETGY(v0, 0, -1, -1, -1);
VSTR128_U12(v0, ed, fixedaddress+16);
}
SMWRITE2();
}
break;
case 0x2B:
INST_NAME("VMOVNTPS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VMOVQ(v1, v0);
if(vex.l) {
GETGYEY_empty(v0, v1);
VMOVQ(v1, v0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VSTR128_U12(v0, ed, fixedaddress);
if(vex.l) {
GETGY(v0, 0, -1, -1, -1);
VSTR128_U12(v0, ed, fixedaddress+16);
}
}
break;
case 0x2E:
// no special check...
case 0x2F:
if(opcode==0x2F) {INST_NAME("VCOMISS Gx, Ex");} else {INST_NAME("VUCOMISS Gx, Ex");}
SETFLAGS(X_ALL, SF_SET_NODF);
nextop = F8;
GETGX(v0, 0);
GETEXSS(s0, 0, 0);
FCMPS(v0, s0);
FCOMI(x1, x2);
break;
case 0x50:
INST_NAME("VMOVMSPKPS Gd, Ex");
nextop = F8;
GETGD;
MOV32w(gd, 0);
if(MODREG) {
// EX is an xmm reg
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETEX_Y(v0, 0, 0); } else { GETEY(v0); }
SQXTN_16(q0, v0); // reduces the 4 32bits to 4 16bits
VMOVQDto(x1, q0, 0);
LSRx(x1, x1, 15);
BFIx(gd, x1, 0+(l*4), 1);
LSRx(x1, x1, 16);
BFIx(gd, x1, 1+(l*4), 1);
LSRx(x1, x1, 16);
BFIx(gd, x1, 2+(l*4), 1);
LSRx(x1, x1, 16);
BFIx(gd, x1, 3+(l*4), 1);
}
} else {
// EX is memory
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0xfff<<3)-24, 7, rex, NULL, 0, 0);
for(int l=0; l<1+vex.l; ++l) {
LDRx_U12(x1, ed, fixedaddress+16*l);
LSRx(x1, x1, 31);
BFIx(gd, x1, 0+(l*4), 1);
LSRx(x1, x1, 32);
BFIx(gd, x1, 1+(l*4), 1);
LDRx_U12(x1, ed, fixedaddress+8+16*l);
LSRx(x1, x1, 31);
BFIx(gd, x1, 2+(l*4), 1);
LSRx(x1, x1, 32);
BFIx(gd, x1, 3+(l*4), 1);
}
}
break;
case 0x51:
INST_NAME("VSQRTPS Gx, Ex");
nextop = F8;
SKIPTEST(x1);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_EX(q0, q1, 0); } else { GETGY_empty_EY(q0, q1); }
VFSQRTQS(q0, q1);
}
if(!vex.l) YMM0(gd);
break;
case 0x52:
INST_NAME("VRSQRTPS Gx, Ex");
nextop = F8;
SKIPTEST(x1);
v0 = fpu_get_scratch(dyn, ninst);
VFMOVSQ_8(v0, 0b01110000); //1.0f
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_EX(q0, q1, 0); } else { GETGY_empty_EY(q0, q1); }
#if 0
// the aproximation doesn't not work on Death Stranding. code around 0x1419c9100 fail...
if(!l) {
if(q1==q0)
v1 = fpu_get_scratch(dyn, ninst);
else
v1 = q1;
}
// more precise
VFRSQRTEQS(v0, q1);
VFMULQS(v1, v0, q1);
VFRSQRTSQS(v1, v1, v0);
VFMULQS(q0, v1, v0);
#else
VFSQRTQS(q0, q1);
VFDIVQS(q0, v0, q0);
#endif
}
if(!vex.l) YMM0(gd);
break;
case 0x53:
INST_NAME("VRCPPS Gx, Ex");
nextop = F8;
SKIPTEST(x1);
q0 = fpu_get_scratch(dyn, ninst);
VFMOVSQ_8(q0, 0b01110000); //1.0f
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETGX_empty_EX(v0, v1, 0);
#if 0
if(v0==v1)
q1 = fpu_get_scratch(dyn, ninst);
#endif
} else {
GETGY_empty_EY(v0, v1);
}
#if 0
if(v0!=v1) q1 = v0;
VFRECPEQS(q0, v1);
VFRECPSQS(q1, q0, v1);
VFMULQS(v0, q0, q1);
#else
VFDIVQS(v0, q0, v1);
#endif
}
if(!vex.l) YMM0(gd);
break;
case 0x54:
INST_NAME("VANDPS Gx, Vx, Ex");
nextop = F8;
GETGX_empty_VXEX(v0, v2, v1, 0);
VANDQ(v0, v2, v1);
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VANDQ(v0, v2, v1);
} else YMM0(gd)
break;
case 0x55:
INST_NAME("VANDNPS Gx, Vx, Ex");
nextop = F8;
GETGX_empty_VXEX(v0, v2, v1, 0);
VBICQ(v0, v1, v2);
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VBICQ(v0, v1, v2);
} else YMM0(gd)
break;
case 0x56:
INST_NAME("VORPS Gx, Vx, Ex");
nextop = F8;
GETGX_empty_VXEX(v0, v2, v1, 0);
VORRQ(v0, v2, v1);
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VORRQ(v0, v2, v1);
} else YMM0(gd)
break;
case 0x57:
INST_NAME("VXORPS Gx, Vx, Ex");
nextop = F8;
GETGX_empty_VXEX(v0, v2, v1, 0);
VEORQ(v0, v2, v1);
if(vex.l) {
GETGY_empty_VYEY(v0, v2, v1);
VEORQ(v0, v2, v1);
} else YMM0(gd)
break;
case 0x58:
INST_NAME("VADDPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFADDQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd)
break;
case 0x59:
INST_NAME("VMULPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFMULQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd)
break;
case 0x5A:
INST_NAME("VCVTPS2PD Gx, Ex");
nextop = F8;
GETGX_empty_EX(v0, v1, 0);
if(vex.l) {
GETGY_empty(q0, -1, -1, -1);
FCVTL2(q0, v1);
} else YMM0(gd)
FCVTL(v0, v1);
break;
case 0x5B:
INST_NAME("VCVTDQ2PS Gx, Ex");
nextop = F8;
GETGX_empty_EX(v0, v1, 0);
SCVTQFS(v0, v1);
if(vex.l) {
GETGY_empty_EY(v0, v1);
SCVTQFS(v0, v1);
} else YMM0(gd)
break;
case 0x5C:
INST_NAME("VSUBPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFSUBQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd)
break;
case 0x5D:
INST_NAME("VMINPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
// FMIN/FMAX wll not copy a NaN if either is NaN
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
VFMINQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan) && (v2!=v1)) {
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
VBIFQ(v0, v1, q0); // copy dest where source is NaN
}
}
if(!vex.l) YMM0(gd);
break;
case 0x5E:
INST_NAME("VDIVPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFDIVQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd)
break;
case 0x5F:
INST_NAME("VMAXPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
// FMIN/FMAX wll not copy a NaN if either is NaN
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
VFMAXQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan) && (v2!=v1)) {
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
VBIFQ(v0, v1, q0); // copy dest where source is NaN
}
}
if(!vex.l) YMM0(gd);
break;
case 0x77:
if(!vex.l) {
INST_NAME("VZEROUPPER");
if(vex.v!=0) {
UDF(0);
} else {
for(int i=0; i<(rex.is32bits?8:16); ++i) {
YMM0(i);
}
}
} else {
INST_NAME("VZEROALL");
if(vex.v!=0) {
UDF(0);
} else {
for(int i=0; i<(rex.is32bits?8:16); ++i) {
v0 = sse_get_reg_empty(dyn, ninst, x1, i);
VEORQ(v0, v0, v0);
YMM0(i);
}
}
}
break;
case 0xAE:
nextop = F8;
if(MODREG) {
DEFAULT;
} else
switch((nextop>>3)&7) {
case 2:
INST_NAME("VLDMXCSR Md");
GETED(0);
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
if(BOX64ENV(sse_flushto0)) {
MRS_fpcr(x2); // get fpscr
LSRw_IMM(x3, ed, 15); // get FZ bit
BFIw(x2, x3, 24, 1); // inject FZ bit
EORw_REG_LSR(x3, x3, ed, 1); // FZ xor DAZ
BFIw(x2, x3, 1, 1); // inject AH bit
MSR_fpcr(x2); // put new fpscr
}
if(BOX64ENV(sse_flushto0)) {
// try to sync mxcsr with fpsr on the flag side
/* mapping is
ARM -> X86
0 -> 0 // Invalid operation
1 -> 2 // Divide by 0
2 -> 3 // Overflow
3 -> 4 // underflow
4 -> 5 // Inexact
5 -> 1 // denormal
*/
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
if(ed!=x1)
MOVw_REG(x1, ed); // x1 = 543210
RORw(x3, x1, 2); // x3 = 10.....5432
BFIw(x1, x3, 1, 4); // x1 = 54320
RORw(x3, x3, 32-1); // x3 = 0.....54321
BFIw(x1, x3, 5, 1); // x1 = 154320
MRS_fpsr(x2);
BFIx(x2, x1, 0, 6);
MSR_fpsr(x2);
}
break;
case 3:
INST_NAME("VSTMXCSR Md");
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
if(BOX64ENV(sse_flushto0)) {
// sync with fpsr, with mask from mxcsr
MRS_fpsr(x1);
// doing ARM -> X86 here, 543210 => 432150
UBFXw(x2, x1, 1, 5); // x2 = 54321
BFIw(x1, x2, 2, 4); // x1 = 432110
LSRw(x2, x2, 4); // x2 = 5
BFIw(x1, x2, 1, 1); // x1 = 432150
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
BFIw(x4, x1, 0, 6); // inject back the flags
}
STW(x4, ed, fixedaddress);
break;
default:
DEFAULT;
}
break;
case 0xC2:
INST_NAME("VCMPPS Gx, Vx, Ex, Ib");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12) || ((u8&15)==13) || ((u8&15)==14)) {
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(((u8&15)==7)?v0:q0, q0, q0); // 0 if NAN, 1 if not NAN
}
switch(u8&0xf) {
// the inversion of the params in the comparison is there to handle NaN the same way SSE does
case 0x00: VFCMEQQS(v0, v2, v1); break; // Equal, not unordered
case 0x01: VFCMGTQS(v0, v1, v2); break; // Less than
case 0x02: VFCMGEQS(v0, v1, v2); break; // Less or equal
case 0x03: VMVNQ(v0, q0); break; // unordered
case 0x04: VFCMEQQS(v0, v2, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
case 0x05: VFCMGTQS(v0, v1, v2); VMVNQ(v0, v0); break; // Greater or equal or unordered
case 0x06: VFCMGEQS(v0, v1, v2); VMVNQ(v0, v0); break; // Greater or unordered
case 0x07: break; // ordered
case 0x08: VFCMEQQS(v0, v2, v1); VORNQ(v0, v0, q0); break; // Equal, or unordered
case 0x09: VFCMGTQS(v0, v1, v2); VORNQ(v0, v0, q0); break; // Less than or unordered
case 0x0a: VFCMGEQS(v0, v1, v2); VORNQ(v0, v0, q0); break; // Less or equal or unordered
case 0x0b: VEORQ(v0, v0, v0); break; // false
case 0x0c: VFCMEQQS(v0, v2, v1); VBICQ(v0, q0, v0); break;
case 0x0d: VFCMGEQS(v0, v2, v1); break;
case 0x0e: VFCMGTQS(v0, v2, v1); break;
case 0x0f: MOVIQ_64(v0, 0xff); break; //true
}
}
if(!vex.l) YMM0(gd);
break;
case 0xC6:
INST_NAME("VSHUFPS Gx, Vx, Ex, Ib");
nextop = F8;
GETVX(v2, 0);
if(!MODREG) {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
v1 = -1; // to avoid a warning
} else
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX_empty(v0);
u8 = F8;
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
VDUPQ_32(v0, v2, u8&3);
} else if(v2==v1 && (u8==0xe0)) { // elements 3 2 0 0
VMOVQ(v0, v2);
VMOVeS(v0, 1, v0, 0);
} else if(v2==v1 && (u8==0xe5)) { // elements 3 2 1 1
VMOVQ(v0, v2);
VMOVeS(v0, 0, v0, 1);
} else if(v2==v1 && (u8==0xa0)) { // elements 2 2 0 0
VTRNQ1_32(v0, v1, v2);
} else if(v2==v1 && (u8==0xf5)) { // elements 3 3 1 1
VTRNQ2_32(v0, v1, v2);
} else if(v2==v1 && (u8==0xb1)) { // elements 2 3 0 1
VREV64Q_32(v0, v1);
} else if(MODREG && u8==0x88) { // elements 2 0 2 0
VUZP1Q_32(v0, v2, v1);
} else if(MODREG && u8==0xdd) { // elements 3 1 3 1
VUZP2Q_32(v0, v2, v1);
} else {
if((v0==v1) || (v0==v2)) {
d0 = fpu_get_scratch(dyn, ninst); s0 = 0;
} else {
d0 = v0; s0 = 1;
}
// first two elements from Vx
for(int i=0; i<2; ++i) {
VMOVeS(d0, i, v2, (u8>>(i*2))&3);
}
// second two from Ex
if(MODREG) {
for(int i=2; i<4; ++i) {
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
}
} else {
SMREAD();
for(int i=2; i<4; ++i) {
ADDx_U12(x2, ed, ((u8>>(i*2))&3)*4);
VLD1_32(d0, i, x2);
}
}
if(v0!=d0) VMOVQ(v0, d0);
}
if(vex.l) {
if(MODREG)
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1);
GETGY_empty_VY(v0, v2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
VDUPQ_32(v0, v2, u8&3);
} else if(v2==v1 && (u8==0xe0)) { // elements 3 2 0 0
VMOVQ(v0, v2);
VMOVeS(v0, 1, v0, 0);
} else if(v2==v1 && (u8==0xe5)) { // elements 3 2 1 1
VMOVQ(v0, v2);
VMOVeS(v0, 0, v0, 1);
} else if(v2==v1 && (u8==0xa0)) { // elements 2 2 0 0
VTRNQ1_32(v0, v1, v2);
} else if(v2==v1 && (u8==0xf5)) { // elements 3 3 1 1
VTRNQ2_32(v0, v1, v2);
} else if(v2==v1 && (u8==0xb1)) { // elements 2 3 0 1
VREV64Q_32(v0, v1);
} else if(MODREG && u8==0x88) { // elements 2 0 2 0
VUZP1Q_32(v0, v2, v1);
} else if(MODREG && u8==0xdd) { // elements 3 1 3 1
VUZP2Q_32(v0, v2, v1);
} else {
if(s0) d0 = v0;
for(int i=0; i<2; ++i) {
VMOVeS(d0, i, v2, (u8>>(i*2))&3);
}
if(MODREG) {
for(int i=2; i<4; ++i) {
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
}
} else {
SMREAD();
for(int i=2; i<4; ++i) {
ADDx_U12(x2, ed, 16+((u8>>(i*2))&3)*4);
VLD1_32(d0, i, x2);
}
}
VMOVQ(v0, d0);
}
} else YMM0(gd);
break;
default:
DEFAULT;
}
return addr;
}
-302
View File
@@ -1,302 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
int need_tst;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch(opcode) {
case 0xF2:
INST_NAME("ANDN Gd, Vd, Ed");
nextop = F8;
SETFLAGS(X_ALL, SF_SET);
GETGD;
GETED(0);
GETVD;
need_tst = 0;
IFX(X_ZF) need_tst = 1;
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
IFXNATIVE(X_CF, NF_CF) need_tst = 1;
if(need_tst)
BICSxw(gd, ed, vd);
else
BICxw(gd, ed, vd);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(x1, cEQ);
BFIw(xFlags, x1, F_ZF, 1);
}
}
IFX(X_OF) {
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
}
IFX(X_CF) {
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
}
IFX(X_SF) {
IFNATIVE(NF_SF) {} else {
LSRxw_IMM(x1, gd, rex.w?63:31);
BFIw(xFlags, x1, F_SF, 1);
}
}
break;
case 0xF3:
nextop = F8;
switch((nextop>>3)&7) {
case 1:
INST_NAME("BLSR Vd, Ed");
SETFLAGS(X_ALL, SF_SET);
GETED(0);
GETVD;
IFX(X_CF) {
TSTxw_REG(ed, ed);
CSETMw(x3, cEQ);
BFIw(xFlags, x3, F_CF, 1);
}
SUBxw_U12(x3, ed, 1);
need_tst = 0;
IFX(X_ZF) need_tst = 1;
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
if(need_tst)
ANDSxw_REG(vd, ed, x3);
else
ANDxw_REG(vd, ed, x3);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETMw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1);
}
}
IFX(X_SF) {
IFNATIVE(NF_SF) {} else {
LSRxw(x3, vd, rex.w?63:31);
BFIw(xFlags, x3, F_SF, 1);
}
}
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
if (BOX64ENV(dynarec_test)) {
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
}
break;
case 2:
INST_NAME("BLSMSK Vd, Ed");
SETFLAGS(X_ALL, SF_SET);
GETED(0);
GETVD;
IFX(X_CF) {
TSTxw_REG(ed, ed);
CSETMw(x3, cEQ);
BFIw(xFlags, x3, F_CF, 1);
}
SUBxw_U12(x3, ed, 1);
need_tst = 0;
IFX(X_ZF) need_tst = 1;
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
EORxw_REG(vd, ed, x3);
if(need_tst)
TSTxw_REG(vd, vd);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETMw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1);
}
}
IFX(X_SF) {
IFNATIVE(NF_SF) {} else {
LSRxw(x3, vd, rex.w?63:31);
BFIw(xFlags, x3, F_SF, 1);
}
}
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
if (BOX64ENV(dynarec_test)) {
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
}
break;
case 3:
INST_NAME("BLSI Vd, Ed");
SETFLAGS(X_ALL, SF_SET);
GETED(0);
GETVD;
IFX(X_CF) {
TSTxw_REG(ed, ed);
CSETMw(x3, cEQ);
BFIw(xFlags, x3, F_CF, 1);
}
NEGxw_REG(x3, ed);
need_tst = 0;
IFX(X_ZF) need_tst = 1;
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
if(need_tst)
ANDSxw_REG(vd, ed, x3);
else
ANDxw_REG(vd, ed, x3);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETMw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1);
}
}
IFX(X_SF) {
IFNATIVE(NF_SF) {} else {
LSRxw(x3, vd, rex.w?63:31);
BFIw(xFlags, x3, F_SF, 1);
}
}
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
if (BOX64ENV(dynarec_test)) {
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
}
break;
default:
DEFAULT;
}
break;
case 0xF5:
INST_NAME("BZHI Gd, Ed, Vd");
nextop = F8;
SETFLAGS(X_ALL, SF_SET);
GETGD;
GETED(0);
GETVD;
UXTBw(x1, vd);
CMPSw_U12(x1, rex.w?64:32);
CSETMxw(x2, cPL);
IFX(X_CF) {
BFIw(xFlags, x2, F_CF, 1);
}
MVNxw_REG(x2, x2); //prepare mask
B_MARK(cPL);
LSLxw_REG(x2, x2, x1);
MARK;
need_tst = 0;
IFX(X_ZF) need_tst = 1;
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
if(need_tst) {
BICSxw(gd, ed, x2);
} else
BICxw(gd, ed, x2);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1);
}
}
IFX(X_SF) {
IFNATIVE(NF_SF) {} else {
LSRxw(x3, gd, rex.w?63:31);
BFIw(xFlags, x3, F_SF, 1);
}
}
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
break;
case 0xF7:
INST_NAME("BEXTR Gd, Ed, Vd");
nextop = F8;
SETFLAGS(X_ALL, SF_SET);
GETGD;
GETED(0);
GETVD;
MOV64xw(x1, 0);
UXTBw(x2, vd); // start
BFXILw(x3, vd, 8, 8); // length
TSTw_REG(x3, x3);
B_MARK(cEQ);
LSRxw_REG(x1, ed, x2);
CMPSw_U12(x3, rex.w?64:32);
B_MARK(cGE);
MOV32w(x2, rex.w?64:32);
SUBw_REG(x2, x2, x3);
LSLxw_REG(x1, x1, x2);
LSRxw_REG(x1, x1, x2);
TSTxw_REG(x1, x1);
MARK;
MOVxw_REG(gd, x1);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1);
}
}
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
IFX(X_CF) BFCw(xFlags, F_CF, 1);
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
IFX(X_SF) IFNATIVE(NF_SF) {} else {BFCw(xFlags, F_SF, 1);}
break;
default:
DEFAULT;
}
return addr;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,835 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
#if STEP > 1
static const int8_t round_round[] = { 0, 2, 1, 3};
#endif
rex_t rex = vex.rex;
switch(opcode) {
case 0x00:
case 0x01:
if(opcode) {INST_NAME("VPERMPD Gx, Ex, Imm8");} else {INST_NAME("VPERMQ Gx, Ex, Imm8");}
nextop = F8;
GETGX_empty_EX(v0, q0, 1);
u8 = F8;
if(v0==q0) d0 = fpu_get_scratch(dyn, ninst);
if(v0==q0 || !MODREG) d1 = fpu_get_scratch(dyn, ninst);
q1 = d1;
GETGY_empty_EY(v1, q1);
if(v0==q0) { VMOVQ(d0, q0); VMOVQ(d1, q1); } else {d1 = q1; d0 = q0;}
VMOVeD(v0, 0, ((u8>>1)&1)?d1:d0, (u8>>0)&1);
VMOVeD(v0, 1, ((u8>>3)&1)?d1:d0, (u8>>2)&1);
VMOVeD(v1, 0, ((u8>>5)&1)?d1:d0, (u8>>4)&1);
VMOVeD(v1, 1, ((u8>>7)&1)?d1:d0, (u8>>6)&1);
break;
case 0x02:
INST_NAME("VPBLENDD Gx, Vx, Ex, u8");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8;} else { GETGY_empty_VYEY(v0, v2, v1); u8 >>=4;}
wb1 = 0; // mask
for(int i=0; i<4; ++i)
if(u8&(1<<i))
wb1 |= (3<<(i*2));
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
SXTL_16(q0, q0); // expand 16bits to 32bits...
if(v0==v1) {
VBIFQ(v0, v2, q0);
} else {
if(v0!=v2) VMOVQ(v0, v2);
VBITQ(v0, v1, q0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x04:
INST_NAME("VPERMILPS Gx, Ex, Imm8");
nextop = F8;
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETGX_empty_EX(v0, v1, 1);
u8 = F8;
if(v0==v1) {q1 = fpu_get_scratch(dyn, ninst); VMOVQ(q1, v1);}
} else {
GETGY_empty_EY(v0, v1);
if(v0==v1) {VMOVQ(q1, v1);}
}
if(u8==0x00 || u8==0x55 || u8==0xAA || u8==0xFF)
VDUPQ_32(v0, (v0==v1)?q1:v1, u8&3);
else if(u8==0x50)
VZIP1Q_32(v0, v1, v1);
else if(u8==0xFA)
VZIP2Q_32(v0, v1, v1);
else if(u8==0xA0)
VTRNQ1_32(v0, v1, v1);
else if(u8==0xF5)
VTRNQ2_32(v0, v1, v1);
else for(int i=0; i<4; ++i)
VMOVeS(v0, i, (v0==v1)?q1:v1, (u8>>(i*2))&3);
}
if(!vex.l) YMM0(gd);
break;
case 0x05:
INST_NAME("VPERMILD Gx, Ex, Imm8");
nextop = F8;
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETGX_empty_EX(v0, v1, 1);
u8 = F8;
} else {
GETGY_empty_EY(v0, v1);
}
switch(((u8>>(l*2))&3)) {
case 0b00:
case 0b11:
VDUPQ_64(v0, v1, ((u8>>(l*2))&1));
break;
case 0b10:
if(v0!=v1) VMOVQ(v0, v1);
break;
case 0b01:
VEXTQ_8(v0, v1, v1, 8); // invert 64bits values
break;
}
}
if(!vex.l) YMM0(gd);
break;
case 0x06:
case 0x46:
if(opcode==0x06) { INST_NAME("VPERM2F128 Gx, Vx, Ex, Imm8"); } else { INST_NAME("VPERM2I128 Gx, Vx, Ex, Imm8"); }
nextop = F8;
if(!vex.l) UDF(0);
if(MODREG) {
s0 = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg(dyn, ninst, x1, s0, 0);
} else {
s0 = -1;
v1 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
}
u8 = F8;
GETVX(v2, 0);
GETGX_empty(v0);
if((v0==v2) && ((u8&0xf0)==0)) {
q0 = fpu_get_scratch(dyn, ninst);
VMOVQ(q0, v2);
v2 = q0;
}
if((v0==v1) && ((u8&0xf0)==0x20)) {
q1 = fpu_get_scratch(dyn, ninst);
VMOVQ(q1, v1);
v1 = q1;
}
switch(u8&0x0f) {
case 0: if(v0!=v2) VMOVQ(v0, v2); break;
case 1: d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); VMOVQ(v0, d2); break;
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
case 3: if(MODREG) { d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
default: VEORQ(v0, v0, v0);
}
if((u8&0xf0)==0x10) { if((u8&0x0f)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
if(MODREG && ((u8&0xf0)==0x30)) { if((u8&0x0f)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, s0, -1);
switch((u8>>4)&0x0f) {
case 0: VMOVQ(v0, v2); break;
case 1: if(v0!=d2) VMOVQ(v0, d2); break;
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
case 3: if(MODREG) { if(v0!=d1) VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
default: VEORQ(v0, v0, v0);
}
break;
case 0x08:
INST_NAME("VROUNDPS Gx, Ex, Ib");
nextop = F8;
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_EX(v0, v1, 1); u8 = F8; } else { GETGY_empty_EY(v0, v1); }
if(u8&4) {
if(!l) wb1 = sse_setround(dyn, ninst, x1, x2, x4);
VFRINTISQ(v0, v1);
if(l || !vex.l) x87_restoreround(dyn, ninst, wb1);
} else {
VFRINTRSQ(v0, v1, round_round[u8&3]);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x09:
INST_NAME("VROUNDPD Gx, Ex, Ib");
nextop = F8;
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_EX(v0, v1, 1); u8 = F8; } else { GETGY_empty_EY(v0, v1); }
if(u8&4) {
if(!l) wb1 = sse_setround(dyn, ninst, x1, x2, x4);
VFRINTIDQ(v0, v1);
if(l || !vex.l) x87_restoreround(dyn, ninst, wb1);
} else {
VFRINTRDQ(v0, v1, round_round[u8&3]);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x0A:
INST_NAME("VROUNDSS Gx, Vx, Ex, Ib");
nextop = F8;
GETEXSS(v1, 0, 1);
GETGX_empty_VX(v0, v2);
u8 = F8;
d1 = fpu_get_scratch(dyn, ninst);
if(u8&4) {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
FRINTXS(d1, v1);
x87_restoreround(dyn, ninst, u8);
} else {
FRINTRRS(d1, v1, round_round[u8&3]);
}
if(v0!=v2) VMOVQ(v0, v2);
VMOVeS(v0, 0, d1, 0);
YMM0(gd);
break;
case 0x0B:
INST_NAME("VROUNDSD Gx, Vx, Ex, Ib");
nextop = F8;
GETEXSD(v1, 0, 1);
GETGX_empty_VX(v0, v2);
u8 = F8;
d1 = fpu_get_scratch(dyn, ninst);
if(u8&4) {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
FRINTXD(d1, v1);
x87_restoreround(dyn, ninst, u8);
} else {
FRINTRRD(d1, v1, round_round[u8&3]);
}
if(v0!=v2) VMOVQ(v0, v2);
VMOVeD(v0, 0, d1, 0);
YMM0(gd);
break;
case 0x0C:
INST_NAME("VBLENDPS Gx, Vx, Ex, Ib");
nextop = F8;
GETGX_empty_VXEX(q0, q2, q1, 1);
u8 = F8;
if((u8&0xf)==0xf) {
if(q0!=q1) VMOVQ(q0, q1);
} else if(q0==q1) {
for(int i=0; i<4; ++i)
if(u8&(1<<i)) {
VMOVeS(q0, i, q1, i);
} else if(q0!=q2)
VMOVeS(q0, i, q2, i);
} else {
if(q0!=q2)
VMOVQ(q0, q2);
if((u8&15)==0b0011) {
VMOVeD(q0, 0, q1, 0);
} else if((u8&15)==0b1100) {
VMOVeD(q0, 1, q1, 1);
} else for(int i=0; i<4; ++i)
if(u8&(1<<i)) {
VMOVeS(q0, i, q1, i);
}
}
if(vex.l) {
GETGY_empty_VYEY(q0, q2, q1);
if((u8&0xf0)==0xf0) {
if(q0!=q1) VMOVQ(q0, q1);
} else if(q0==q1) {
for(int i=0; i<4; ++i)
if(u8&(1<<(i+4))) {
VMOVeS(q0, i, q1, i);
} else if(q0!=q2)
VMOVeS(q0, i, q2, i);
} else {
if(q0!=q2)
VMOVQ(q0, q2);
if((u8>>4)==0b0011) {
VMOVeD(q0, 0, q1, 0);
} else if((u8>>4)==0b1100) {
VMOVeD(q0, 1, q1, 1);
} else for(int i=0; i<4; ++i)
if(u8&(1<<(i+4))) {
VMOVeS(q0, i, q1, i);
}
}
} else YMM0(gd);
break;
case 0x0D:
INST_NAME("VBLENDPD Gx, Vx, Ex, Ib");
nextop = F8;
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 1); u8 = F8; } else { GETGY_empty_VYEY(q0, q2, q1); }
switch(u8>>(l*2)&3) {
case 0b00: if(q0!=q2) VMOVQ(q0, q2); break; // VxVx
case 0b01: if(q0!=q1) VMOVeD(q0, 0, q1, 0); if(q0!=q2) VMOVeD(q0, 1, q2, 1); break; // Ex[0]Vx[1]
case 0b10: if(q0!=q2) VMOVeD(q0, 0, q2, 0); if(q0!=q1) VMOVeD(q0, 1, q1, 1); break; // Vx[0]Ex[1]
case 0b11: if(q0!=q1) VMOVQ(q0, q1); break; // ExEx
}
}
if(!vex.l) YMM0(gd);
break;
case 0x0E:
INST_NAME("VPBLENDW Gx, Vx, Ex, u8");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8;} else { GETGY_empty_VYEY(v0, v2, v1); }
if(!l) {
MOVI_64(q0, u8);
SXTL_8(q0, q0); // expand 8bits to 16bits...
}
if(v0==v1) {
VBIFQ(v0, v2, q0);
} else {
if(v0!=v2) VMOVQ(v0, v2);
VBITQ(v0, v1, q0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x0F:
INST_NAME("VPALIGNR Gx, Vx, Ex, Ib");
nextop = F8;
d0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETGX_empty_VXEX(v0, v2, v1, 1);
u8 = F8;
} else {
GETGY_empty_VYEY(v0, v2, v1);
}
if(u8>31) {
VEORQ(v0, v0, v0);
} else if(u8>15) {
if(!l) VEORQ(d0, d0, d0);
VEXTQ_8(v0, v2, d0, u8-16);
} else {
VEXTQ_8(v0, v1, v2, u8);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x14:
INST_NAME("VPEXTRB Ed, Gx, imm8");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
ed = x1;
}
u8 = F8;
VMOVBto(ed, v0, u8&0x0f);
if(!MODREG) {
STB(ed, wback, fixedaddress);
}
break;
case 0x15:
INST_NAME("VPEXTRW Ed, Gx, imm8");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 1);
ed = x1;
}
u8 = F8;
VMOVHto(ed, v0, u8&7);
if(!MODREG) {
STH(ed, wback, fixedaddress);
}
break;
case 0x16:
INST_NAME("VPEXTRD/Q Ed, Gx, imm8");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
ed = x1;
}
u8 = F8;
if(rex.w) {
VMOVQDto(ed, v0, u8&1);
} else {
VMOVSto(ed, v0, u8&3);
}
if(!MODREG) {
STxw(ed, wback, fixedaddress);
}
break;
case 0x17:
INST_NAME("VEXTRACTPS Ed, Gx, imm8");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
ed = x1;
}
u8 = F8;
VMOVSto(ed, v0, u8&3);
if(!MODREG) {
STW(ed, wback, fixedaddress);
}
break;
case 0x18:
case 0x38:
if(opcode==0x18) {INST_NAME("VINSERTF128 Gx, Vx, Ex, imm8");} else {INST_NAME("VINSERTI128 Gx, Vx, Ex, imm8");}
nextop = F8;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
v1 = -1; // to avoid a warning
}
u8 = F8;
GETVX(v2, 0);
GETGX_empty(v0);
if(v0==v2 && u8==1) {
GETGY_empty(q0, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
q2 = q0;
} else {
GETGY_empty_VY(q0, q2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
}
if(MODREG)
VMOVQ((u8&1)?q0:v0, v1);
else
VLD128((u8&1)?q0:v0, ed, fixedaddress);
if(v0!=v2)
VMOVQ((u8&1)?v0:q0, (u8&1)?v2:q2);
break;
case 0x19:
case 0x39:
if(opcode==0x19) {INST_NAME("VEXTRACTF128 Ex, Gx, imm8");} else {INST_NAME("VEXTRACTI128 Ex, Gx, imm8");}
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop);
GETGX(v0, 0);
if(u8&1) {GETGY(v0, ((nextop&7)+(rex.b<<3)==gd && MODREG)?1:0, -1, -1, -1);}
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOVQ(v1, v0);
if((nextop&7)+(rex.b<<3)==gd && (u8&1))
VEORQ(v0, v0, v0); // special case like vextractf128 xmm3, ymm3, 0x01
else
YMM0((nextop&7)+(rex.b<<3));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
VST128(v0, ed, fixedaddress);
}
F8; // read u8, but it's been already handled
break;
case 0x1D:
INST_NAME("VCVTPS2PH Ex, Gx");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3));
} else {
v1 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<(3+vex.l), vex.l?15:7, rex, NULL, 0, 1);
}
if(vex.l && v0==v1) {
q0 = fpu_get_scratch(dyn, ninst);
VMOVQ(q0, v0);
v0 = q0;
}
u8 = F8;
if(u8&4) {
s0 = sse_setround(dyn, ninst, x1, x2, x6);
} else {
u8&=3;
if(u8==1) u8=2;
else if(u8==2) u8=1;
MRS_fpcr(x1); // get fpscr
MOV32w(x2, u8);
MOVx_REG(x6, x1);
BFIx(x1, x2, 22, 2); // inject new round
MSR_fpcr(x1); // put new fpscr
s0 = x6;
}
FCVTN16(v1, v0);
if(vex.l) {
GETGY(v0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1,-1);
FCVTN162(v1, v0);
}
x87_restoreround(dyn, ninst, s0);
if(MODREG) {
YMM0((nextop&7)+(rex.b<<3));
} else {
if(vex.l) {
VST128(v1, ed, fixedaddress);
} else {
VST64(v1, ed, fixedaddress);
}
SMWRITE2();
}
break;
case 0x20:
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
nextop = F8;
GETGX_empty_VX(v0, v2);
GETED(1);
u8 = F8;
if(v0!=v2) VMOVQ(v0, v2);
VMOVQBfrom(v0, u8&0xf, ed);
YMM0(gd);
break;
case 0x21:
INST_NAME("VINSERTPS Gx, Vx, Ex, Ib");
nextop = F8;
if (MODREG) {
GETGX_empty_VXEX(v0, v2, v1, 1);
u8 = F8;
if(v0==v1) {
d0 = fpu_get_scratch(dyn, ninst);
VMOVQ(d0, v1);
if(v0!=v2) VMOVQ(v0, v2);
VMOVeS(v0, (u8>>4)&3, d0, (u8>>6)&3);
} else {
if(v0!=v2) VMOVQ(v0, v2);
VMOVeS(v0, (u8>>4)&3, v1, (u8>>6)&3);
}
} else {
GETGX_empty_VX(v0, v2);
if(v0!=v2) VMOVQ(v0, v2);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
u8 = F8;
LDW(x2, wback, fixedaddress);
VMOVQSfrom(v0, (u8>>4)&3, x2);
}
uint8_t zmask = u8 & 0xf;
for (uint8_t i=0; i<4; i++) {
if (zmask & (1<<i)) {
VMOVQSfrom(v0, i, wZR);
}
}
YMM0(gd);
break;
case 0x22:
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
nextop = F8;
GETGX_empty_VX(v0, v2);
GETED(1);
u8 = F8;
if(v0!=v2) VMOVQ(v0, v2);
if(rex.w)
VMOVQDfrom(v0, u8&1, ed);
else
VMOVQSfrom(v0, u8&3, ed);
YMM0(gd);
break;
case 0x40:
INST_NAME("VDPPS Gx, Vx, Ex, Ib");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop);
q0 = fpu_get_scratch(dyn, ninst);
// first mask
if((u8&0x0f)!=0x0f) {
wb1 = 0; // mask
for(int i=0; i<4; ++i)
if(u8&(1<<i))
wb1 |= (3<<(i*2));
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
SXTL_16(q0, q0); // expand 16bits to 32bits...
}
if((u8&0xf0)!=0xf0) {
q1 = fpu_get_scratch(dyn, ninst);
// second mask
wb1 = 0; // mask
for(int i=0; i<4; ++i)
if((u8>>4)&(1<<i))
wb1 |= (3<<(i*2));
MOVI_64(q1, wb1); // load 8bits value as a 8bytes mask
SXTL_16(q1, q1); // expand 16bits to 32bits...
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
VFMULQS(v0, v2, v1);
if((u8&0xf0)!=0xf0) {
VANDQ(v0, v0, q1); // second mask
}
VFADDPQS(v0, v0, v0);
FADDPS(v0, v0);
VDUPQ_32(v0, v0, 0);
if((u8&0x0f)!=0x0f) {
VANDQ(v0, v0, q0); // first mask
}
}
if(!vex.l) YMM0(gd);
break;
case 0x41:
INST_NAME("VDPPD Gx, Vx, Ex, Ib");
nextop = F8;
GETGX_empty_VXEX(v0, v1, v2, 0);
u8 = F8;
VFMULQD(v0, v1, v2);
// mask some, duplicate all, mask some
for(int i=0; i<2; ++i)
if(!(u8&(1<<(4+i)))) {
VMOVQDfrom(v0, i, xZR);
}
FADDPD(v0, v0);
VDUPQ_64(v0, v0, 0);
for(int i=0; i<2; ++i)
if(!(u8&(1<<i))) {
VMOVQDfrom(v0, i, xZR);
}
if(!vex.l) YMM0(gd);
break;
case 0x44:
INST_NAME("PCLMULQDQ Gx, Vx, Ex, Ib");
nextop = F8;
if(arm64_pmull) {
d0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETGX_empty_VXEX(v0, v2, v1, 1);
u8 = F8;
} else {
GETGY_empty_VYEY(v0, v2, v1);
}
switch (u8&0b00010001) {
case 0b00000000:
PMULL_128(v0, v2, v1);
break;
case 0b00010001:
PMULL2_128(v0, v2, v1);
break;
case 0b00000001:
VEXTQ_8(d0, v2, v2, 8); // Swap Up/Lower 64bits parts
PMULL_128(v0, d0, v1);
break;
case 0b00010000:
VEXTQ_8(d0, v2, v2, 8); // Swap Up/Lower 64bits parts
PMULL2_128(v0, d0, v1);
break;
}
}
} else {
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETG;
sse_forget_reg(dyn, ninst, gd);
sse_reflect_reg(dyn, ninst, vex.v);
}
MOV32w(x1, gd); // gx
MOV32w(x2, vex.v); // vx
if(MODREG) {
if(!l) {
ed = (nextop&7)+(rex.b<<3);
sse_forget_reg(dyn, ninst, ed);
}
MOV32w(x3, ed);
} else {
if(!l) {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
if(ed!=x3) {
MOVx_REG(x3, ed);
}
} else {
ADDx_U12(x3, ed, 16);
}
}
if(!l) u8 = F8;
MOV32w(x4, u8);
CALL_(l?native_pclmul_y:native_pclmul_x, -1, x3);
}
}
if(!vex.l) YMM0(gd);
break;
//case 0x46: // see 0x06
case 0x4A:
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
GETGX_empty_VXEX(v0, v2, v1, 1);
F8;
} else {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
if(MODREG)
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
else
VLDR128_U12(v1, ed, fixedaddress+16);
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
}
VSSHRQ_32(q0, q1, 31); // create mask
if(v0==v1)
VBIFQ(v0, v2, q0);
else {
if(v0!=v2) VMOVQ(v0, v2);
VBITQ(v0, v1, q0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x4B:
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
GETGX_empty_VXEX(v0, v2, v1, 1);
F8;
} else {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
if(MODREG)
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
else
VLDR128_U12(v1, ed, fixedaddress+16);
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
}
VSSHRQ_64(q0, q1, 63); // create mask
if(v0==v1)
VBIFQ(v0, v2, q0);
else {
if(v0!=v2) VMOVQ(v0, v2);
VBITQ(v0, v1, q0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x4C:
INST_NAME("VBLENDPVB Gx, Vx, Ex, XMMImm8");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
GETGX_empty_VXEX(v0, v2, v1, 1);
F8;
} else {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
if(MODREG)
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
else
VLDR128_U12(v1, ed, fixedaddress+16);
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
}
VSSHRQ_8(q0, q1, 7); // create mask
if(v0==v1)
VBIFQ(v0, v2, q0);
else {
if(v0!=v2) VMOVQ(v0, v2);
VBITQ(v0, v1, q0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0xDF:
INST_NAME("VAESKEYGENASSIST Gx, Ex, Ib");
nextop = F8;
GETG;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd); // gx
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
sse_forget_reg(dyn, ninst, ed);
MOV32w(x2, ed);
MOV32w(x3, 0); //p = NULL
} else {
MOV32w(x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
if(ed!=x3) {
MOVx_REG(x3, ed);
}
}
u8 = F8;
MOV32w(x4, u8);
CALL(native_aeskeygenassist, -1);
if(!vex.l) YMM0(gd);
break;
default:
DEFAULT;
}
return addr;
}
-554
View File
@@ -1,554 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u, u64;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch(opcode) {
case 0x10:
INST_NAME("VMOVSD Gx, [Vx,] Ex");
nextop = F8;
GETG;
if(MODREG) {
GETGX_empty_VXEX(v0, v2, v1, 0);
if(v0!=v1) VMOVeD(v0, 0, v1, 0);
if(v0!=v2) VMOVeD(v0, 1, v2, 1);
} else {
SMREAD();
GETGX_empty(v0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
VLD64(v0, ed, fixedaddress); // upper part reseted
}
YMM0(gd);
break;
case 0x11:
INST_NAME("VMOVSD Ex, Vx, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
GETVXEX(v2, 0, v1, 1, 0);
if(v0!=v1) VMOVeD(v1, 0, v0, 0);
if(v1!=v2) VMOVeD(v1, 1, v2, 1);
YMM0((nextop&7)+(rex.b<<3));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
VST64(v0, ed, fixedaddress);
SMWRITE2();
}
break;
case 0x12:
INST_NAME("VMOVDDUP Gx, Ex");
nextop = F8;
GETG;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX_empty(v0);
VDUPQ_64(v0, v1, 0);
if(vex.l) {
GETGY_empty_EY(v0, v1);
VDUPQ_64(v0, v1, 0);
}
} else {
SMREAD();
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VLDQ1R_64(v0, ed);
if(vex.l) {
GETGY_empty(v0, -1, -1, -1);
ADDx_U12(x3, ed, 16);
VLDQ1R_64(v0, x3);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x2A:
INST_NAME("VCVTSI2SD Gx, Vx, Ed");
nextop = F8;
GETGX_empty_VX(v0, v1);
GETED(0);
d1 = fpu_get_scratch(dyn, ninst);
if(rex.w) {
SCVTFDx(d1, ed);
} else {
SCVTFDw(d1, ed);
}
if(v0!=v1) VMOVQ(v0, v1);
VMOVeD(v0, 0, d1, 0);
YMM0(gd);
break;
case 0x2C:
INST_NAME("VCVTTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETEXSD(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
FCVTZSxwD(gd, q0);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
} else {
MOV32w(gd, 0x80000000);
}
}
break;
case 0x2D:
INST_NAME("VCVTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETEXSD(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
u8 = sse_setround(dyn, ninst, x1, x2, x3);
d1 = fpu_get_scratch(dyn, ninst);
FRINTID(d1, q0);
x87_restoreround(dyn, ninst, u8);
FCVTZSxwD(gd, d1);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
} else {
MOV32w(gd, 0x80000000);
}
}
break;
case 0x51:
INST_NAME("VSQRTSD Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FCMEQD(q0, v1, v1); // 0 if NAN, 1 if not NAN
}
FSQRTD(d1, v1);
if(!BOX64ENV(dynarec_fastnan)) {
FCMEQD(q1, d1, d1); // 0 => out is NAN
VBIC(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORR(d1, d1, q1); // NAN -> -NAN
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, d1, 0);
YMM0(gd)
break;
case 0x58:
INST_NAME("VADDSD Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FADDD(q2, v1, v2); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FADDD(q2, v1, v2); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x59:
INST_NAME("VMULSD Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FMULD(q2, v1, v2); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FMULD(q2, v1, v2); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd);
break;
case 0x5A:
INST_NAME("VCVTSD2SS Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(BOX64ENV(dynarec_fastround)==2) {
FCVT_S_D(d1, v1);
} else {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
FCVT_S_D(d1, v1);
x87_restoreround(dyn, ninst, u8);
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d1, 0);
YMM0(gd)
break;
case 0x5C:
INST_NAME("VSUBSD Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FSUBD(q2, v2, v1); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FSUBD(q2, v2, v1); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x5D:
INST_NAME("VMINSD Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
// VMINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
FCMPD(v2, v1);
FCSELD(d1, v1, v2, cCS);
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
break;
case 0x5E:
INST_NAME("VDIVSD Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FDIVD(q2, v2, v1); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FDIVD(q2, v2, v1); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x5F:
INST_NAME("VMAXSD Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSD(v1, 0, 0);
GETGX_empty_VX(v0, v2);
FCMPD(v1, v2);
FCSELD(d1, v1, v2, cCS);
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeD(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
break;
case 0x70:
INST_NAME("VPSHUFLW Gx, Ex, Ib");
nextop = F8;
d0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETEX_Y(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
if(v0==v1) {
VMOVQ(d0, v1);
}
VDUP_16(v0, v1, u8&3);
if(v0==v1)
v1 = d0;
} else {
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
if(!l) {
u64 = 0;
for (int i=0; i<4; ++i) {
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
}
MOV64x(x2, u64);
}
VMOVQDfrom(d0, 0, x2);
VTBL1_8(d0, v1, d0);
VMOVeD(v0, 0, d0, 0);
}
if(v0!=v1) {
VMOVeD(v0, 1, v1, 1);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x7C:
INST_NAME("VHADDPS Gx, Vx, Ex");
nextop = F8;
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
VFADDPQS(v0, v2, v1);
}
if(!vex.l) YMM0(gd);
break;
case 0x7D:
INST_NAME("VHSUBPS Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
if(MODREG || (v1==v2)) {
q1 = fpu_get_scratch(dyn, ninst);
} else
q1 = v1;
if(vex.l)
q2 = fpu_get_scratch(dyn, ninst);
else
q2 = q0;
// q0 will contains -1 / 0 / -1 / 0
MOVIQ_64(q0, 0xf0);
VSHLQ_32(q0, q0, 31); // keep sign bit
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
VEORQ(q1, v1, q0);
VEORQ(q2, v2, q0);
VFADDPQS(v0, q2, q1);
}
if(!vex.l) YMM0(gd);
break;
case 0xC2:
INST_NAME("CMPSD Gx, Ex, Ib");
nextop = F8;
GETEXSD(v1, 0, 1);
GETGX_empty_VX(v0, v2);
u8 = F8;
FCMPD(v2, v1);
if(v0!=v2) VMOVQ(v0, v2);
switch(u8&7) {
case 0: CSETMx(x2, cEQ); break; // Equal
case 1: CSETMx(x2, cCC); break; // Less than
case 2: CSETMx(x2, cLS); break; // Less or equal
case 3: CSETMx(x2, cVS); break; // NaN
case 4: CSETMx(x2, cNE); break; // Not Equal or unordered
case 5: CSETMx(x2, cCS); break; // Greater or equal or unordered
case 6: CSETMx(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
case 7: CSETMx(x2, cVC); break; // not NaN
}
VMOVQDfrom(v0, 0, x2);
YMM0(gd);
break;
case 0xD0:
INST_NAME("VADDSUBPS Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
MAYUSE(addsubps);
MOV64x(x2, (uintptr_t)&addsubps);
VLDR128_U12(q0, x2, 0);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(v0==v1) {
//TODO: find a better way
if(!l) q1 = fpu_get_scratch(dyn, ninst);
VMOVQ(q1, v2);
VFMLAQS(q1, v1, q0);
VMOVQ(v0, q1);
} else {
if(v0!=v2) VMOVQ(v0, v2);
VFMLAQS(v0, v1, q0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0xE6:
INST_NAME("VCVTPD2DQ Gx, Ex");
nextop = F8;
u8 = sse_setround(dyn, ninst, x1, x2, x6);
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETEX_Y(v1, 0, 0);
GETGX_empty(v0);
if(!BOX64ENV(dynarec_fastround) || vex.l)
d0 = fpu_get_scratch(dyn, ninst);
} else {
GETEY(v1);
}
if(BOX64ENV(dynarec_fastround)) {
VFRINTIDQ(l?d0:v0, v1);
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
if(!l)
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
else
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
} else {
if(!l) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
ORRw_mask(x4, xZR, 1, 0); //0x80000000
}
for(int i=0; i<2; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if(i) {
VMOVeD(d0, 0, v1, i);
FRINTID(d0, d0);
} else {
FRINTID(d0, v1);
}
FCVTZSwD(x1, d0);
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
CSELx(x1, x1, x4, cEQ);
VMOVQSfrom(v0, i+l*2, x1);
}
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
}
}
x87_restoreround(dyn, ninst, u8);
YMM0(gd);
break;
case 0xF0:
INST_NAME("LDDQU Gx,Ex");
nextop = F8;
GETG;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
if(vex.l) {
GETGY_empty_EY(v0, v1);
VMOVQ(v0, v1);
}
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 7, rex, NULL, 0, 0);
VLDR128_U12(v0, ed, fixedaddress);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
VLDR128_U12(v0, ed, fixedaddress+16);
}
if(!vex.l) YMM0(gd);
break;
default:
DEFAULT;
}
return addr;
}
@@ -1,131 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F2_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch(opcode) {
case 0xF5:
INST_NAME("PDEP Gd, Ed, Vd");
nextop = F8;
GETGD;
GETED(0);
GETVD;
if(gd==ed || gd==vd) {
gb1 = gd;
gd = x4;
} else {
gb1 = 0;
}
// x3 = mask of mask, loop while not 0
MOV32w(gd, 0);
MOV64x(x2, 1);
MOV64x(x3, 1);
MARK;
TSTxw_REG(ed, x3);
B_MARK2(cEQ);
TSTxw_REG(vd, x2);
B_MARK3(cEQ);
ORRxw_REG(gd, gd, x3);
MARK3;
LSLxw_IMM(x2, x2, 1);
MARK2;
LSLxw_IMM(x3, x3, 1);
CBNZxw_MARK(x3);
if(gb1)
MOVxw_REG(gb1, gd);
break;
case 0xF6:
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
nextop = F8;
GETGD;
GETED(0);
GETVD;
if(rex.w) {
// 64bits mul
if((gd==xRDX) || (gd==ed) || (gd==vd))
gb1 = x3;
else
gb1 = gd;
UMULH(gb1, xRDX, ed);
if(gd!=vd) {MULx(vd, xRDX, ed);}
if(gb1==x3) {
MOVx_REG(gd, gb1);
}
} else {
// 32bits mul
UMULL(x3, xRDX, ed);
if(gd!=vd) {MOVw_REG(vd, x3);}
LSRx(gd, x3, 32);
}
break;
case 0xF7:
INST_NAME("SHRX Gd, Ed, Vd");
nextop = F8;
GETGD;
GETED(0);
GETVD;
ANDx_mask(x3, vd, 1, 0, rex.w?5:4); // mask 0x3f/0x1f
LSRxw_REG(gd, ed, x3);
break;
default:
DEFAULT;
}
return addr;
}
@@ -1,78 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F2_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch(opcode) {
case 0xF0:
INST_NAME("RORX Gd, Ed, Ib");
nextop = F8;
GETGD;
GETED(1);
u8 = F8;
u8&=rex.w?0x3f:0x1f;
RORxw(gd, ed, u8);
break;
default:
DEFAULT;
}
return addr;
}
-582
View File
@@ -1,582 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u, u64;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch(opcode) {
case 0x10:
INST_NAME("VMOVSS Gx, Ex [,Vx]");
nextop = F8;
GETG;
if(MODREG) {
GETGX_empty_VXEX(v0, v2, v1, 0);
if((v0!=v2) && (v0!=v1)) VMOVQ(v0, v2);
if(v0!=v1) VMOVeS(v0, 0, v1, 0);
if((v0!=v2) && (v0==v1)) { VMOVeS(v0, 1, v2, 1); VMOVeD(v0, 1, v2, 1);}
} else {
GETGX_empty(v0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v0, ed, fixedaddress);
}
YMM0(gd);
break;
case 0x11:
INST_NAME("VMOVSS Ex, Gx [,Vx]");
nextop = F8;
GETG;
if(MODREG) {
GETGXVXEX_empty(v0, v2, v1, 0);
if((v2!=v1) && (v2!=v0)) VMOVQ(v2, v1);
if(v2!=v0) VMOVeS(v2, 0, v0, 0);
if((v2!=v1) && (v2==v0)) { VMOVeS(v2, 1, v0, 1); VMOVeD(v2, 1, v0, 1);}
YMM0((nextop&7)+(rex.b<<3));
} else {
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VST32(v0, ed, fixedaddress);
SMWRITE2();
}
break;
case 0x12:
INST_NAME("VMOVSLDUP Gx, Ex");
nextop = F8;
GETEX_Y(q1, 0, 0);
GETGX_empty(q0);
VTRNQ1_32(q0, q1, q1);
if(vex.l) {
GETGY_empty_EY(q0, q1);
VTRNQ1_32(q0, q1, q1);
} else YMM0(gd);
break;
case 0x16:
INST_NAME("MOVSHDUP Gx, Ex");
nextop = F8;
GETEX_Y(q1, 0, 0);
GETGX_empty(q0);
VTRNQ2_32(q0, q1, q1);
if(vex.l) {
GETGY_empty_EY(q0, q1);
VTRNQ2_32(q0, q1, q1);
} else YMM0(gd);
break;
case 0x2A:
INST_NAME("VCVTSI2SS Gx, Vx, Ed");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETGX_empty_VX(v0, v1);
GETED(0);
if(rex.w) {
SCVTFSx(d1, ed);
} else {
SCVTFSw(d1, ed);
}
if(v0!=v1) VMOVQ(v0, v1);
VMOVeS(v0, 0, d1, 0);
YMM0(gd);
break;
case 0x2C:
INST_NAME("VCVTTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETEXSS(d0, 0, 0);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
FCVTZSxwS(gd, d0);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
} else {
ORRw_mask(gd, xZR, 1, 0); //0x80000000
}
}
break;
case 0x2D:
INST_NAME("VCVTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETEXSS(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
u8 = sse_setround(dyn, ninst, x1, x2, x3);
d1 = fpu_get_scratch(dyn, ninst);
FRINTIS(d1, q0);
x87_restoreround(dyn, ninst, u8);
FCVTZSxwS(gd, d1);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
} else {
ORRw_mask(gd, xZR, 1, 0); //0x80000000
}
}
break;
case 0x51:
INST_NAME("SQRTSS Gx, Ex");
nextop = F8;
GETEXSS(d0, 0, 0);
GETGX_empty_VX(v0, v2);
d1 = fpu_get_scratch(dyn, ninst);
FSQRTS(d1, d0);
if(v0!=v2) VMOVQ(v0, v2);
VMOVeS(v0, 0, d1, 0);
YMM0(gd);
break;
case 0x52:
INST_NAME("VRSQRTSS Gx, Vx Ex");
nextop = F8;
GETGX(v0, 1);
GETVX(v2, 0);
GETEXSS(v1, 0, 0);
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
// and want 1.0f = 0x3f800000
// so 00111111 10000000 00000000 00000000
// a = 0, b = 1, c = 1, d = 1, efgh=0
// 0b01110000
FMOVS_8(d0, 0b01110000);
FSQRTS(d1, v1);
FDIVS(d0, d0, d1);
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d0, 0);
YMM0(gd);
break;
case 0x53:
INST_NAME("VRCPSS Gx, Vx, Ex");
nextop = F8;
GETGX(v0, 1);
GETVX(v2, 0);
GETEXSS(v1, 0, 0);
d0 = fpu_get_scratch(dyn, ninst);
FMOVS_8(d0, 0b01110000); //1.0f
FDIVS(d0, d0, v1);
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d0, 0);
YMM0(gd);
break;
case 0x58:
INST_NAME("VADDSS Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FADDS(q2, v1, v2); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FADDS(q2, v1, v2); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x59:
INST_NAME("VMULSS Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FMULS(q2, v1, v2); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FMULS(q2, v1, v2); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x5A:
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(v0!=v2) {
if(v0==v1) {
VMOV(d1, v1);
v1 = d1;
}
VMOVQ(v0, v2);
}
FCVT_D_S(d1, v1);
VMOVeD(v0, 0, d1, 0);
YMM0(gd);
break;
case 0x5B:
INST_NAME("VCVTTPS2DQ Gx, Ex");
nextop = F8;
d0 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastround)) {
MRS_fpsr(x5);
ORRw_mask(x4, xZR, 1, 0); //0x80000000
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
if(BOX64ENV(dynarec_fastround)) {
VFCVTZSQS(v0, v1);
} else {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
for(int i=0; i<4; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
VMOVeS(d0, 0, v1, i);
VFCVTZSs(d0, d0);
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ(x5, FPSR_IOC, 4+4);
VMOVQSfrom(d0, 0, x4);
VMOVeS(v0, i, d0, 0);
}
}
}
if(!vex.l) YMM0(gd);
break;
case 0x5C:
INST_NAME("VSUBSS Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FSUBS(q2, v2, v1); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FSUBS(q2, v2, v1); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x5D:
INST_NAME("VMINSS Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
FCMPS(v2, v1);
FCSELS(d1, v1, v2, cCS);
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
break;
case 0x5E:
INST_NAME("VDIVSS Gx, Vx, Ex");
nextop = F8;
q2 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
if(!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FDIVS(q2, v2, v1); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
} else {
FDIVS(q2, v2, v1); // the high part of the vector is erased...
}
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, q2, 0);
YMM0(gd)
break;
case 0x5F:
INST_NAME("VMAXSS Gx, Vx, Ex");
nextop = F8;
d1 = fpu_get_scratch(dyn, ninst);
GETEXSS(v1, 0, 0);
GETGX_empty_VX(v0, v2);
FCMPS(v1, v2);
FCSELS(d1, v1, v2, cCS);
if(v0!=v2) {
VMOVQ(v0, v2);
}
VMOVeS(v0, 0, d1, 0); // to not erase uper part
YMM0(gd)
break;
case 0x6F:
INST_NAME("VMOVDQU Gx, Ex");// no alignment constraint on NEON here, so same as MOVDQA
nextop = F8;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX_empty(v0);
VMOVQ(v0, v1);
if(vex.l) {
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, -12, -1);
GETGY_empty(v0, (nextop&7)+(rex.b<<3), -1, -1);
VMOVQ(v0, v1);
}
} else {
GETGX_empty(v0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VLDR128_U12(v0, ed, fixedaddress);
if(vex.l) {
GETGY_empty(v0, -1, -1, -1);
VLDR128_U12(v0, ed, fixedaddress+16);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x70:
INST_NAME("VPSHUFHW Gx, Ex, Ib");
nextop = F8;
d0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETEX_Y(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
VDUP_16(d0, v1, 4+(u8&3));
} else {
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
if(!l) {
u64 = 0;
for (int i=0; i<4; ++i) {
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+8)<<(i*16+0);
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+9)<<(i*16+8);
}
MOV64x(x2, u64);
}
VMOVQDfrom(d0, 0, x2);
VTBL1_8(d0, v1, d0);
}
VMOVeD(v0, 1, d0, 0);
if(v0!=v1) {
VMOVeD(v0, 0, v1, 0);
}
}
if(!vex.l) YMM0(gd);
break;
case 0x7E:
INST_NAME("MOVQ Gx, Ex");
nextop = F8;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
GETGX_empty(v0);
FMOVD(v0, v1);
} else {
GETGX_empty(v0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
VLD64(v0, ed, fixedaddress);
}
YMM0(gd);
break;
case 0x7F:
INST_NAME("VMOVDQU Ex, Gx");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVQ(v1, v0);
if(vex.l) {
GETGY(v0, 0, (nextop&7) + (rex.b<<3), -1, -1);
v1 = ymm_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3), gd, -1, -1);
VMOVQ(v1, v0);
} // no ymm raz here it seems
} else {
IF_UNALIGNED(ip) {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(wback!=x1) {
MOVx_REG(x1, wback);
wback = x1;
}
for(int i=0; i<16; ++i) {
VST1_8(v0, i, wback);
ADDx_U12(wback, wback, 1);
}
if(vex.l) {
GETGY(v0, 0, -1, -1, -1);
for(int i=0; i<16; ++i) {
VST1_8(v0, i, wback);
ADDx_U12(wback, wback, 1);
}
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
VSTR128_U12(v0, ed, fixedaddress);
if(vex.l) {
GETGY(v0, 0, -1, -1, -1);
VSTR128_U12(v0, ed, fixedaddress+16);
}
}
SMWRITE2();
}
break;
case 0xC2:
INST_NAME("VCMPSS Gx, Vx, Ex, Ib");
nextop = F8;
GETEXSS(v1, 0, 1);
GETGX_empty_VX(v0, v2);
u8 = F8;
if(((u8&15)!=11) && ((u8&15)!=15)) {
if((u8&15)>7)
FCMPS(v1, v2);
else
FCMPS(v2, v1);
}
// TODO: create a test for this one, there might be an issue with cases 9, 10 and 13
if(v0!=v2) VMOVQ(v0, v2);
switch(u8&15) {
case 0x00: CSETMw(x2, cEQ); break; // Equal
case 0x01: CSETMw(x2, cCC); break; // Less than
case 0x02: CSETMw(x2, cLS); break; // Less or equal
case 0x03: CSETMw(x2, cVS); break; // NaN
case 0x04: CSETMw(x2, cNE); break; // Not Equal or unordered
case 0x05: CSETMw(x2, cCS); break; // Greater or equal or unordered
case 0x06: CSETMw(x2, cHI); break; // Greater or unordered
case 0x07: CSETMw(x2, cVC); break; // not NaN
case 0x08: CSETMw(x2, cEQ); CSETMw(x3, cVS); ORRw_REG(x2, x2, x3); break; // Equal or unordered
case 0x09: CSETMw(x2, cHI); break; // Less than or unordered
case 0x0a: CSETMw(x2, cCS); break; // Less or equal or unordered
case 0x0b: MOV32w(x2, 0); break; // false
case 0x0c: CSETMw(x2, cNE); CSETMw(x3, cVS); BICw(x2, x2, x3); break; // Not Equal not unordered
case 0x0d: CSETMw(x2, cLS); break; // Greater or equal not unordered
case 0x0e: CSETMw(x2, cCC); break; // Greater not unordered
case 0x0f: MOV32w(x2, 0xffffffff); break; // true
}
VMOVQSfrom(v0, 0, x2);
YMM0(gd);
break;
case 0xE6:
INST_NAME("VCVTDQ2PD Gx, Ex");
nextop = F8;
if(vex.l) {
GETEX_Y(v1, 0, 0);
} else {
GETEXSD(v1, 0, 0);
}
GETGX_empty(v0);
d0 = fpu_get_scratch(dyn, ninst);
if(vex.l) {
q0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
SXTL2_32(q0, v1);
SCVTQFD(q0, q0);
} else YMM0(gd);
SXTL_32(v0, v1);
SCVTQFD(v0, v0);
break;
default:
DEFAULT;
}
return addr;
}
@@ -1,107 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch(opcode) {
case 0xF5:
INST_NAME("PEXT Gd, Ed, Vd");
nextop = F8;
GETGD;
GETED(0);
GETVD;
if(gd==ed || gd==vd) {
gb1 = gd;
gd = x4;
} else {
gb1 = 0;
}
// x3 = mask of mask, loop while not 0
MOV32w(gd, 0);
MOV64x(x3, 1LL<<(rex.w?63:31));
MARK;
TSTxw_REG(ed, x3);
B_MARK2(cEQ); // mask not set
TSTxw_REG(vd, x3);
CSINCxw(gd, gd, gd, cEQ); // return gd if TRUE, else gd+1
RORxw(gd, gd, 1);
MARK2;
LSRxw_IMM(x3, x3, 1);
CBNZxw_MARK(x3);
RBITxw(gd, gd);
if(gb1)
MOVxw_REG(gb1, gd);
break;
case 0xF7:
INST_NAME("SARX Gd, Ed, Vd");
nextop = F8;
GETGD;
GETED(0);
GETVD;
ANDx_mask(x3, vd, 1, 0, rex.w?5:4); // mask 0x3f/0x1f
ASRxw_REG(gd, ed, x3);
break;
default:
DEFAULT;
}
return addr;
}
-347
View File
@@ -1,347 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
{
(void)ip; (void)rep; (void)need_epilog;
uint8_t nextop = F8;
uint8_t ed;
uint8_t u8;
int64_t fixedaddress;
int unscaled;
int v1, v2;
int s0;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
if(MODREG)
switch(nextop) {
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
INST_NAME("FADD ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FADDS(v1, v1, v2);
} else {
FADDD(v1, v1, v2);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 0xC8:
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
INST_NAME("FMUL ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FMULS(v1, v1, v2);
} else {
FMULD(v1, v1, v2);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
INST_NAME("FCOM ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
FCOM(x1, x2, x3);
break;
case 0xD8:
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
INST_NAME("FCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
FCOM(x1, x2, x3);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
case 0xE2:
case 0xE3:
case 0xE4:
case 0xE5:
case 0xE6:
case 0xE7:
INST_NAME("FSUB ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FSUBS(v1, v1, v2);
} else {
FSUBD(v1, v1, v2);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 0xE8:
case 0xE9:
case 0xEA:
case 0xEB:
case 0xEC:
case 0xED:
case 0xEE:
case 0xEF:
INST_NAME("FSUBR ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FSUBS(v1, v2, v1);
} else {
FSUBD(v1, v2, v1);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 0xF0:
case 0xF1:
case 0xF2:
case 0xF3:
case 0xF4:
case 0xF5:
case 0xF6:
case 0xF7:
INST_NAME("FDIV ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FDIVS(v1, v1, v2);
} else {
FDIVD(v1, v1, v2);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 0xF8:
case 0xF9:
case 0xFA:
case 0xFB:
case 0xFC:
case 0xFD:
case 0xFE:
case 0xFF:
INST_NAME("FDIVR ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FDIVS(v1, v2, v1);
} else {
FDIVD(v1, v2, v1);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
default:
DEFAULT;
break;
} else
switch((nextop>>3)&7) {
case 0:
INST_NAME("FADD ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
FADDS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FADDD(v1, v1, s0);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 1:
INST_NAME("FMUL ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
FMULS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FMULD(v1, v1, s0);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 2:
INST_NAME("FCOM ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FCMPS(v1, s0);
} else {
FCVT_D_S(s0, s0);
FCMPD(v1, s0);
}
FCOM(x1, x2, x3);
break;
case 3:
INST_NAME("FCOMP ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FCMPS(v1, s0);
} else {
FCVT_D_S(s0, s0);
FCMPD(v1, s0);
}
FCOM(x1, x2, x3);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 4:
INST_NAME("FSUB ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
FSUBS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FSUBD(v1, v1, s0);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 5:
INST_NAME("FSUBR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
FSUBS(v1, s0, v1);
} else {
FCVT_D_S(s0, s0);
FSUBD(v1, s0, v1);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 6:
INST_NAME("FDIV ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
FDIVS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FDIVD(v1, v1, s0);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 7:
INST_NAME("FDIVR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
if(ST_IS_F(0)) {
FDIVS(v1, s0, v1);
} else {
FCVT_D_S(s0, s0);
FDIVD(v1, s0, v1);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
default:
DEFAULT;
}
return addr;
}
-590
View File
@@ -1,590 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
{
(void)ip; (void)rep; (void)need_epilog;
uint8_t nextop = F8;
uint8_t ed;
uint8_t wback, wb1;
uint8_t u8;
int64_t fixedaddress, j64;
int unscaled;
int v1, v2;
int s0;
int i1, i2, i3;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
if(MODREG)
switch(nextop) {
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
INST_NAME("FLD STx");
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, X87_ST(nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
if(ST_IS_F(0)) {
FMOVS(v2, v1);
} else {
FMOVD(v2, v1);
}
break;
case 0xC8:
INST_NAME("FXCH ST0");
break;
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
INST_NAME("FXCH STx");
// swap the cache value, not the double value itself :p
x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
// should set C1 to 0
break;
case 0xD0:
INST_NAME("FNOP");
break;
case 0xD8:
INST_NAME("FSTPNCE ST0, ST0");
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
INST_NAME("FSTPNCE ST0, STx");
// copy the cache value for st0 to stx
x87_get_st_empty(dyn, ninst, x1, x2, nextop&7, X87_ST(nextop&7));
x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xE0:
INST_NAME("FCHS");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FNEGS(v1, v1);
} else {
FNEGD(v1, v1);
}
break;
case 0xE1:
INST_NAME("FABS");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FABSS(v1, v1);
} else {
FABSD(v1, v1);
}
break;
case 0xE4:
INST_NAME("FTST");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FCMPS_0(v1);
} else {
FCMPD_0(v1);
}
FCOM(x1, x2, x3); // same flags...
break;
case 0xE5:
INST_NAME("FXAM");
#if 1
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
// value put in x14
if(i1==-1) {
if(fpu_is_st_freed(dyn, ninst, 0)) {
MOV32w(x4, 0b100000100000000);
B_MARK3_nocond;
} else {
// not in cache, so check Empty status and load it
i2 = -dyn->n.x87stack;
LDRw_U12(x3, xEmu, offsetof(x64emu_t, fpu_stack));
if(i2) {
if(i2<0) {
ADDw_U12(x3, x3, -i2);
} else {
SUBw_U12(x3, x3, i2);
}
}
CMPSw_U12(x3, 0);
MOV32w(x4, 0b100000100000000); // empty: C3,C2,C0 = 101
B_MARK3(cLE);
// x5 will be the actual top
LDRw_U12(x5, xEmu, offsetof(x64emu_t, top));
if(i2) {
if(i2<0) {
SUBw_U12(x5, x5, -i2);
} else {
ADDw_U12(x5, x5, i2);
}
ANDw_mask(x5, x5, 0, 2); // (emu->top + i)&7
}
// load x2 with ST0 anyway, for sign extraction
ADDx_REG_LSL(x1, xEmu, x5, 3);
LDRx_U12(x2, x1, offsetof(x64emu_t, x87));
// load tag
if(i2>=0) {
LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
if(i2>0) {
ORRw_mask(x3, x3, 0b010000, 0b001111); // 0xffff0000
LSRw_IMM(x3, x3, i2*2);
}
TSTw_mask(x3, 0, 1); // 0b11
B_MARK3(cNE); // empty: C3,C2,C0 = 101
}
}
} else {
// simply move from cache reg to x2
v1 = dyn->n.x87reg[i1];
VMOVQDto(x2, v1, 0);
}
// get exponant in x1
LSRx_IMM(x1, x2, 20+32);
ANDSx_mask(x1, x1, 1, 0b00000, 0b001010); // 0x7ff
B_MARK(cNE); // not zero or denormal
ANDSx_mask(x1, x2, 1, 0, 0b111110); // 0x7fffffffffffffff
MOV32w(x4, 0b100000000000000); // Zero: C3,C2,C0 = 100
MOV32w(x5, 0b100010000000000); // Denormal: C3,C2,C0 = 110
CSELx(x4, x4, x5, cEQ);
B_MARK3(c__);
MARK;
CMPSx_U12(x1, 0x7ff); // infinite/NaN?
MOV32w(x5, 0b000010000000000); // normal: C3,C2,C0 = 010
CSELx(x4, x5, x4, cNE);
B_MARK3(cNE);
TSTx_mask(x2, 1, 0b000000, 0b110011); // 0x000fffffffffffff
MOV32w(x4, 0b000010100000000); // infinity: C3,C2,C0 = 011
MOV32w(x3, 0b000000100000000); // NaN: C3,C2,C0 = 001
CSELx(x4, x4, x3, cEQ);
MARK3;
// Extract signa & Update SW
LSRx_IMM(x1, x2, 63);
BFIx(x4, x1, 9, 1); //C1
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
MOV32w(x2, 0b01000111);
BICw_REG_LSL(x1, x1, x2, 8);
ORRw_REG(x4, x4, x1);
STRH_U12(x4, xEmu, offsetof(x64emu_t, sw));
#else
MESSAGE(LOG_DUMP, "Need Optimization\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
CALL(fpu_fxam, -1); // should be possible inline, but is it worth it?
x87_unstackcount(dyn, ninst, x1, i1);
#endif
break;
case 0xE8:
INST_NAME("FLD1");
if(ninst<dyn->size+2 && (dyn->insts[ninst+1].pred_sz==1) && (dyn->insts[ninst+2].pred_sz==1)
&& PK(0)==0xD9 && PK(1)==0xE8
&& PK(2)==0xD9 && PK(3)==0xF3
) {
MESSAGE(LOG_DUMP, "Hack for FLD1 FLD1 FPATAN");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
FTABLE64(v1, PI/4.0);
addr+=4;
} else {
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
FMOVS_8(v1, 0b01110000);
} else {
FMOVD_8(v1, 0b01110000);
}
}
break;
case 0xE9:
INST_NAME("FLDL2T");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
FTABLE64(v1, L2T);
break;
case 0xEA:
INST_NAME("FLDL2E");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
FTABLE64(v1, L2E);
break;
case 0xEB:
INST_NAME("FLDPI");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
FTABLE64(v1, PI);
break;
case 0xEC:
INST_NAME("FLDLG2");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
FTABLE64(v1, LG2);
break;
case 0xED:
INST_NAME("FLDLN2");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
FTABLE64(v1, LN2);
break;
case 0xEE:
INST_NAME("FLDZ");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
VEOR(v1, v1, v1);
break;
case 0xF0:
INST_NAME("F2XM1");
MESSAGE(LOG_DUMP, "Need Optimization (F2XM1)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
CALL(native_f2xm1, -1);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xF1:
INST_NAME("FYL2X");
MESSAGE(LOG_DUMP, "Need Optimization (FYL2X)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fyl2x, -1);
x87_unstackcount(dyn, ninst, x1, i1);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xF2:
INST_NAME("FPTAN");
MESSAGE(LOG_DUMP, "Need Optimization (FPTAN)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
x87_unstackcount(dyn, ninst, x1, i1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
if(PK(0)==0xdd && PK(1)==0xd8) {
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emitting 1\n");
u8 = F8;
u8 = F8;
} else {
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
FMOVS_8(v1, 0b01110000);
} else {
FMOVD_8(v1, 0b01110000);
}
}
break;
case 0xF3:
INST_NAME("FPATAN");
MESSAGE(LOG_DUMP, "Need Optimization (FPATAN)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xF4:
INST_NAME("FXTRACT");
MESSAGE(LOG_DUMP, "Need Optimization (FXTRACT)\n");
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fxtract, -1);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xF5:
INST_NAME("FPREM1");
#if 0
MESSAGE(LOG_DUMP, "Need Optimization\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fprem1, -1);
x87_unstackcount(dyn, ninst, x1, i1);
#else
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
FDIVD(s0, v1, v2);
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
FCVTZSxD(x4, s0);
FMULD(s0, s0, v2);
FSUBD(v1, v1, s0);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
// set C2 = 0
BFCw(x1, 10, 1);
// set C1 = Q0
BFIw(x1, x4, 9, 1);
// set C3 = Q1
LSRx_IMM(x4, x4, 1);
BFIw(x1, x4, 14, 1);
// Set C0 = Q2
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
#endif
break;
case 0xF6:
INST_NAME("FDECSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
SUBw_U12(x2, x2, 1);
ANDw_mask(x2, x2, 0, 2); //mask=7
STRw_U12(x2, xEmu, offsetof(x64emu_t, top));
break;
case 0xF7:
INST_NAME("FINCSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
ADDw_U12(x2, x2, 1);
ANDw_mask(x2, x2, 0, 2); //mask=7
STRw_U12(x2, xEmu, offsetof(x64emu_t, top));
break;
case 0xF8:
INST_NAME("FPREM");
#if 0
MESSAGE(LOG_DUMP, "Need Optimization\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fprem, -1);
x87_unstackcount(dyn, ninst, x1, i1);
#else
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
FDIVD(s0, v1, v2);
FRINTZD(s0, s0);
FCVTZSxD(x4, s0);
FMULD(s0, s0, v2);
FSUBD(v1, v1, s0);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
// set C2 = 0
BFCw(x1, 10, 1);
// set C1 = Q0
BFIw(x1, x4, 9, 1);
// set C3 = Q1
LSRx_IMM(x4, x4, 1);
BFIw(x1, x4, 14, 1);
// Set C0 = Q2
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
#endif
break;
case 0xF9:
INST_NAME("FYL2XP1");
MESSAGE(LOG_DUMP, "Need Optimization (FYL2XP1)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fyl2xp1, -1);
x87_unstackcount(dyn, ninst, x1, i1);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xFA:
INST_NAME("FSQRT");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
if(ST_IS_F(0)) {
FSQRTS(v1, v1);
} else {
FSQRTD(v1, v1);
}
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 0xFB:
INST_NAME("FSINCOS");
MESSAGE(LOG_DUMP, "Need Optimization (FSINCOS)\n");
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 1);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xFC:
INST_NAME("FRNDINT");
#if 0
MESSAGE(LOG_DUMP, "Need Optimization\n");
// use C helper for now, nothing staightforward is available
x87_forget(dyn, ninst, x1, x2, 0);
CALL(native_frndint, -1);
#else
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
u8 = x87_setround(dyn, ninst, x1, x2, x3);
if(ST_IS_F(0)) {
FRINTIS(v1, v1);
} else {
FRINTID(v1, v1);
}
x87_restoreround(dyn, ninst, u8);
#endif
break;
case 0xFD:
INST_NAME("FSCALE");
MESSAGE(LOG_DUMP, "Need Optimization (FSCALE)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xFE:
INST_NAME("FSIN");
MESSAGE(LOG_DUMP, "Need Optimization (FSIN)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xFF:
INST_NAME("FCOS");
MESSAGE(LOG_DUMP, "Need Optimization (FCOS)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
break;
default:
DEFAULT;
break;
} else
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD ST0, float[ED]");
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, BOX64ENV(dynarec_x87double)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v1, ed, fixedaddress);
if(!ST_IS_F(0)) {
FCVT_D_S(v1, v1);
}
break;
case 2:
INST_NAME("FST float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else {
s0 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
FCVT_S_D(s0, v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
}
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VST32(s0, ed, fixedaddress);
break;
case 3:
INST_NAME("FSTP float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
if(!ST_IS_F(0)) {
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FCVT_S_D(v1, v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
}
VST32(v1, ed, fixedaddress);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 4:
INST_NAME("FLDENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FLDENV)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {
MOVx_REG(x1, ed);
}
MOV32w(x2, 0);
CALL(fpu_loadenv, -1);
break;
case 5:
INST_NAME("FLDCW Ew");
GETEW(x1, 0);
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
break;
case 6:
INST_NAME("FNSTENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {
MOVx_REG(x1, ed);
}
MOV32w(x2, 0);
CALL(fpu_savenv, -1);
break;
case 7:
INST_NAME("FNSTCW Ew");
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
ed = x1;
wb1 = 1;
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
EWBACK;
break;
default:
DEFAULT;
}
return addr;
}
-254
View File
@@ -1,254 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
int64_t j64;
uint8_t ed;
uint8_t wback;
uint8_t u8;
int v1, v2;
int d0;
int s0;
int64_t fixedaddress;
int unscaled;
MAYUSE(s0);
MAYUSE(d0);
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(ed);
MAYUSE(j64);
if(MODREG)
switch(nextop) {
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
INST_NAME("FCMOVB ST0, STx");
READFLAGS(X_CF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
TSTw_mask(xFlags, 0, 0); //mask=1<<F_CF
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cNE); // F_CF==1
} else {
FCSELD(v1, v2, v1, cNE); // F_CF==1
}
break;
case 0xC8:
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
INST_NAME("FCMOVE ST0, STx");
READFLAGS(X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
TSTw_mask(xFlags, 0b011010, 0); //mask=1<<F_ZF
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cNE);
} else {
FCSELD(v1, v2, v1, cNE); // F_ZF==0
}
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
INST_NAME("FCMOVBE ST0, STx");
READFLAGS(X_CF|X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
MOV32w(x1, (1<<F_CF)|(1<<F_ZF));
TSTw_REG(xFlags, x1);
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cNE);
} else {
FCSELD(v1, v2, v1, cNE); // F_CF==0 & F_ZF==0
}
break;
case 0xD8:
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
INST_NAME("FCMOVU ST0, STx");
READFLAGS(X_PF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
TSTw_mask(xFlags, 0b011110, 0); //mask=1<<F_PF
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cNE);
} else {
FCSELD(v1, v2, v1, cNE); // F_PF==0
}
break;
case 0xE9:
INST_NAME("FUCOMPP ST0, ST1");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, 1, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
FCOM(x1, x2, x3);
X87_POP_OR_FAIL(dyn, ninst, x3);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
default:
DEFAULT;
break;
} else
switch((nextop>>3)&7) {
case 0:
INST_NAME("FIADD ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FADDD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 1:
INST_NAME("FIMUL ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FMULD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 2:
INST_NAME("FICOM ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
FCMPD(v1, v2);
FCOM(x1, x2, x3);
break;
case 3:
INST_NAME("FICOMP ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
FCMPD(v1, v2);
FCOM(x1, x2, x3);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 4:
INST_NAME("FISUB ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FSUBD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 5:
INST_NAME("FISUBR ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FSUBD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 6:
INST_NAME("FIDIV ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FDIVD(v1, v1, v2);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
case 7:
INST_NAME("FIDIVR ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = fpu_get_scratch(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(v2, ed, fixedaddress);
SXTL_32(v2, v2); // i32 -> i64
SCVTFDD(v2, v2); // i64 -> double
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x5, x4);
FDIVD(v1, v2, v1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
}
return addr;
}
Loaded 100 of 2180 files, more files were not shown because too many files have changed in this diff. Show more