mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-06 07:12:28 +01:00
Compare commits
No commits in common. "master" and "v0.0.38" have entirely different histories.
|
|
@ -6,13 +6,12 @@ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
|||
export HOMEBREW_NO_ENV_HINTS=1
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
|
||||
brew install -f --overwrite --quiet pipenv googletest opencv@4 ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
|
||||
brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative
|
||||
brew install -f --overwrite --quiet ccache pipenv googletest ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
|
||||
brew link -f --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5
|
||||
|
||||
# moltenvk based on commit for 1.4.0 release
|
||||
# moltenvk based on commit for 1.3.0 release
|
||||
export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/ea2bec5f1f4384e188d7fc0702ab21a20a2ced08/Formula/m/molten-vk.rb
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/7255441cbcafabaa8950f67c7ec55ff499dbb2d3/Formula/m/molten-vk.rb
|
||||
/opt/homebrew/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb
|
||||
export HOMEBREW_DEVELOPER=0
|
||||
|
||||
|
|
@ -28,25 +27,23 @@ export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64'
|
|||
export WORKDIR;
|
||||
WORKDIR="$(pwd)"
|
||||
|
||||
# Setup ccache
|
||||
if [ ! -d "$CCACHE_DIR" ]; then
|
||||
mkdir -p "$CCACHE_DIR"
|
||||
fi
|
||||
|
||||
# Get Qt
|
||||
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
||||
mkdir -p "/tmp/Qt"
|
||||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
|
||||
sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
|
||||
# nested Qt 6.9.3 URL workaround
|
||||
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
|
||||
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
|
||||
# archived Qt 6.7.3 URL workaround
|
||||
sed -i '' "s/official_releases/archive/g" qt-downloader
|
||||
cd "/tmp/Qt"
|
||||
"$BREW_PATH/bin/pipenv" run pip3 uninstall py7zr requests semantic_version lxml
|
||||
"$BREW_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml --no-cache
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader"
|
||||
"$BREW_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64"
|
||||
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.9.3 workaround
|
||||
"$BREW_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
|
||||
fi
|
||||
|
||||
cd "$WORKDIR"
|
||||
|
|
|
|||
|
|
@ -8,17 +8,13 @@ export HOMEBREW_NO_INSTALL_CLEANUP=1
|
|||
|
||||
brew install -f --overwrite --quiet ccache pipenv "llvm@$LLVM_COMPILER_VER"
|
||||
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
|
||||
# shellcheck disable=SC3009
|
||||
rm /usr/local/bin/{idle3.14,pip3.14,pydoc3.14,python3.14,python3.14-config} && \
|
||||
rm /usr/local/bin/{idle3,pip3,pydoc3,python3,python3-config}
|
||||
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet opencv@4 ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
|
||||
arch -x86_64 /usr/local/bin/brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
|
||||
arch -x86_64 /usr/local/bin/brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5
|
||||
|
||||
# moltenvk based on commit for 1.4.0 release
|
||||
# moltenvk based on commit for 1.3.0 release
|
||||
export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/ea2bec5f1f4384e188d7fc0702ab21a20a2ced08/Formula/m/molten-vk.rb
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/7255441cbcafabaa8950f67c7ec55ff499dbb2d3/Formula/m/molten-vk.rb
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb
|
||||
export HOMEBREW_DEVELOPER=0
|
||||
export CXX=clang++
|
||||
|
|
@ -39,13 +35,16 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
|||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
|
||||
sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
|
||||
# nested Qt 6.9.3 URL workaround
|
||||
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
|
||||
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
|
||||
# archived Qt 6.7.3 URL workaround
|
||||
sed -i '' "s/official_releases/archive/g" qt-downloader
|
||||
cd "/tmp/Qt"
|
||||
"/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run pip3 install py7zr requests semantic_version lxml
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader"
|
||||
"/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64"
|
||||
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.9.3 workaround
|
||||
"/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
|
||||
fi
|
||||
|
||||
cd "$WORKDIR"
|
||||
|
|
@ -55,8 +54,7 @@ export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN
|
|||
export SDL3_DIR="$BREW_X64_PATH/opt/sdl3/lib/cmake/SDL3"
|
||||
|
||||
export PATH="/opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
|
||||
# shellcheck disable=SC2155
|
||||
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib,-L$(brew --prefix llvm)/lib/c++"
|
||||
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
|
||||
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
|
||||
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
|
||||
export LIBRARY_PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib:$BREW_X64_PATH/lib"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
|||
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh
|
||||
chmod +x ./linuxdeploy-plugin-checkrt.sh
|
||||
|
||||
export EXTRA_PLATFORM_PLUGINS="libqwayland.so"
|
||||
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
|
||||
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor"
|
||||
|
||||
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt
|
||||
|
|
@ -32,25 +32,6 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
|||
# Remove git directory containing local commit history file
|
||||
rm -rf ./AppDir/usr/share/rpcs3/git
|
||||
|
||||
# Download translations
|
||||
mkdir -p "./AppDir/usr/translations"
|
||||
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
|
||||
| grep "browser_download_url" \
|
||||
| grep "RPCS3-languages.zip" \
|
||||
| cut -d '"' -f 4)
|
||||
if [ -z "$ZIP_URL" ]; then
|
||||
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
|
||||
else
|
||||
echo "Downloading translations from: $ZIP_URL"
|
||||
curl -L -o translations.zip "$ZIP_URL" || {
|
||||
echo "Failed to download translations.zip. Continuing without translations."
|
||||
exit 0
|
||||
}
|
||||
unzip -o translations.zip -d "./AppDir/usr/translations" >/dev/null 2>&1 || \
|
||||
echo "Failed to extract translations.zip. Continuing without translations."
|
||||
rm -f translations.zip
|
||||
fi
|
||||
|
||||
curl -fsSLo /uruntime "https://github.com/VHSgunzo/uruntime/releases/download/v0.3.4/uruntime-appimage-dwarfs-$CPU_ARCH"
|
||||
chmod +x /uruntime
|
||||
/uruntime --appimage-mkdwarfs -f --set-owner 0 --set-group 0 --no-history --no-create-timestamp \
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ cd bin
|
|||
mkdir "rpcs3.app/Contents/lib/" || true
|
||||
|
||||
cp "$(realpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
|
||||
cp "$(realpath /opt/homebrew/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib"
|
||||
cp "$(realpath /opt/homebrew/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
|
||||
cp "$(realpath /opt/homebrew/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
|
||||
|
||||
|
|
@ -32,28 +31,11 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
|
|||
|
||||
../../.ci/optimize-mac.sh rpcs3.app
|
||||
|
||||
# Download translations
|
||||
mkdir -p "rpcs3.app/Contents/translations"
|
||||
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
|
||||
| grep "browser_download_url" \
|
||||
| grep "RPCS3-languages.zip" \
|
||||
| cut -d '"' -f 4)
|
||||
if [ -z "$ZIP_URL" ]; then
|
||||
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
|
||||
else
|
||||
echo "Downloading translations from: $ZIP_URL"
|
||||
curl -L -o translations.zip "$ZIP_URL" || {
|
||||
echo "Failed to download translations.zip. Continuing without translations."
|
||||
exit 0
|
||||
}
|
||||
unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1 || \
|
||||
echo "Failed to extract translations.zip. Continuing without translations."
|
||||
rm -f translations.zip
|
||||
fi
|
||||
|
||||
# Hack
|
||||
install_name_tool -delete_rpath /opt/homebrew/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/lib not needed"
|
||||
install_name_tool -delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib not needed"
|
||||
install_name_tool \
|
||||
-delete_rpath /opt/homebrew/lib \
|
||||
-delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
|
||||
#-delete_rpath /opt/homebrew1/Cellar/sdl3/3.2.8/lib
|
||||
|
||||
# Need to do this rename hack due to case insensitive filesystem
|
||||
mv rpcs3.app RPCS3_.app
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
|
|||
cd bin
|
||||
mkdir "rpcs3.app/Contents/lib/"
|
||||
|
||||
cp "$(realpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
|
||||
cp "$(realpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/unwind/libunwind.1.dylib)" "rpcs3.app/Contents/Frameworks/libunwind.1.dylib"
|
||||
cp "$(realpath /usr/local/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib"
|
||||
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
|
||||
cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
|
||||
cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
|
||||
|
||||
|
|
@ -33,25 +31,6 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
|
|||
|
||||
../../.ci/optimize-mac.sh rpcs3.app
|
||||
|
||||
# Download translations
|
||||
mkdir -p "rpcs3.app/Contents/translations"
|
||||
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
|
||||
| grep "browser_download_url" \
|
||||
| grep "RPCS3-languages.zip" \
|
||||
| cut -d '"' -f 4)
|
||||
if [ -z "$ZIP_URL" ]; then
|
||||
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
|
||||
else
|
||||
echo "Downloading translations from: $ZIP_URL"
|
||||
curl -L -o translations.zip "$ZIP_URL" || {
|
||||
echo "Failed to download translations.zip. Continuing without translations."
|
||||
exit 0
|
||||
}
|
||||
unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1 || \
|
||||
echo "Failed to extract translations.zip. Continuing without translations."
|
||||
rm -f translations.zip
|
||||
fi
|
||||
|
||||
# Need to do this rename hack due to case insensitive filesystem
|
||||
mv rpcs3.app RPCS3_.app
|
||||
mv RPCS3_.app RPCS3.app
|
||||
|
|
|
|||
|
|
@ -24,25 +24,6 @@ mkdir ./bin/config/input_configs
|
|||
curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt
|
||||
curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat
|
||||
|
||||
# Download translations
|
||||
mkdir -p ./bin/share/qt6/translations
|
||||
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
|
||||
| grep "browser_download_url" \
|
||||
| grep "RPCS3-languages.zip" \
|
||||
| cut -d '"' -f 4)
|
||||
if [ -z "$ZIP_URL" ]; then
|
||||
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
|
||||
else
|
||||
echo "Downloading translations from: $ZIP_URL"
|
||||
curl -L -o translations.zip "$ZIP_URL" || {
|
||||
echo "Failed to download translations.zip. Continuing without translations."
|
||||
exit 0
|
||||
}
|
||||
unzip -o translations.zip -d "./bin/share/qt6/translations" >/dev/null 2>&1 || \
|
||||
echo "Failed to extract translations.zip. Continuing without translations."
|
||||
rm -f translations.zip
|
||||
fi
|
||||
|
||||
# Package artifacts
|
||||
7z a -m0=LZMA2 -mx9 "$BUILD" ./bin/*
|
||||
|
||||
|
|
|
|||
|
|
@ -15,25 +15,6 @@ mkdir ./bin/config/input_configs
|
|||
curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt
|
||||
curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat
|
||||
|
||||
# Download translations
|
||||
mkdir -p ./bin/qt6/translations
|
||||
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
|
||||
| grep "browser_download_url" \
|
||||
| grep "RPCS3-languages.zip" \
|
||||
| cut -d '"' -f 4)
|
||||
if [ -z "$ZIP_URL" ]; then
|
||||
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
|
||||
else
|
||||
echo "Downloading translations from: $ZIP_URL"
|
||||
curl -L -o translations.zip "$ZIP_URL" || {
|
||||
echo "Failed to download translations.zip. Continuing without translations."
|
||||
exit 0
|
||||
}
|
||||
unzip -o translations.zip -d "./bin/qt6/translations" >/dev/null 2>&1 || \
|
||||
echo "Failed to extract translations.zip. Continuing without translations."
|
||||
rm -f translations.zip
|
||||
fi
|
||||
|
||||
# Download SSL certificate (not needed with CURLSSLOPT_NATIVE_CA)
|
||||
#curl -fsSL 'https://curl.haxx.se/ca/cacert.pem' 1> ./bin/cacert.pem
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pkg info # debug
|
|||
pkg install "llvm$LLVM_COMPILER_VER"
|
||||
|
||||
# Mandatory dependencies (qtX-base is pulled via qtX-multimedia)
|
||||
pkg install git ccache cmake ninja "qt$QT_VER_MAIN-multimedia" "qt$QT_VER_MAIN-svg" glew openal-soft ffmpeg pcre2
|
||||
pkg install git ccache cmake ninja "qt$QT_VER_MAIN-multimedia" "qt$QT_VER_MAIN-svg" glew openal-soft ffmpeg
|
||||
|
||||
# Optional dependencies (libevdev is pulled by qtX-base)
|
||||
pkg install pkgconf alsa-lib pulseaudio sdl3 evdev-proto vulkan-headers vulkan-loader opencv
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
|
|||
QT_VER_MSVC_UP=$(echo "${QT_VER_MSVC}" | tr '[:lower:]' '[:upper:]')
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
|
||||
QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
|
||||
QT_SUFFIX="-Windows-Windows_11_24H2-${QT_VER_MSVC_UP}-Windows-Windows_11_24H2-X86_64.7z"
|
||||
QT_SUFFIX="-Windows-Windows_11_23H2-${QT_VER_MSVC_UP}-Windows-Windows_11_23H2-X86_64.7z"
|
||||
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}"
|
||||
QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
|
||||
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
|
||||
|
|
|
|||
16
.github/workflows/rpcs3.yml
vendored
16
.github/workflows/rpcs3.yml
vendored
|
|
@ -30,23 +30,23 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.7"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.6"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
|
||||
- os: ubuntu-24.04
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.7"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy:1.6"
|
||||
build_sh: "/rpcs3/.ci/build-linux.sh"
|
||||
compiler: gcc
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.7"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.6"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: clang
|
||||
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
|
||||
- os: ubuntu-24.04-arm
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.7"
|
||||
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.6"
|
||||
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
|
||||
compiler: gcc
|
||||
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
|
||||
|
|
@ -134,9 +134,9 @@ jobs:
|
|||
runs-on: macos-14
|
||||
env:
|
||||
CCACHE_DIR: /tmp/ccache_dir
|
||||
QT_VER: '6.10.1'
|
||||
QT_VER: '6.7.3'
|
||||
QT_VER_MAIN: '6'
|
||||
LLVM_COMPILER_VER: '21'
|
||||
LLVM_COMPILER_VER: '19'
|
||||
RELEASE_MESSAGE: ../GitHubReleaseMessage.txt
|
||||
UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }}
|
||||
UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }}
|
||||
|
|
@ -212,9 +212,9 @@ jobs:
|
|||
env:
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.10.1'
|
||||
QT_VER: '6.9.3'
|
||||
QT_VER_MSVC: 'msvc2022'
|
||||
QT_DATE: '202511161843'
|
||||
QT_DATE: '202509261208'
|
||||
LLVM_VER: '19.1.7'
|
||||
VULKAN_VER: '1.3.268.0'
|
||||
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
|
|
|
|||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -21,7 +21,7 @@
|
|||
ignore = dirty
|
||||
[submodule "3rdparty/hidapi"]
|
||||
path = 3rdparty/hidapi/hidapi
|
||||
url = ../../libusb/hidapi.git
|
||||
url = ../../RPCS3/hidapi.git
|
||||
branch = master
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/pugixml"]
|
||||
|
|
|
|||
2
3rdparty/CMakeLists.txt
vendored
2
3rdparty/CMakeLists.txt
vendored
|
|
@ -278,7 +278,7 @@ if(USE_FAUDIO)
|
|||
target_compile_definitions(FAudio-static INTERFACE -DHAVE_FAUDIO)
|
||||
set(FAUDIO_TARGET FAudio-static)
|
||||
else()
|
||||
message(WARNING
|
||||
message(FATAL_ERROR
|
||||
"-- RPCS3: 3rdparty FAudio requires SDL 3.2.0 or newer. Since a valid SDL3"
|
||||
">=3.2.0 version cannot be found, building with FAudio will be skipped.")
|
||||
set(USE_FAUDIO OFF CACHE BOOL "Disabled FAudio with SDL < 3.2.0" FORCE)
|
||||
|
|
|
|||
2
3rdparty/FAudio
vendored
2
3rdparty/FAudio
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 4ea8afea6ba857c24e40877f487d000d559b196d
|
||||
Subproject commit 8a87fdc9242a7b507cf5c96c539334a1760c1ec7
|
||||
2
3rdparty/MoltenVK/CMakeLists.txt
vendored
2
3rdparty/MoltenVK/CMakeLists.txt
vendored
|
|
@ -3,7 +3,7 @@ include(ExternalProject)
|
|||
|
||||
ExternalProject_Add(moltenvk
|
||||
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
|
||||
GIT_TAG 4588705
|
||||
GIT_TAG 49b97f2
|
||||
BUILD_IN_SOURCE 1
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
|
||||
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
|
||||
|
|
|
|||
2
3rdparty/OpenAL/openal-soft
vendored
2
3rdparty/OpenAL/openal-soft
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 0e5e98e4ac8adae92e4f7653dd6eee17aa9c8791
|
||||
Subproject commit dc7d7054a5b4f3bec1dc23a42fd616a0847af948
|
||||
4
3rdparty/OpenAL/openal-soft.vcxproj
vendored
4
3rdparty/OpenAL/openal-soft.vcxproj
vendored
|
|
@ -49,11 +49,11 @@
|
|||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
|
||||
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
|
||||
</CmakeReleaseCLI>
|
||||
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
|
||||
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
|
||||
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
|
||||
</CmakeDebugCLI>
|
||||
<CmakeCopyCLI>
|
||||
echo Copying..
|
||||
|
|
|
|||
2
3rdparty/curl/curl
vendored
2
3rdparty/curl/curl
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 400fffa90f30c7a2dc762fa33009d24851bd2016
|
||||
Subproject commit 11b991232fbcaa88e2b1faecac224416b0001e35
|
||||
17
3rdparty/curl/libcurl.vcxproj
vendored
17
3rdparty/curl/libcurl.vcxproj
vendored
|
|
@ -80,12 +80,10 @@
|
|||
<ClCompile Include="curl\lib\cshutdn.c" />
|
||||
<ClCompile Include="curl\lib\curlx\base64.c" />
|
||||
<ClCompile Include="curl\lib\curlx\dynbuf.c" />
|
||||
<ClCompile Include="curl\lib\curlx\fopen.c" />
|
||||
<ClCompile Include="curl\lib\curlx\inet_ntop.c" />
|
||||
<ClCompile Include="curl\lib\curlx\inet_pton.c" />
|
||||
<ClCompile Include="curl\lib\curlx\multibyte.c" />
|
||||
<ClCompile Include="curl\lib\curlx\nonblock.c" />
|
||||
<ClCompile Include="curl\lib\curlx\strerr.c" />
|
||||
<ClCompile Include="curl\lib\curlx\strparse.c" />
|
||||
<ClCompile Include="curl\lib\curlx\timediff.c" />
|
||||
<ClCompile Include="curl\lib\curlx\timeval.c" />
|
||||
|
|
@ -94,9 +92,9 @@
|
|||
<ClCompile Include="curl\lib\curlx\warnless.c" />
|
||||
<ClCompile Include="curl\lib\curlx\winapi.c" />
|
||||
<ClCompile Include="curl\lib\curl_addrinfo.c" />
|
||||
<ClCompile Include="curl\lib\curl_des.c" />
|
||||
<ClCompile Include="curl\lib\curl_endian.c" />
|
||||
<ClCompile Include="curl\lib\curl_fnmatch.c" />
|
||||
<ClCompile Include="curl\lib\curl_fopen.c" />
|
||||
<ClCompile Include="curl\lib\curl_gethostname.c" />
|
||||
<ClCompile Include="curl\lib\curl_get_line.c" />
|
||||
<ClCompile Include="curl\lib\curl_gssapi.c" />
|
||||
|
|
@ -122,6 +120,7 @@
|
|||
<ClCompile Include="curl\lib\fake_addrinfo.c" />
|
||||
<ClCompile Include="curl\lib\file.c" />
|
||||
<ClCompile Include="curl\lib\fileinfo.c" />
|
||||
<ClCompile Include="curl\lib\fopen.c" />
|
||||
<ClCompile Include="curl\lib\formdata.c" />
|
||||
<ClCompile Include="curl\lib\ftp.c" />
|
||||
<ClCompile Include="curl\lib\ftplistparser.c" />
|
||||
|
|
@ -148,6 +147,7 @@
|
|||
<ClCompile Include="curl\lib\idn.c" />
|
||||
<ClCompile Include="curl\lib\if2ip.c" />
|
||||
<ClCompile Include="curl\lib\imap.c" />
|
||||
<ClCompile Include="curl\lib\krb5.c" />
|
||||
<ClCompile Include="curl\lib\ldap.c" />
|
||||
<ClCompile Include="curl\lib\llist.c" />
|
||||
<ClCompile Include="curl\lib\macos.c" />
|
||||
|
|
@ -159,7 +159,6 @@
|
|||
<ClCompile Include="curl\lib\mqtt.c" />
|
||||
<ClCompile Include="curl\lib\multi.c" />
|
||||
<ClCompile Include="curl\lib\multi_ev.c" />
|
||||
<ClCompile Include="curl\lib\multi_ntfy.c" />
|
||||
<ClCompile Include="curl\lib\netrc.c" />
|
||||
<ClCompile Include="curl\lib\noproxy.c" />
|
||||
<ClCompile Include="curl\lib\openldap.c" />
|
||||
|
|
@ -204,7 +203,6 @@
|
|||
<ClCompile Include="curl\lib\version.c" />
|
||||
<ClCompile Include="curl\lib\vquic\curl_ngtcp2.c" />
|
||||
<ClCompile Include="curl\lib\vquic\curl_quiche.c" />
|
||||
<ClCompile Include="curl\lib\vtls\apple.c" />
|
||||
<ClCompile Include="curl\lib\vtls\cipher_suite.c" />
|
||||
<ClCompile Include="curl\lib\vtls\hostcheck.c" />
|
||||
<ClCompile Include="curl\lib\vtls\rustls.c" />
|
||||
|
|
@ -227,6 +225,7 @@
|
|||
<ClCompile Include="curl\lib\vssh\curl_path.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh2.c" />
|
||||
<ClCompile Include="curl\lib\vssh\wolfssh.c" />
|
||||
<ClCompile Include="curl\lib\vtls\gtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\keylog.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls.c" />
|
||||
|
|
@ -275,12 +274,10 @@
|
|||
<ClInclude Include="curl\lib\curlx\binmode.h" />
|
||||
<ClInclude Include="curl\lib\curlx\curlx.h" />
|
||||
<ClInclude Include="curl\lib\curlx\dynbuf.h" />
|
||||
<ClInclude Include="curl\lib\curlx\fopen.h" />
|
||||
<ClInclude Include="curl\lib\curlx\inet_ntop.h" />
|
||||
<ClInclude Include="curl\lib\curlx\inet_pton.h" />
|
||||
<ClInclude Include="curl\lib\curlx\multibyte.h" />
|
||||
<ClInclude Include="curl\lib\curlx\nonblock.h" />
|
||||
<ClInclude Include="curl\lib\curlx\strerr.h" />
|
||||
<ClInclude Include="curl\lib\curlx\strparse.h" />
|
||||
<ClInclude Include="curl\lib\curlx\timediff.h" />
|
||||
<ClInclude Include="curl\lib\curlx\timeval.h" />
|
||||
|
|
@ -290,13 +287,14 @@
|
|||
<ClInclude Include="curl\lib\curlx\winapi.h" />
|
||||
<ClInclude Include="curl\lib\curl_addrinfo.h" />
|
||||
<ClInclude Include="curl\lib\curl_ctype.h" />
|
||||
<ClInclude Include="curl\lib\curl_des.h" />
|
||||
<ClInclude Include="curl\lib\curl_endian.h" />
|
||||
<ClInclude Include="curl\lib\curl_fnmatch.h" />
|
||||
<ClInclude Include="curl\lib\curl_fopen.h" />
|
||||
<ClInclude Include="curl\lib\curl_gethostname.h" />
|
||||
<ClInclude Include="curl\lib\curl_get_line.h" />
|
||||
<ClInclude Include="curl\lib\curl_gssapi.h" />
|
||||
<ClInclude Include="curl\lib\curl_hmac.h" />
|
||||
<ClInclude Include="curl\lib\curl_krb5.h" />
|
||||
<ClInclude Include="curl\lib\curl_ldap.h" />
|
||||
<ClInclude Include="curl\lib\curl_md4.h" />
|
||||
<ClInclude Include="curl\lib\curl_md5.h" />
|
||||
|
|
@ -327,6 +325,7 @@
|
|||
<ClInclude Include="curl\lib\fake_addrinfo.h" />
|
||||
<ClInclude Include="curl\lib\file.h" />
|
||||
<ClInclude Include="curl\lib\fileinfo.h" />
|
||||
<ClInclude Include="curl\lib\fopen.h" />
|
||||
<ClInclude Include="curl\lib\formdata.h" />
|
||||
<ClInclude Include="curl\lib\ftp.h" />
|
||||
<ClInclude Include="curl\lib\ftplistparser.h" />
|
||||
|
|
@ -358,7 +357,6 @@
|
|||
<ClInclude Include="curl\lib\multihandle.h" />
|
||||
<ClInclude Include="curl\lib\multiif.h" />
|
||||
<ClInclude Include="curl\lib\multi_ev.h" />
|
||||
<ClInclude Include="curl\lib\multi_ntfy.h" />
|
||||
<ClInclude Include="curl\lib\netrc.h" />
|
||||
<ClInclude Include="curl\lib\noproxy.h" />
|
||||
<ClInclude Include="curl\lib\parsedate.h" />
|
||||
|
|
@ -405,7 +403,6 @@
|
|||
<ClInclude Include="curl\lib\vquic\curl_ngtcp2.h" />
|
||||
<ClInclude Include="curl\lib\vquic\curl_quiche.h" />
|
||||
<ClInclude Include="curl\lib\vquic\vquic_int.h" />
|
||||
<ClInclude Include="curl\lib\vtls\apple.h" />
|
||||
<ClInclude Include="curl\lib\vtls\cipher_suite.h" />
|
||||
<ClInclude Include="curl\lib\vtls\hostcheck.h" />
|
||||
<ClInclude Include="curl\lib\vtls\rustls.h" />
|
||||
|
|
|
|||
51
3rdparty/curl/libcurl.vcxproj.filters
vendored
51
3rdparty/curl/libcurl.vcxproj.filters
vendored
|
|
@ -42,6 +42,9 @@
|
|||
<ClCompile Include="curl\lib\curl_addrinfo.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curl_des.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curl_endian.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -156,6 +159,9 @@
|
|||
<ClCompile Include="curl\lib\imap.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\krb5.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\ldap.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -327,6 +333,9 @@
|
|||
<ClCompile Include="curl\lib\vssh\libssh2.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vssh\wolfssh.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vtls\gtls.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -387,6 +396,9 @@
|
|||
<ClCompile Include="curl\lib\headers.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\fopen.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\noproxy.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -534,21 +546,6 @@
|
|||
<ClCompile Include="curl\lib\cf-ip-happy.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curl_fopen.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\multi_ntfy.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\vtls\apple.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curlx\fopen.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="curl\lib\curlx\strerr.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="curl\include\curl\curl.h">
|
||||
|
|
@ -626,6 +623,9 @@
|
|||
<ClInclude Include="curl\lib\curl_ctype.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_des.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_endian.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -926,6 +926,9 @@
|
|||
<ClInclude Include="curl\lib\vtls\keylog.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_krb5.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\easyoptions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -950,6 +953,9 @@
|
|||
<ClInclude Include="curl\lib\easy_lock.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\fopen.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\functypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -1106,21 +1112,6 @@
|
|||
<ClInclude Include="curl\lib\curl_mem_undef.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curl_fopen.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\multi_ntfy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\vtls\apple.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curlx\fopen.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="curl\lib\curlx\strerr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="curl\lib\libcurl.rc">
|
||||
|
|
|
|||
2
3rdparty/fusion/fusion
vendored
2
3rdparty/fusion/fusion
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 759ac5d698baefca53f1975a0bb1d2dcbdb9f836
|
||||
Subproject commit 066d4a63b2c714b20b0a8073a01fda7c5c6763f6
|
||||
2
3rdparty/hidapi/hidapi
vendored
2
3rdparty/hidapi/hidapi
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit d6b2a974608dec3b76fb1e36c189f22b9cf3650c
|
||||
Subproject commit f42423643ec9011c98cccc0bb790722bbbd3f30b
|
||||
2
3rdparty/libpng/libpng
vendored
2
3rdparty/libpng/libpng
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 49363adcfaf098748d7a4c8c624ad8c45a8c3a86
|
||||
Subproject commit 2b978915d82377df13fcbb1fb56660195ded868a
|
||||
2
3rdparty/libsdl-org/SDL
vendored
2
3rdparty/libsdl-org/SDL
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 7f3ae3d57459e59943a4ecfefc8f6277ec6bf540
|
||||
Subproject commit a96677bdf6b4acb84af4ec294e5f60a4e8cbbe03
|
||||
1
3rdparty/libsdl-org/SDL.vcxproj
vendored
1
3rdparty/libsdl-org/SDL.vcxproj
vendored
|
|
@ -384,6 +384,7 @@
|
|||
<ClCompile Include="SDL\src\render\opengl\SDL_shaders_gl.c" />
|
||||
<ClCompile Include="SDL\src\render\opengles2\SDL_render_gles2.c" />
|
||||
<ClCompile Include="SDL\src\render\opengles2\SDL_shaders_gles2.c" />
|
||||
<ClCompile Include="SDL\src\render\SDL_d3dmath.c" />
|
||||
<ClCompile Include="SDL\src\render\SDL_render.c" />
|
||||
<ClCompile Include="SDL\src\render\SDL_render_unsupported.c" />
|
||||
<ClCompile Include="SDL\src\render\SDL_yuv_sw.c" />
|
||||
|
|
|
|||
6
3rdparty/libsdl-org/SDL.vcxproj.filters
vendored
6
3rdparty/libsdl-org/SDL.vcxproj.filters
vendored
|
|
@ -172,6 +172,9 @@
|
|||
<Filter Include="render\direct3d12">
|
||||
<UniqueIdentifier>{f48c2b17-1bee-4fec-a7c8-24cf619abe08}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="video\intrin">
|
||||
<UniqueIdentifier>{653672cc-90ae-4eba-a256-6479f2c31804}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="main">
|
||||
<UniqueIdentifier>{00001967ea2801028a046a722a070000}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -1457,6 +1460,9 @@
|
|||
<ClCompile Include="SDL\src\sensor\windows\SDL_windowssensor.c">
|
||||
<Filter>sensor\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SDL\src\render\SDL_d3dmath.c">
|
||||
<Filter>render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SDL\src\render\SDL_render.c">
|
||||
<Filter>render</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
|||
5
3rdparty/qt6.cmake
vendored
5
3rdparty/qt6.cmake
vendored
|
|
@ -6,15 +6,14 @@ find_package(Qt6 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia M
|
|||
if(WIN32)
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
|
||||
else()
|
||||
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||
find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui GuiPrivate)
|
||||
find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui)
|
||||
if(Qt6DBus_FOUND)
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::DBus Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
|
||||
target_compile_definitions(3rdparty_qt6 INTERFACE -DHAVE_QTDBUS)
|
||||
else()
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
|
||||
endif()
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::GuiPrivate)
|
||||
target_include_directories(3rdparty_qt6 INTERFACE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(Qt6Widgets_FOUND)
|
||||
|
|
|
|||
2
3rdparty/zstd/CMakeLists.txt
vendored
2
3rdparty/zstd/CMakeLists.txt
vendored
|
|
@ -10,7 +10,7 @@ else()
|
|||
option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON)
|
||||
option(ZSTD_BUILD_TESTS "BUILD TESTS" OFF)
|
||||
|
||||
add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(zstd/build/cmake EXLUDE_FROM_ALL)
|
||||
add_library(3rdparty_zstd INTERFACE)
|
||||
target_link_libraries(3rdparty_zstd INTERFACE libzstd_static)
|
||||
endif()
|
||||
|
|
|
|||
15
BUILDING.md
15
BUILDING.md
|
|
@ -8,38 +8,37 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
|||
### Windows 10 or later
|
||||
|
||||
The following tools are required to build RPCS3 on Windows 10 or later:
|
||||
- [Visual Studio 2022/2026](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
- [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
|
||||
|
||||
**NOTES:**
|
||||
- **Visual Studio 2026** needs at least **CMake 4.2.0+**.
|
||||
- **Visual Studio 2022/2026** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
|
||||
- **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
|
||||
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
|
||||
on how to build the project with **Visual Studio**.
|
||||
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project
|
||||
with standalone **CMake** tool.
|
||||
|
||||
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
- [Qt 6.10.1](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Qt 6.9.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
|
||||
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
|
||||
|
||||
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.10.1\msvc2022_64\`
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.9.3\msvc2022_64\`
|
||||
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
|
||||
|
||||
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2022) instead.
|
||||
|
||||
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
|
||||
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.10.1\msvc2022_64\`
|
||||
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.9.3\msvc2022_64\`
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
|
||||
- Clang 17+ or GCC 13+
|
||||
- [CMake 3.28.0+](https://www.cmake.org/download/)
|
||||
- [Qt 6.10.1](https://www.qt.io/download-qt-installer)
|
||||
- [Qt 6.9.3](https://www.qt.io/download-qt-installer)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
- [SDL3](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
|
||||
|
|
@ -122,7 +121,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
|
|||
##### Configuring the Qt Plugin (if used)
|
||||
|
||||
1) go to `Extensions->Qt VS Tools->Qt Versions`
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.10.1\msvc2022_64`, version will fill in automatically
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.9.3\msvc2022_64`, version will fill in automatically
|
||||
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
|
||||
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ if(MSVC)
|
|||
endif()
|
||||
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message(FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms.")
|
||||
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
|
||||
endif()
|
||||
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
|
||||
|
|
|
|||
|
|
@ -166,55 +166,6 @@ bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool try_to_uint128(u128* out, std::string_view value)
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_uint128(): called with an empty string");
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 result_low = 0, result_high = 0;
|
||||
const char* start_high64 = value.data();
|
||||
const char* end = value.data() + value.size();
|
||||
|
||||
if (start_high64[0] == '0' && value.size() >= 2 && (start_high64[1] == 'x' || start_high64[1] == 'X'))
|
||||
{
|
||||
// Hex support
|
||||
start_high64 += 2;
|
||||
}
|
||||
|
||||
const char* start_low64 = end - std::min<usz>(end - start_high64, 16);
|
||||
|
||||
// Hexadecimal-only
|
||||
constexpr int base = 16;
|
||||
|
||||
auto ret = std::from_chars(start_low64, end, result_low, base);
|
||||
|
||||
if (ret.ec != std::errc() || ret.ptr != end)
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_uint128('%s'): invalid integer", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (start_high64 == start_low64)
|
||||
{
|
||||
if (out) *out = result_low;
|
||||
return true;
|
||||
}
|
||||
|
||||
ret = std::from_chars(start_high64, start_low64, result_high, base);
|
||||
|
||||
if (ret.ec != std::errc() || ret.ptr != start_low64)
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_uint128('%s'): invalid integer", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out) *out = result_low + (u128{result_high} << 64);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> cfg::make_float_range(f64 min, f64 max)
|
||||
{
|
||||
return {std::to_string(min), std::to_string(max)};
|
||||
|
|
@ -327,19 +278,6 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string cfg::uint128::to_string(u128 value) noexcept
|
||||
{
|
||||
std::string result = "0x";
|
||||
result.resize(result.size() + 32);
|
||||
|
||||
for (u32 i = 0; i < 32; i++)
|
||||
{
|
||||
result[result.size() - 1 - i] = "0123456789ABCDEF"[static_cast<u64>(value >> (i * 4)) % 16];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> cfg::try_to_enum_list(decltype(&fmt_class_string<int>::format) func)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ namespace cfg
|
|||
_enum, // cfg::_enum type
|
||||
_int, // cfg::_int type
|
||||
uint, // cfg::uint type
|
||||
uint128, // cfg::uint128 type
|
||||
string, // cfg::string type
|
||||
set, // cfg::set_entry type
|
||||
map, // cfg::map_entry type
|
||||
|
|
@ -579,86 +578,6 @@ namespace cfg
|
|||
// Alias for 64 bit int
|
||||
using uint64 = uint<0, u64{umax}>;
|
||||
|
||||
// Unsigned 128-bit integer entry.
|
||||
class uint128 final : public _base
|
||||
{
|
||||
using int_type = u128;
|
||||
|
||||
atomic_t<int_type> m_value{};
|
||||
int_type original_def = 0;
|
||||
|
||||
public:
|
||||
int_type def;
|
||||
|
||||
uint128(node* owner, const std::string& name, int_type def = 0, bool dynamic = false)
|
||||
: _base(type::uint128, owner, name, dynamic)
|
||||
, m_value(def)
|
||||
, original_def(def)
|
||||
, def(def)
|
||||
{
|
||||
}
|
||||
|
||||
operator int_type() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
operator ullong() const
|
||||
{
|
||||
return static_cast<ullong>(m_value.load());
|
||||
}
|
||||
|
||||
int_type get() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
m_value = def;
|
||||
}
|
||||
|
||||
void restore_defaults() override
|
||||
{
|
||||
def = original_def;
|
||||
}
|
||||
|
||||
static std::string to_string(u128 value) noexcept;
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
return to_string(m_value.load());
|
||||
}
|
||||
|
||||
std::string def_to_string() const override
|
||||
{
|
||||
return to_string(def);
|
||||
}
|
||||
|
||||
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
u128 result;
|
||||
if (try_to_uint128(&result, value))
|
||||
{
|
||||
m_value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void set(u128 value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
std::vector<std::string> to_list() const override
|
||||
{
|
||||
// Should not be used
|
||||
return make_uint_range(0, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Simple string entry with mutex
|
||||
class string : public _base
|
||||
{
|
||||
|
|
|
|||
|
|
@ -658,11 +658,7 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
|
|||
std::string result;
|
||||
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
|
||||
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
|
||||
null_mod->setTargetTriple(llvm::Triple(jit_compiler::triple1()));
|
||||
#else
|
||||
null_mod->setTargetTriple(jit_compiler::triple1());
|
||||
#endif
|
||||
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
|
||||
|
||||
|
|
@ -676,11 +672,7 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
|
|||
else
|
||||
{
|
||||
mem = std::make_unique<MemoryManager2>(std::move(symbols_cement));
|
||||
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
|
||||
null_mod->setTargetTriple(llvm::Triple(jit_compiler::triple2()));
|
||||
#else
|
||||
null_mod->setTargetTriple(jit_compiler::triple2());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ namespace fmt
|
|||
}
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
[[noreturn]] ~throw_exception() = default;
|
||||
[[noreturn]] ~throw_exception();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max);
|
|||
// Convert string to unsigned integer
|
||||
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max);
|
||||
|
||||
// Convert string to unsigned int128_t
|
||||
bool try_to_uint128(u128* out, std::string_view value);
|
||||
|
||||
// Convert string to float
|
||||
bool try_to_float(f64* out, std::string_view value, f64 min, f64 max);
|
||||
|
||||
|
|
|
|||
|
|
@ -106,11 +106,6 @@ thread_local u64 g_tls_wait_fail = 0;
|
|||
thread_local bool g_tls_access_violation_recovered = false;
|
||||
extern thread_local std::string(*g_tls_log_prefix)();
|
||||
|
||||
namespace stx
|
||||
{
|
||||
atomic_t<u32> g_launch_retainer{0};
|
||||
}
|
||||
|
||||
// Report error and call std::abort(), defined in main.cpp
|
||||
[[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true);
|
||||
|
||||
|
|
|
|||
|
|
@ -465,8 +465,6 @@ public:
|
|||
namespace stx
|
||||
{
|
||||
struct launch_retainer;
|
||||
|
||||
extern atomic_t<u32> g_launch_retainer;
|
||||
}
|
||||
|
||||
// Derived from the callable object Context, possibly a lambda
|
||||
|
|
@ -483,11 +481,6 @@ class named_thread final : public Context, result_storage<Context>, thread_base
|
|||
|
||||
u64 entry_point2()
|
||||
{
|
||||
while (u32 value = stx::g_launch_retainer)
|
||||
{
|
||||
stx::g_launch_retainer.wait(value);
|
||||
}
|
||||
|
||||
thread::initialize([]()
|
||||
{
|
||||
if constexpr (!result::empty)
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// Generic deferred routine wrapper
|
||||
// Use-case is similar to "defer" statement in other languages, just invokes a callback when the object goes out of scope
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template <typename F>
|
||||
requires std::is_invocable_v<F>
|
||||
class deferred_op
|
||||
{
|
||||
public:
|
||||
deferred_op(F&& callback)
|
||||
: m_callback(callback)
|
||||
{}
|
||||
|
||||
~deferred_op()
|
||||
{
|
||||
m_callback();
|
||||
}
|
||||
|
||||
private:
|
||||
F m_callback;
|
||||
};
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ QPushButton::disabled {
|
|||
/* QSpinBox (Settings -> Emulator -> width/height) */
|
||||
/* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
height: 1.50em;
|
||||
height: 0.1em;
|
||||
background-color: #b3ac98;
|
||||
}
|
||||
QSpinBox::disabled, QDoubleSpinBox::disabled {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ if(MSVC)
|
|||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_DEPRECATE=1 _CRT_NON_CONFORMING_SWPRINTFS=1 _SCL_SECURE_NO_WARNINGS=1
|
||||
NOMINMAX _ENABLE_EXTENDED_ALIGNED_STORAGE=1 _HAS_EXCEPTIONS=0)
|
||||
add_link_options(/DYNAMICBASE)
|
||||
|
||||
#TODO: Some of these could be cleaned up
|
||||
add_compile_options(/wd4805) # Comparing boolean and int
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ else ()
|
|||
|
||||
find_package_handle_standard_args(FFMPEG
|
||||
DEFAULT_MSG
|
||||
FFMPEG_LIBAVCODEC FFMPEG_LIBAVFORMAT FFMPEG_LIBAVUTIL FFMPEG_LIBSWSCALE FFMPEG_LIBSWRESAMPLE
|
||||
FFMPEG_LIBAVCODEC FFMPEG_LIBAVFORMAT FFMPEG_LIBSWSCALE FFMPEG_LIBSWRESAMPLE
|
||||
)
|
||||
|
||||
if (FFMPEG_FOUND)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <charconv>
|
||||
#include <string_view>
|
||||
|
||||
std::string to_hex(std::uint64_t value, bool prfx = true)
|
||||
{
|
||||
|
|
@ -86,7 +85,7 @@ int main(int argc, char* argv[])
|
|||
// Decode address and try to find the object
|
||||
std::uint64_t addr = -1;
|
||||
|
||||
std::from_chars(arg.data() + ("--start-address=0x"sv).size(), arg.data() + arg.size(), addr, 16);
|
||||
std::from_chars(arg.data() + strlen("--start-address=0x"), arg.data() + arg.size(), addr, 16);
|
||||
|
||||
for (int j = 0; j < 0x100'0000; j++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,16 @@ include(CheckFunctionExists)
|
|||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
set(ADDITIONAL_LIBS "")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
#on some Linux distros shm_unlink and similar functions are in librt only
|
||||
list(APPEND ADDITIONAL_LIBS "rt")
|
||||
elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||
#it seems like glibc includes the iconv functions we use but other libc
|
||||
#implementations like the one on OSX don't seem implement them
|
||||
list(APPEND ADDITIONAL_LIBS "iconv")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
add_compile_definitions(DATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
|
||||
# Optionally enable X11 for window management
|
||||
|
|
@ -68,16 +78,8 @@ if (NOT ANDROID)
|
|||
3rdparty::libcurl
|
||||
3rdparty::zlib
|
||||
3rdparty::opencv
|
||||
3rdparty::fusion)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
#on some Linux distros shm_unlink and similar functions are in librt only
|
||||
target_link_libraries(rpcs3_lib PRIVATE rt)
|
||||
elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||
#it seems like glibc includes the iconv functions we use but other libc
|
||||
#implementations like the one on OSX don't seem implement them
|
||||
target_link_libraries(rpcs3_lib PRIVATE iconv)
|
||||
endif()
|
||||
3rdparty::fusion
|
||||
${ADDITIONAL_LIBS})
|
||||
|
||||
# Unix display manager
|
||||
if(X11_FOUND)
|
||||
|
|
@ -104,16 +106,19 @@ if (NOT ANDROID)
|
|||
endif()
|
||||
|
||||
# Build rpcs3 executable
|
||||
add_executable(rpcs3 WIN32 MACOSX_BUNDLE)
|
||||
if(WIN32)
|
||||
add_executable(rpcs3 WIN32)
|
||||
target_sources(rpcs3 PRIVATE rpcs3.rc)
|
||||
target_compile_definitions(rpcs3 PRIVATE UNICODE _UNICODE)
|
||||
elseif(APPLE)
|
||||
add_executable(rpcs3 MACOSX_BUNDLE)
|
||||
target_sources(rpcs3 PRIVATE rpcs3.icns update_helper.sh)
|
||||
set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
set_target_properties(rpcs3
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
|
||||
else()
|
||||
add_executable(rpcs3)
|
||||
endif()
|
||||
|
||||
target_sources(rpcs3
|
||||
|
|
@ -132,12 +137,17 @@ if (NOT ANDROID)
|
|||
|
||||
# Copy icons to executable directory
|
||||
if(APPLE)
|
||||
if (CMAKE_BUILD_TYPE MATCHES "Debug" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
|
||||
set(QT_DEPLOY_FLAGS "-no-strip")
|
||||
else()
|
||||
set(QT_DEPLOY_FLAGS "")
|
||||
endif()
|
||||
qt_finalize_target(rpcs3)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "$<$<CONFIG:Debug,RelWithDebInfo>:-no-strip>")
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
|
||||
elseif(UNIX)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
|
||||
|
|
@ -188,11 +198,8 @@ if(BUILD_RPCS3_TESTS)
|
|||
PRIVATE
|
||||
tests/test.cpp
|
||||
tests/test_fmt.cpp
|
||||
tests/test_pair.cpp
|
||||
tests/test_tuple.cpp
|
||||
tests/test_simple_array.cpp
|
||||
tests/test_address_range.cpp
|
||||
tests/test_rsx_cfg.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(rpcs3_test
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ SELF_KEY::SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::str
|
|||
version_end = ver_end;
|
||||
revision = rev;
|
||||
self_type = type;
|
||||
hex_to_bytes(erk, e, 0);
|
||||
hex_to_bytes(riv, r, 0);
|
||||
hex_to_bytes(pub, pb, 0);
|
||||
hex_to_bytes(priv, pr, 0);
|
||||
hex_to_bytes(erk, e.c_str(), 0);
|
||||
hex_to_bytes(riv, r.c_str(), 0);
|
||||
hex_to_bytes(pub, pb.c_str(), 0);
|
||||
hex_to_bytes(priv, pr.c_str(), 0);
|
||||
curve_type = ct;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,9 @@
|
|||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "key_vault.h"
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
|
|
@ -23,24 +21,50 @@
|
|||
// Auxiliary functions (endian swap, xor).
|
||||
|
||||
// Hex string conversion auxiliary functions.
|
||||
void hex_to_bytes(unsigned char* data, std::string_view hex_str, unsigned int str_length)
|
||||
u64 hex_to_u64(const char* hex_str)
|
||||
{
|
||||
const auto strn_length = (str_length > 0) ? str_length : hex_str.size();
|
||||
auto length = std::strlen(hex_str);
|
||||
u64 tmp = 0;
|
||||
u64 result = 0;
|
||||
char c;
|
||||
|
||||
while (length--)
|
||||
{
|
||||
c = *hex_str++;
|
||||
if((c >= '0') && (c <= '9'))
|
||||
tmp = c - '0';
|
||||
else if((c >= 'a') && (c <= 'f'))
|
||||
tmp = c - 'a' + 10;
|
||||
else if((c >= 'A') && (c <= 'F'))
|
||||
tmp = c - 'A' + 10;
|
||||
else
|
||||
tmp = 0;
|
||||
result |= (tmp << (length * 4));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void hex_to_bytes(unsigned char* data, const char* hex_str, unsigned int str_length)
|
||||
{
|
||||
const auto strn_length = (str_length > 0) ? str_length : std::strlen(hex_str);
|
||||
auto data_length = strn_length / 2;
|
||||
char tmp_buf[3] = {0, 0, 0};
|
||||
|
||||
// Don't convert if the string length is odd.
|
||||
if ((strn_length % 2) == 0)
|
||||
{
|
||||
for (size_t i = 0; i < strn_length; i += 2)
|
||||
while (data_length--)
|
||||
{
|
||||
const auto [ptr, err] = std::from_chars(hex_str.data() + i, hex_str.data() + i + 2, *data++, 16);
|
||||
if (err != std::errc())
|
||||
{
|
||||
fmt::throw_exception("Failed to read hex string: %s", std::make_error_code(err).message());
|
||||
}
|
||||
tmp_buf[0] = *hex_str++;
|
||||
tmp_buf[1] = *hex_str++;
|
||||
|
||||
*data++ = static_cast<u8>(hex_to_u64(tmp_buf) & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
|
||||
void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len)
|
||||
{
|
||||
|
|
@ -157,7 +181,7 @@ std::array<u8, PASSPHRASE_KEY_LEN> sc_combine_laid_paid(s64 laid, s64 paid)
|
|||
{
|
||||
const std::string paid_laid = fmt::format("%016llx%016llx", laid, paid);
|
||||
std::array<u8, PASSPHRASE_KEY_LEN> out{};
|
||||
hex_to_bytes(out.data(), paid_laid, PASSPHRASE_KEY_LEN * 2);
|
||||
hex_to_bytes(out.data(), paid_laid.c_str(), PASSPHRASE_KEY_LEN * 2);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string_view>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum { CRYPTO_MAX_PATH = 4096 };
|
||||
|
||||
|
|
@ -16,7 +15,8 @@ char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PA
|
|||
std::string sha256_get_hash(const char* data, usz size, bool lower_case);
|
||||
|
||||
// Hex string conversion auxiliary functions.
|
||||
void hex_to_bytes(unsigned char* data, std::string_view hex_str, unsigned int str_length);
|
||||
u64 hex_to_u64(const char* hex_str);
|
||||
void hex_to_bytes(unsigned char *data, const char *hex_str, unsigned int str_length);
|
||||
|
||||
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
|
||||
void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,6 @@ namespace audio
|
|||
g_cfg.audio.volume.set(std::clamp<s32>(new_volume, g_cfg.audio.volume.min, g_cfg.audio.volume.max));
|
||||
Emu.GetCallbacks().update_emu_settings();
|
||||
|
||||
rsx::overlays::queue_message(localized_string(localized_string_id::AUDIO_CHANGED, "%d%%", g_cfg.audio.volume.get()), 3'000'000, {}, rsx::overlays::message_pin_location::top_left, {}, true, true);
|
||||
rsx::overlays::queue_message(get_localized_string(localized_string_id::AUDIO_CHANGED, fmt::format("%d%%", g_cfg.audio.volume.get()).c_str()), 3'000'000);
|
||||
}
|
||||
} // namespace audio
|
||||
|
|
|
|||
|
|
@ -402,7 +402,6 @@ target_sources(rpcs3_emu PRIVATE
|
|||
Io/GunCon3.cpp
|
||||
Io/Infinity.cpp
|
||||
Io/interception.cpp
|
||||
Io/KamenRider.cpp
|
||||
Io/KeyboardHandler.cpp
|
||||
Io/midi_config_types.cpp
|
||||
Io/mouse_config.cpp
|
||||
|
|
@ -516,7 +515,6 @@ target_sources(rpcs3_emu PRIVATE
|
|||
RSX/Overlays/overlay_video.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
|
||||
RSX/Program/Assembler/FPToCFG.cpp
|
||||
RSX/Program/CgBinaryProgram.cpp
|
||||
RSX/Program/CgBinaryFragmentProgram.cpp
|
||||
RSX/Program/CgBinaryVertexProgram.cpp
|
||||
|
|
@ -579,7 +577,6 @@ if(TARGET 3rdparty_vulkan)
|
|||
RSX/VK/vkutils/buffer_object.cpp
|
||||
RSX/VK/vkutils/chip_class.cpp
|
||||
RSX/VK/vkutils/commands.cpp
|
||||
RSX/VK/vkutils/ex.cpp
|
||||
RSX/VK/vkutils/data_heap.cpp
|
||||
RSX/VK/vkutils/descriptors.cpp
|
||||
RSX/VK/vkutils/image.cpp
|
||||
|
|
@ -592,7 +589,6 @@ if(TARGET 3rdparty_vulkan)
|
|||
RSX/VK/vkutils/device.cpp
|
||||
RSX/VK/vkutils/sampler.cpp
|
||||
RSX/VK/vkutils/shared.cpp
|
||||
RSX/VK/vkutils/unique_resource.cpp
|
||||
RSX/VK/VKAsyncScheduler.cpp
|
||||
RSX/VK/VKCommandStream.cpp
|
||||
RSX/VK/VKCommonDecompiler.cpp
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ struct cpu_prof
|
|||
reservation_samples = 0;
|
||||
}
|
||||
|
||||
static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, u32 type_id, bool extended_print = false)
|
||||
static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, bool extended_print = false)
|
||||
{
|
||||
// Print results
|
||||
std::string results;
|
||||
|
|
@ -204,18 +204,11 @@ struct cpu_prof
|
|||
const f64 _frac = count / busy / samples;
|
||||
|
||||
// Print only 7 hash characters out of 11 (which covers roughly 48 bits)
|
||||
if (type_id == 2)
|
||||
{
|
||||
fmt::append(results, "\n\t[%s", fmt::base57(be_t<u64>{name}));
|
||||
results.resize(results.size() - 4);
|
||||
fmt::append(results, "\n\t[%s", fmt::base57(be_t<u64>{name}));
|
||||
results.resize(results.size() - 4);
|
||||
|
||||
// Print chunk address from lowest 16 bits
|
||||
fmt::append(results, "...chunk-0x%05x]: %.4f%% (%u)", (name & 0xffff) * 4, _frac * 100., count);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(results, "\n\t[0x%07x]: %.4f%% (%u)", name, _frac * 100., count);
|
||||
}
|
||||
// Print chunk address from lowest 16 bits
|
||||
fmt::append(results, "...chunk-0x%05x]: %.4f%% (%u)", (name & 0xffff) * 4, _frac * 100., count);
|
||||
|
||||
if (results.size() >= (extended_print ? 10000 : 5000))
|
||||
{
|
||||
|
|
@ -264,37 +257,27 @@ struct cpu_prof
|
|||
}
|
||||
|
||||
// Print results
|
||||
const std::string results = format(chart, samples, idle, ptr->id_type());
|
||||
const std::string results = format(chart, samples, idle);
|
||||
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):\n%s", ptr->get_name(), ptr->id, samples, get_percent(idle, samples), new_samples, reservation_samples, get_percent(reservation_samples, samples - idle), results);
|
||||
|
||||
new_samples = 0;
|
||||
}
|
||||
|
||||
static void print_all(std::unordered_map<shared_ptr<cpu_thread>, sample_info>& threads, sample_info& all_info, u32 type_id)
|
||||
static void print_all(std::unordered_map<shared_ptr<cpu_thread>, sample_info>& threads, sample_info& all_info)
|
||||
{
|
||||
u64 new_samples = 0;
|
||||
|
||||
// Print all results and cleanup
|
||||
for (auto& [ptr, info] : threads)
|
||||
{
|
||||
if (ptr->id_type() != type_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
new_samples += info.new_samples;
|
||||
info.print(ptr);
|
||||
}
|
||||
|
||||
std::multimap<u64, u64, std::greater<u64>> chart;
|
||||
|
||||
for (auto& [ptr, info] : threads)
|
||||
for (auto& [_, info] : threads)
|
||||
{
|
||||
if (ptr->id_type() != type_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// This function collects thread information regardless of 'new_samples' member state
|
||||
for (auto& [name, count] : info.freq)
|
||||
{
|
||||
|
|
@ -318,7 +301,7 @@ struct cpu_prof
|
|||
|
||||
if (new_samples < min_print_all_samples && thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
profiler.notice("All %s Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", type_id == 1 ? "PPU" : "SPU", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle));
|
||||
profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -327,13 +310,12 @@ struct cpu_prof
|
|||
chart.emplace(count, name);
|
||||
}
|
||||
|
||||
const std::string results = format(chart, samples, idle, type_id, true);
|
||||
profiler.notice("All %s Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):%s", type_id == 1 ? "PPU" : "SPU", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle), results);
|
||||
const std::string results = format(chart, samples, idle, true);
|
||||
profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):%s", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle), results);
|
||||
}
|
||||
};
|
||||
|
||||
sample_info all_spu_threads_info{};
|
||||
sample_info all_ppu_threads_info{};
|
||||
sample_info all_threads_info{};
|
||||
|
||||
void operator()()
|
||||
{
|
||||
|
|
@ -394,11 +376,8 @@ struct cpu_prof
|
|||
{
|
||||
if (auto state = +ptr->state; cpu_flag::exit - state)
|
||||
{
|
||||
const auto spu = ptr->try_get<spu_thread>();
|
||||
const auto ppu = ptr->try_get<ppu_thread>();
|
||||
|
||||
// Get short function hash
|
||||
const u64 name = ppu ? atomic_storage<u32>::load(ppu->cia) : atomic_storage<u64>::load(ptr->block_hash);
|
||||
const u64 name = atomic_storage<u64>::load(ptr->block_hash);
|
||||
|
||||
// Append occurrence
|
||||
info.samples++;
|
||||
|
|
@ -408,17 +387,17 @@ struct cpu_prof
|
|||
info.freq[name]++;
|
||||
info.new_samples++;
|
||||
|
||||
if (spu)
|
||||
if (auto spu = ptr->try_get<spu_thread>())
|
||||
{
|
||||
if (spu->raddr)
|
||||
{
|
||||
info.reservation_samples++;
|
||||
}
|
||||
|
||||
// Append verification time to fixed common name 0000000...chunk-0x3fffc
|
||||
if (name >> 16 && (name & 0xffff) == 0)
|
||||
info.freq[0xffff]++;
|
||||
}
|
||||
|
||||
// Append verification time to fixed common name 0000000...chunk-0x3fffc
|
||||
if (name >> 16 && (name & 0xffff) == 0)
|
||||
info.freq[0xffff]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -441,10 +420,8 @@ struct cpu_prof
|
|||
{
|
||||
profiler.success("Flushing profiling results...");
|
||||
|
||||
all_ppu_threads_info = {};
|
||||
all_spu_threads_info = {};
|
||||
sample_info::print_all(threads, all_ppu_threads_info, 1);
|
||||
sample_info::print_all(threads, all_spu_threads_info, 2);
|
||||
all_threads_info = {};
|
||||
sample_info::print_all(threads, all_threads_info);
|
||||
}
|
||||
|
||||
if (Emu.IsPaused())
|
||||
|
|
@ -465,8 +442,7 @@ struct cpu_prof
|
|||
}
|
||||
|
||||
// Print all remaining results
|
||||
sample_info::print_all(threads, all_ppu_threads_info, 1);
|
||||
sample_info::print_all(threads, all_spu_threads_info, 2);
|
||||
sample_info::print_all(threads, all_threads_info);
|
||||
}
|
||||
|
||||
static constexpr auto thread_name = "CPU Profiler"sv;
|
||||
|
|
@ -483,7 +459,7 @@ extern f64 get_cpu_program_usage_percent(u64 hash)
|
|||
{
|
||||
u64 total = 0;
|
||||
|
||||
for (auto [name, count] : prof->all_spu_threads_info.freq)
|
||||
for (auto [name, count] : prof->all_threads_info.freq)
|
||||
{
|
||||
if ((name & -65536) == hash)
|
||||
{
|
||||
|
|
@ -496,7 +472,7 @@ extern f64 get_cpu_program_usage_percent(u64 hash)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return std::max<f64>(0.0001, static_cast<f64>(total) * 100 / (prof->all_spu_threads_info.samples - prof->all_spu_threads_info.idle));
|
||||
return std::max<f64>(0.0001, static_cast<f64>(total) * 100 / (prof->all_threads_info.samples - prof->all_threads_info.idle));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -663,22 +639,27 @@ void cpu_thread::operator()()
|
|||
thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(get_class()));
|
||||
}
|
||||
|
||||
ensure(g_fxo->is_init<cpu_profiler>());
|
||||
while (!g_fxo->is_init<cpu_profiler>())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Can we have a little race, right? First thread is started concurrently with g_fxo->init()
|
||||
thread_ctrl::wait_for(1000);
|
||||
}
|
||||
|
||||
switch (get_class())
|
||||
{
|
||||
case thread_class::ppu:
|
||||
{
|
||||
if (g_cfg.core.ppu_prof)
|
||||
{
|
||||
g_fxo->get<cpu_profiler>().registered.push(id);
|
||||
}
|
||||
|
||||
//g_fxo->get<cpu_profiler>().registered.push(id);
|
||||
break;
|
||||
}
|
||||
case thread_class::spu:
|
||||
{
|
||||
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
|
||||
if (g_cfg.core.spu_prof)
|
||||
{
|
||||
g_fxo->get<cpu_profiler>().registered.push(id);
|
||||
}
|
||||
|
|
@ -1565,7 +1546,7 @@ void cpu_thread::flush_profilers() noexcept
|
|||
return;
|
||||
}
|
||||
|
||||
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug || g_cfg.core.ppu_prof)
|
||||
if (g_cfg.core.spu_prof)
|
||||
{
|
||||
g_fxo->get<cpu_profiler>().registered.push(0);
|
||||
}
|
||||
|
|
@ -1604,30 +1585,22 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
|||
|
||||
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu)
|
||||
{
|
||||
if (give_up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
|
||||
|
||||
if (spu.current_func && spu.unsavable && !force_collect)
|
||||
if (spu.current_func && spu.unsavable)
|
||||
{
|
||||
const u64 start = spu.start_time;
|
||||
|
||||
// Automatically give up if it is asleep 5 seconds or more
|
||||
if (start && current > start && current - start >= 5'000'000)
|
||||
// Automatically give up if it is asleep 15 seconds or more
|
||||
if (start && current > start && current - start >= 15'000'000)
|
||||
{
|
||||
give_up = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
|
||||
});
|
||||
|
||||
if (give_up)
|
||||
if (!force_collect && give_up)
|
||||
{
|
||||
spu_list.clear();
|
||||
old_counter = umax;
|
||||
return decltype(&spu_list){};
|
||||
}
|
||||
|
||||
|
|
@ -1652,7 +1625,6 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
|||
}
|
||||
else if (get_system_time() - start >= 150'000)
|
||||
{
|
||||
std::this_thread::sleep_for(1ms);
|
||||
passed_count++;
|
||||
start = 0;
|
||||
continue;
|
||||
|
|
@ -1664,29 +1636,37 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
|||
if (!spu_list)
|
||||
{
|
||||
// Give up for now
|
||||
std::this_thread::sleep_for(50ms);
|
||||
std::this_thread::sleep_for(10ms);
|
||||
passed_count++;
|
||||
start = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Avoid using suspend_all when more than 2 threads known to be unsavable
|
||||
u32 savable_threads = 0;
|
||||
u32 unsavable_threads = 0;
|
||||
|
||||
for (auto& spu : *spu_list)
|
||||
{
|
||||
if (!spu->unsavable)
|
||||
if (spu->unsavable)
|
||||
{
|
||||
savable_threads++;
|
||||
unsavable_threads++;
|
||||
|
||||
if (unsavable_threads >= 3)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!savable_threads)
|
||||
if (unsavable_threads >= 3)
|
||||
{
|
||||
std::this_thread::yield();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flag for optimization
|
||||
bool paused_anyone = false;
|
||||
|
||||
if (cpu_thread::suspend_all(nullptr, {}, [&]()
|
||||
{
|
||||
if (!get_spus(false, true))
|
||||
|
|
@ -1715,13 +1695,19 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
|||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
paused_anyone = true;
|
||||
ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& spu : *spu_list)
|
||||
if (failed && paused_anyone)
|
||||
{
|
||||
if (!failed && !is_emu_paused)
|
||||
// For faster signalling, first remove state flags then batch notifications
|
||||
for (auto& spu : *spu_list)
|
||||
{
|
||||
ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause));
|
||||
spu->state -= cpu_flag::dbg_global_pause;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1733,6 +1719,13 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!paused_anyone)
|
||||
{
|
||||
// Need not do anything
|
||||
std::this_thread::yield();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& spu : *spu_list)
|
||||
{
|
||||
if (spu->state & cpu_flag::wait)
|
||||
|
|
@ -1762,7 +1755,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
|
|||
{
|
||||
spu->state.notify_one();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4007,7 +4007,7 @@ llvm::CallInst* llvm_asm(
|
|||
const std::string& constraints,
|
||||
llvm::LLVMContext& context)
|
||||
{
|
||||
llvm::ArrayRef<llvm::Type*> types_ref {};
|
||||
llvm::ArrayRef<llvm::Type*> types_ref = std::nullopt;
|
||||
std::vector<llvm::Type*> types;
|
||||
types.reserve(args.size());
|
||||
|
||||
|
|
|
|||
|
|
@ -111,41 +111,7 @@ void AtracXdecDecoder::alloc_avcodec()
|
|||
fmt::throw_exception("avcodec_find_decoder() failed");
|
||||
}
|
||||
|
||||
packet = av_packet_alloc();
|
||||
if (!packet)
|
||||
{
|
||||
fmt::throw_exception("av_packet_alloc() failed");
|
||||
}
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
{
|
||||
fmt::throw_exception("av_frame_alloc() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void AtracXdecDecoder::free_avcodec()
|
||||
{
|
||||
if (packet)
|
||||
{
|
||||
av_packet_free(&packet);
|
||||
}
|
||||
if (frame)
|
||||
{
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
if (ctx)
|
||||
{
|
||||
avcodec_free_context(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void AtracXdecDecoder::init_avcodec()
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
avcodec_free_context(&ctx);
|
||||
}
|
||||
ensure(!(codec->capabilities & AV_CODEC_CAP_SUBFRAMES));
|
||||
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
if (!ctx)
|
||||
|
|
@ -167,6 +133,34 @@ void AtracXdecDecoder::init_avcodec()
|
|||
frame->buf[0] = av_buffer_create(frame->data[0], ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * frame->ch_layout.nb_channels, [](void*, uint8_t*){}, nullptr, 0);
|
||||
return 0;
|
||||
};
|
||||
|
||||
packet = av_packet_alloc();
|
||||
if (!packet)
|
||||
{
|
||||
fmt::throw_exception("av_packet_alloc() failed");
|
||||
}
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
{
|
||||
fmt::throw_exception("av_frame_alloc() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void AtracXdecDecoder::free_avcodec()
|
||||
{
|
||||
av_packet_free(&packet);
|
||||
av_frame_free(&frame);
|
||||
avcodec_free_context(&ctx);
|
||||
}
|
||||
|
||||
void AtracXdecDecoder::init_avcodec()
|
||||
{
|
||||
if (int err = avcodec_close(ctx); err)
|
||||
{
|
||||
fmt::throw_exception("avcodec_close() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
|
||||
}
|
||||
|
||||
ctx->block_align = nbytes;
|
||||
ctx->ch_layout.nb_channels = nch_in;
|
||||
ctx->sample_rate = sampling_freq;
|
||||
|
|
|
|||
|
|
@ -192,10 +192,10 @@ struct AtracXdecDecoder
|
|||
|
||||
// HLE exclusive
|
||||
b8 config_is_set = false; // For savestates
|
||||
const AVCodec* codec = nullptr;
|
||||
AVCodecContext* ctx = nullptr;
|
||||
AVPacket* packet = nullptr;
|
||||
AVFrame* frame = nullptr;
|
||||
const AVCodec* codec;
|
||||
AVCodecContext* ctx;
|
||||
AVPacket* packet;
|
||||
AVFrame* frame;
|
||||
|
||||
u8 spurs_stuff[84]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc.
|
||||
|
||||
|
|
|
|||
|
|
@ -1139,10 +1139,8 @@ error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellCameraGetBufferInfoEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellCameraInfoEx> info)
|
||||
error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellCamera.notice("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);
|
||||
|
||||
// calls cellCameraGetBufferInfo
|
||||
|
|
@ -1153,16 +1151,10 @@ error_code cellCameraGetBufferInfoEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellC
|
|||
}
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
std::lock_guard lock(g_camera.mutex);
|
||||
|
||||
CellCameraInfoEx info_out;
|
||||
*info = g_camera.info;
|
||||
|
||||
{
|
||||
std::lock_guard lock(g_camera.mutex);
|
||||
|
||||
info_out = g_camera.info;
|
||||
}
|
||||
|
||||
*info = info_out;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -464,8 +464,6 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
|||
{
|
||||
get->isNewData = CELL_HDDGAME_ISNEWDATA_NODIR;
|
||||
get->getParam = {};
|
||||
|
||||
cellGame.warning("cellHddGameCheck(): New data.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -478,22 +476,13 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
|||
if (psf.contains("RESOLUTION")) get->getParam.resolution = ::at32(psf, "RESOLUTION").as_integer();
|
||||
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = ::at32(psf, "SOUND_FORMAT").as_integer();
|
||||
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, ::at32(psf, "TITLE").as_string());
|
||||
|
||||
// Old games do not have APP_VER key
|
||||
strcpy_trunc(get->getParam.dataVersion, psf::get_string(psf, "APP_VER", psf::get_string(sfo, "VERSION", "")));
|
||||
|
||||
if (psf.contains("TITLE_ID"))
|
||||
{
|
||||
strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
|
||||
}
|
||||
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, ::at32(psf, "APP_VER").as_string());
|
||||
if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
|
||||
|
||||
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
|
||||
{
|
||||
strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i)));
|
||||
}
|
||||
|
||||
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
|
||||
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
|
||||
}
|
||||
|
||||
// TODO ?
|
||||
|
|
@ -561,7 +550,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
|||
|
||||
case CELL_HDDGAME_CBRESULT_ERR_NOSPACE:
|
||||
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", result->errNeedSizeKB);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, "%d", result->errNeedSizeKB);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, fmt::format("%d", result->errNeedSizeKB).c_str());
|
||||
break;
|
||||
|
||||
case CELL_HDDGAME_CBRESULT_ERR_BROKEN:
|
||||
|
|
@ -576,12 +565,12 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
|||
|
||||
case CELL_HDDGAME_CBRESULT_ERR_INVALID:
|
||||
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_INVALID. Error message: %s", result->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, fmt::format("%s", result->invalidMsg).c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, fmt::format("%s", result->invalidMsg).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1180,7 +1169,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
|||
}
|
||||
case CELL_GAMEDATA_CBRESULT_ERR_NOSPACE:
|
||||
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", cbResult->errNeedSizeKB);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, "%d", cbResult->errNeedSizeKB);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, fmt::format("%d", cbResult->errNeedSizeKB).c_str());
|
||||
break;
|
||||
|
||||
case CELL_GAMEDATA_CBRESULT_ERR_BROKEN:
|
||||
|
|
@ -1195,12 +1184,12 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
|||
|
||||
case CELL_GAMEDATA_CBRESULT_ERR_INVALID:
|
||||
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_INVALID. Error message: %s", cbResult->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, fmt::format("%s", cbResult->invalidMsg).c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, fmt::format("%s", cbResult->invalidMsg).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1697,7 +1686,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
|
|||
break;
|
||||
case CELL_GAME_ERRDIALOG_NOSPACE:
|
||||
// Not enough available space. The application will continue.
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE, "%d", errNeedSizeKB);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE, fmt::format("%d", errNeedSizeKB).c_str());
|
||||
break;
|
||||
case CELL_GAME_ERRDIALOG_BROKEN_EXIT_GAMEDATA:
|
||||
// Game data is corrupted. The application will be terminated.
|
||||
|
|
@ -1709,7 +1698,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
|
|||
break;
|
||||
case CELL_GAME_ERRDIALOG_NOSPACE_EXIT:
|
||||
// Not enough available space. The application will be terminated.
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE_EXIT, "%d", errNeedSizeKB);
|
||||
error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE_EXIT, fmt::format("%d", errNeedSizeKB).c_str());
|
||||
break;
|
||||
default:
|
||||
return CELL_GAME_ERROR_PARAM;
|
||||
|
|
@ -1723,7 +1712,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
|
|||
}
|
||||
|
||||
error_msg += '\n';
|
||||
error_msg += get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, "%s", dirName);
|
||||
error_msg += get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, fmt::format("%s", dirName).c_str());
|
||||
}
|
||||
|
||||
return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE, msg_dialog_source::_cellGame);
|
||||
|
|
|
|||
|
|
@ -224,8 +224,8 @@ enum
|
|||
struct CellGameDataSystemFileParam
|
||||
{
|
||||
char title[CELL_GAMEDATA_SYSP_TITLE_SIZE];
|
||||
char titleLang[CELL_GAMEDATA_SYSP_LANGUAGE_NUM][CELL_GAMEDATA_SYSP_TITLE_SIZE]; // 0x80
|
||||
char titleId[CELL_GAMEDATA_SYSP_TITLEID_SIZE]; // 0xA80
|
||||
char titleLang[CELL_GAMEDATA_SYSP_LANGUAGE_NUM][CELL_GAMEDATA_SYSP_TITLE_SIZE];
|
||||
char titleId[CELL_GAMEDATA_SYSP_TITLEID_SIZE];
|
||||
char reserved0[2];
|
||||
char dataVersion[CELL_GAMEDATA_SYSP_VERSION_SIZE];
|
||||
char reserved1[2];
|
||||
|
|
@ -248,13 +248,13 @@ struct CellGameDataStatGet
|
|||
{
|
||||
be_t<s32> hddFreeSizeKB;
|
||||
be_t<u32> isNewData;
|
||||
char contentInfoPath[CELL_GAMEDATA_PATH_MAX]; // 0x8
|
||||
char gameDataPath[CELL_GAMEDATA_PATH_MAX]; // 0x427
|
||||
char reserved0[2]; // 0x846
|
||||
be_t<s64> st_atime_; // 0x848
|
||||
be_t<s64> st_mtime_; // 0x850
|
||||
be_t<s64> st_ctime_; // 0x858
|
||||
CellGameDataSystemFileParam getParam; // 0x860
|
||||
char contentInfoPath[CELL_GAMEDATA_PATH_MAX];
|
||||
char gameDataPath[CELL_GAMEDATA_PATH_MAX];
|
||||
char reserved0[2];
|
||||
be_t<s64> st_atime_;
|
||||
be_t<s64> st_mtime_;
|
||||
be_t<s64> st_ctime_;
|
||||
CellGameDataSystemFileParam getParam;
|
||||
be_t<s32> sizeKB;
|
||||
be_t<s32> sysSizeKB;
|
||||
char reserved1[68];
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ public:
|
|||
case move_handler::mouse:
|
||||
case move_handler::raw_mouse:
|
||||
{
|
||||
auto& handler = *ensure(g_fxo->try_get<MouseHandlerBase>());
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
std::lock_guard mouse_lock(handler.mutex);
|
||||
const MouseInfo& info = handler.GetInfo();
|
||||
|
||||
|
|
@ -374,7 +374,7 @@ public:
|
|||
#ifdef HAVE_LIBEVDEV
|
||||
case move_handler::gun:
|
||||
{
|
||||
gun_thread& gun = *ensure(g_fxo->try_get<gun_thread>());
|
||||
gun_thread& gun = g_fxo->get<gun_thread>();
|
||||
std::scoped_lock lock(gun.handler.mutex);
|
||||
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
|
||||
|
||||
|
|
@ -505,7 +505,7 @@ public:
|
|||
case move_handler::mouse:
|
||||
case move_handler::raw_mouse:
|
||||
{
|
||||
auto& handler = *ensure(g_fxo->try_get<MouseHandlerBase>());
|
||||
auto& handler = g_fxo->get<MouseHandlerBase>();
|
||||
std::lock_guard mouse_lock(handler.mutex);
|
||||
|
||||
// Make sure that the mouse handler is initialized
|
||||
|
|
@ -522,7 +522,7 @@ public:
|
|||
#ifdef HAVE_LIBEVDEV
|
||||
case move_handler::gun:
|
||||
{
|
||||
gun_thread& gun = *ensure(g_fxo->try_get<gun_thread>());
|
||||
gun_thread& gun = g_fxo->get<gun_thread>();
|
||||
std::scoped_lock lock(gun.handler.mutex);
|
||||
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
|
||||
connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices);
|
||||
|
|
@ -2284,8 +2284,6 @@ error_code cellGemClearStatusFlags(u32 gem_num, u64 mask)
|
|||
|
||||
error_code cellGemConvertVideoFinish(ppu_thread& ppu)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellGem.warning("cellGemConvertVideoFinish()");
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
|
@ -2308,10 +2306,8 @@ error_code cellGemConvertVideoFinish(ppu_thread& ppu)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellGemConvertVideoStart(ppu_thread& ppu, vm::cptr<void> video_frame)
|
||||
error_code cellGemConvertVideoStart(vm::cptr<void> video_frame)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellGem.warning("cellGemConvertVideoStart(video_frame=*0x%x)", video_frame);
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
|
@ -2463,8 +2459,6 @@ error_code cellGemEnableMagnetometer2(u32 gem_num, u32 enable)
|
|||
|
||||
error_code cellGemEnd(ppu_thread& ppu)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellGem.warning("cellGemEnd()");
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
|
@ -3269,7 +3263,7 @@ error_code cellGemPrepareCamera(s32 max_exposure, f32 image_quality)
|
|||
|
||||
extern error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u32> arg2);
|
||||
extern error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2);
|
||||
extern error_code cellCameraGetBufferInfoEx(ppu_thread&, s32 dev_num, vm::ptr<CellCameraInfoEx> info);
|
||||
extern error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info);
|
||||
|
||||
vm::var<CellCameraInfoEx> info = vm::make_var<CellCameraInfoEx>({});
|
||||
vm::var<u32> arg1 = vm::make_var<u32>({});
|
||||
|
|
@ -3277,7 +3271,7 @@ error_code cellGemPrepareCamera(s32 max_exposure, f32 image_quality)
|
|||
|
||||
cellCameraGetAttribute(0, 0x3e6, arg1, arg2);
|
||||
cellCameraSetAttribute(0, 0x3e6, 0x3e, *arg2 | 0x80);
|
||||
cellCameraGetBufferInfoEx(*cpu_thread::get_current<ppu_thread>(), 0, info);
|
||||
cellCameraGetBufferInfoEx(0, info);
|
||||
|
||||
if (info->width == 640)
|
||||
{
|
||||
|
|
@ -3609,8 +3603,6 @@ error_code cellGemTrackHues(vm::cptr<u32> req_hues, vm::ptr<u32> res_hues)
|
|||
|
||||
error_code cellGemUpdateFinish(ppu_thread& ppu)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellGem.warning("cellGemUpdateFinish()");
|
||||
|
||||
auto& gem = g_fxo->get<gem_config>();
|
||||
|
|
|
|||
|
|
@ -2498,7 +2498,7 @@ s32 UCS2stoSBCSs(vm::cptr<u16> src, vm::ptr<u32> src_len, vm::ptr<u8> dst, vm::p
|
|||
|
||||
for (u32 src_pos = 0; src_pos < *src_len; src_pos++)
|
||||
{
|
||||
const u16 ucs2 = src[src_pos];
|
||||
const s16 ucs2 = src[src_pos];
|
||||
|
||||
if (ucs2 >= 0xfffe)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ error_code cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallba
|
|||
default: string_id = localized_string_id::CELL_MSG_DIALOG_ERROR_DEFAULT; break; // An error has occurred.
|
||||
}
|
||||
|
||||
const std::string error = get_localized_string(string_id, "%08x", errorCode);
|
||||
const std::string error = get_localized_string(string_id, fmt::format("%08x", errorCode).c_str());
|
||||
|
||||
return cellMsgDialogOpen2(CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(error), callback, userData, extParam);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -575,12 +575,12 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
|
|||
|
||||
if (setting & CELL_PAD_SETTING_PRESS_ON)
|
||||
{
|
||||
constexpr u32 copy_size = (static_cast<u32>(CELL_PAD_LEN_CHANGE_PRESS_ON) - static_cast<u32>(CELL_PAD_BTN_OFFSET_DIGITAL1)) * sizeof(u16);
|
||||
constexpr u32 copy_size = (CELL_PAD_LEN_CHANGE_PRESS_ON - CELL_PAD_BTN_OFFSET_DIGITAL1) * sizeof(u16);
|
||||
std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_DIGITAL1], &output.button[CELL_PAD_BTN_OFFSET_DIGITAL1], copy_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr u32 copy_size = (static_cast<u32>(CELL_PAD_LEN_CHANGE_DEFAULT) - static_cast<u32>(CELL_PAD_BTN_OFFSET_DIGITAL1)) * sizeof(u16);
|
||||
constexpr u32 copy_size = (CELL_PAD_LEN_CHANGE_DEFAULT - CELL_PAD_BTN_OFFSET_DIGITAL1) * sizeof(u16);
|
||||
std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_DIGITAL1], &output.button[CELL_PAD_BTN_OFFSET_DIGITAL1], copy_size);
|
||||
|
||||
// Clear area if setting is not used
|
||||
|
|
@ -590,7 +590,7 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
|
|||
|
||||
if (data->len == CELL_PAD_LEN_CHANGE_SENSOR_ON)
|
||||
{
|
||||
constexpr u32 copy_size = (static_cast<u32>(CELL_PAD_LEN_CHANGE_SENSOR_ON) - static_cast<u32>(CELL_PAD_BTN_OFFSET_SENSOR_X)) * sizeof(u16);
|
||||
constexpr u32 copy_size = (CELL_PAD_LEN_CHANGE_SENSOR_ON - CELL_PAD_BTN_OFFSET_SENSOR_X) * sizeof(u16);
|
||||
std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_SENSOR_X], &output.button[CELL_PAD_BTN_OFFSET_SENSOR_X], copy_size);
|
||||
}
|
||||
}
|
||||
|
|
@ -1051,15 +1051,7 @@ error_code cellPadSetPortSetting(u32 port_no, u32 port_setting)
|
|||
if (port_no >= CELL_PAD_MAX_PORT_NUM)
|
||||
return CELL_OK;
|
||||
|
||||
if (port_setting & CELL_PAD_SETTING_PRESS_ON)
|
||||
config.port_setting[port_no] |= CELL_PAD_SETTING_PRESS_ON;
|
||||
else
|
||||
config.port_setting[port_no] &= ~CELL_PAD_SETTING_PRESS_ON;
|
||||
|
||||
if (port_setting & CELL_PAD_SETTING_SENSOR_ON)
|
||||
config.port_setting[port_no] |= CELL_PAD_SETTING_SENSOR_ON;
|
||||
else
|
||||
config.port_setting[port_no] &= ~CELL_PAD_SETTING_SENSOR_ON;
|
||||
config.port_setting[port_no] = port_setting;
|
||||
|
||||
// can also return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD <- Update: seems to be just internal and ignored
|
||||
|
||||
|
|
@ -1131,7 +1123,7 @@ error_code cellPadSetPressMode(u32 port_no, u32 mode)
|
|||
if (!config.max_connect)
|
||||
return CELL_PAD_ERROR_UNINITIALIZED;
|
||||
|
||||
if (port_no >= CELL_MAX_PADS || mode > 1)
|
||||
if (port_no >= CELL_PAD_MAX_PORT_NUM)
|
||||
return CELL_PAD_ERROR_INVALID_PARAMETER;
|
||||
|
||||
// CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
|
||||
|
|
@ -1165,7 +1157,7 @@ error_code cellPadSetSensorMode(u32 port_no, u32 mode)
|
|||
if (!config.max_connect)
|
||||
return CELL_PAD_ERROR_UNINITIALIZED;
|
||||
|
||||
if (port_no >= CELL_MAX_PADS || mode > 1)
|
||||
if (port_no >= CELL_MAX_PADS)
|
||||
return CELL_PAD_ERROR_INVALID_PARAMETER;
|
||||
|
||||
// CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ static error_code display_callback_result_error_message(ppu_thread& ppu, const C
|
|||
switch (result.result)
|
||||
{
|
||||
case CELL_SAVEDATA_CBRESULT_ERR_NOSPACE:
|
||||
msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_NO_SPACE, "%d", result.errNeedSizeKB);
|
||||
msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_NO_SPACE, fmt::format("%d", result.errNeedSizeKB).c_str());
|
||||
break;
|
||||
case CELL_SAVEDATA_CBRESULT_ERR_FAILURE:
|
||||
msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_FAILURE);
|
||||
|
|
|
|||
|
|
@ -1230,7 +1230,7 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 revision,
|
|||
if (flags & SAF_UNKNOWN_FLAG_9) spuTgAttr->type |= 0x0800;
|
||||
if (flags & SAF_SYSTEM_WORKLOAD_ENABLED) spuTgAttr->type |= SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM;
|
||||
|
||||
if (s32 rc = sys_spu_thread_group_create(ppu, spurs.ptr(&CellSpurs::spuTG), nSpus, spuPriority, vm::unsafe_ptr_cast<reduced_sys_spu_thread_group_attribute>(spuTgAttr)))
|
||||
if (s32 rc = sys_spu_thread_group_create(ppu, spurs.ptr(&CellSpurs::spuTG), nSpus, spuPriority, spuTgAttr))
|
||||
{
|
||||
ppu_execute<&sys_spu_image_close>(ppu, spurs.ptr(&CellSpurs::spuImg));
|
||||
return rollback(), rc;
|
||||
|
|
|
|||
|
|
@ -3198,7 +3198,7 @@ error_code sceNpLookupTerm()
|
|||
|
||||
error_code sceNpLookupCreateTitleCtx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpId> selfNpId)
|
||||
{
|
||||
sceNp.warning("sceNpLookupCreateTitleCtx(communicationId=*0x%x(%s), selfNpId=0x%x)", communicationId, communicationId ? std::string_view(communicationId->data, 9) : "", selfNpId);
|
||||
sceNp.warning("sceNpLookupCreateTitleCtx(communicationId=*0x%x(%s), selfNpId=0x%x)", communicationId, communicationId ? communicationId->data : "", selfNpId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
|
|
@ -3930,8 +3930,8 @@ error_code sceNpManagerGetMyLanguages(vm::ptr<SceNpMyLanguages> myLanguages)
|
|||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
myLanguages->language1 = g_cfg.sys.language;
|
||||
myLanguages->language2 = g_cfg.sys.language != CELL_SYSUTIL_LANG_ENGLISH_US ? CELL_SYSUTIL_LANG_ENGLISH_US : -1;
|
||||
myLanguages->language1 = SCE_NP_LANG_ENGLISH_US;
|
||||
myLanguages->language2 = g_cfg.sys.language != CELL_SYSUTIL_LANG_ENGLISH_US ? g_cfg.sys.language : -1;
|
||||
myLanguages->language3 = -1;
|
||||
|
||||
return CELL_OK;
|
||||
|
|
@ -3968,7 +3968,7 @@ error_code sceNpManagerGetAccountRegion(vm::ptr<SceNpCountryCode> countryCode, v
|
|||
ensure(ccode.size() == sizeof(SceNpCountryCode::data));
|
||||
std::memcpy(countryCode->data, ccode.data(), sizeof(SceNpCountryCode::data));
|
||||
|
||||
*language = g_cfg.sys.language;
|
||||
*language = CELL_SYSUTIL_LANG_ENGLISH_US;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
@ -6962,7 +6962,7 @@ error_code sceNpSignalingGetConnectionFromPeerAddress(u32 ctx_id, np_in_addr_t p
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetInfoDeprecated> info)
|
||||
error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetInfo> info)
|
||||
{
|
||||
sceNp.warning("sceNpSignalingGetLocalNetInfo(ctx_id=%d, info=*0x%x)", ctx_id, info);
|
||||
|
||||
|
|
@ -6973,8 +6973,7 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetIn
|
|||
return SCE_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Library has backward support for a version of SceNpSignalingNetInfo without npport
|
||||
if (!info || (info->size != sizeof(SceNpSignalingNetInfo) && info->size != sizeof(SceNpSignalingNetInfoDeprecated)))
|
||||
if (!info || info->size != sizeof(SceNpSignalingNetInfo))
|
||||
{
|
||||
return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
|
@ -6986,12 +6985,7 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetIn
|
|||
info->nat_status = SCE_NP_SIGNALING_NETINFO_NAT_STATUS_TYPE2;
|
||||
info->upnp_status = nph.get_upnp_status();
|
||||
info->npport_status = SCE_NP_SIGNALING_NETINFO_NPPORT_STATUS_OPEN;
|
||||
|
||||
if (info->size == sizeof(SceNpSignalingNetInfo))
|
||||
{
|
||||
auto new_info = vm::unsafe_ptr_cast<SceNpSignalingNetInfo>(info);
|
||||
new_info->npport = SCE_NP_PORT;
|
||||
}
|
||||
info->npport = SCE_NP_PORT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1584,16 +1584,6 @@ struct SceNpSignalingNetInfo
|
|||
be_t<u16> npport;
|
||||
};
|
||||
|
||||
struct SceNpSignalingNetInfoDeprecated
|
||||
{
|
||||
be_t<u32> size;
|
||||
be_t<u32> local_addr; // in_addr
|
||||
be_t<u32> mapped_addr; // in_addr
|
||||
be_t<s32> nat_status;
|
||||
be_t<s32> upnp_status;
|
||||
be_t<s32> npport_status;
|
||||
};
|
||||
|
||||
struct SceNpCustomMenuAction
|
||||
{
|
||||
be_t<u32> options;
|
||||
|
|
|
|||
|
|
@ -1300,7 +1300,7 @@ error_code sceNpMatching2GrantRoomOwner(
|
|||
error_code sceNpMatching2CreateContext(
|
||||
vm::cptr<SceNpId> npId, vm::cptr<SceNpCommunicationId> commId, vm::cptr<SceNpCommunicationPassphrase> passPhrase, vm::ptr<SceNpMatching2ContextId> ctxId, s32 option)
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? std::string_view(commId->data, 9) : "", passPhrase, ctxId, option);
|
||||
sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? commId->data : "", passPhrase, ctxId, option);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "util/types.hpp"
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ std::pair<PPUDisAsm::const_op, u64> PPUDisAsm::try_get_const_op_gpr_value(u32 re
|
|||
|
||||
GET_CONST_REG(reg_rs, op.rs);
|
||||
|
||||
return {form, std::rotl<u64>(reg_rs, op.sh64) & (~0ull << (op.mbe64 ^ 63))};
|
||||
return { form, utils::rol64(reg_rs, op.sh64) & (~0ull << (op.mbe64 ^ 63)) };
|
||||
}
|
||||
case ppu_itype::OR:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3483,7 +3483,7 @@ auto RLWIMI()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
||||
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (dup32(std::rotl<u32>(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & mask);
|
||||
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (dup32(utils::rol32(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & mask);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3497,7 +3497,7 @@ auto RLWINM()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = dup32(std::rotl<u32>(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
||||
ppu.gpr[op.ra] = dup32(utils::rol32(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3511,7 +3511,7 @@ auto RLWNM()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = dup32(std::rotl<u32>(static_cast<u32>(ppu.gpr[op.rs]), ppu.gpr[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
||||
ppu.gpr[op.ra] = dup32(utils::rol32(static_cast<u32>(ppu.gpr[op.rs]), ppu.gpr[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3599,7 +3599,7 @@ auto RLDICL()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & (~0ull >> op.mbe64);
|
||||
ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], op.sh64) & (~0ull >> op.mbe64);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3613,7 +3613,7 @@ auto RLDICR()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63));
|
||||
ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63));
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3627,7 +3627,7 @@ auto RLDIC()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
|
||||
ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3642,7 +3642,7 @@ auto RLDIMI()
|
|||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
|
||||
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & mask);
|
||||
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (utils::rol64(ppu.gpr[op.rs], op.sh64) & mask);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3656,7 +3656,7 @@ auto RLDCL()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull >> op.mbe64);
|
||||
ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull >> op.mbe64);
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
@ -3670,7 +3670,7 @@ auto RLDCR()
|
|||
return ppu_exec_select<Flags...>::template select<>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63));
|
||||
ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63));
|
||||
if constexpr (((Flags == has_rc) || ...))
|
||||
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -832,9 +832,6 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr =
|
|||
return;
|
||||
}
|
||||
|
||||
size = utils::align<u32>(size + addr % 4, 4);
|
||||
addr &= -4;
|
||||
|
||||
// Initialize interpreter cache
|
||||
while (size)
|
||||
{
|
||||
|
|
@ -2311,7 +2308,7 @@ void ppu_thread::cpu_sleep()
|
|||
raddr = 0;
|
||||
|
||||
// Setup wait flag and memory flags to relock itself
|
||||
state += cpu_flag::wait + cpu_flag::memory;
|
||||
state += g_use_rtm ? cpu_flag::wait : cpu_flag::wait + cpu_flag::memory;
|
||||
|
||||
if (auto ptr = vm::g_tls_locked)
|
||||
{
|
||||
|
|
@ -2457,8 +2454,10 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
|
|||
// Trigger the scheduler
|
||||
state += cpu_flag::suspend;
|
||||
|
||||
// Acquire memory passive lock
|
||||
state += cpu_flag::memory;
|
||||
if (!g_use_rtm)
|
||||
{
|
||||
state += cpu_flag::memory;
|
||||
}
|
||||
|
||||
call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1);
|
||||
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
|
||||
|
|
@ -2704,7 +2703,11 @@ ppu_thread::ppu_thread(utils::serial& ar)
|
|||
|
||||
// Trigger the scheduler
|
||||
state += cpu_flag::suspend;
|
||||
state += cpu_flag::memory;
|
||||
|
||||
if (!g_use_rtm)
|
||||
{
|
||||
state += cpu_flag::memory;
|
||||
}
|
||||
|
||||
ppu_tname = make_single<std::string>(ar.pop<std::string>());
|
||||
|
||||
|
|
@ -3188,6 +3191,221 @@ extern u64 ppu_ldarx(ppu_thread& ppu, u32 addr)
|
|||
return ppu_load_acquire_reservation<u64>(ppu, addr);
|
||||
}
|
||||
|
||||
const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, const void* _old, u64 _new)>("ppu_stcx_accurate_tx", [](native_asm& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
Label fall = c.newLabel();
|
||||
Label fail = c.newLabel();
|
||||
Label _ret = c.newLabel();
|
||||
Label load = c.newLabel();
|
||||
|
||||
//if (utils::has_avx() && !s_tsx_avx)
|
||||
//{
|
||||
// c.vzeroupper();
|
||||
//}
|
||||
|
||||
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
|
||||
c.push(x86::rbp);
|
||||
c.push(x86::r13);
|
||||
c.push(x86::r14);
|
||||
c.sub(x86::rsp, 48);
|
||||
#ifdef _WIN32
|
||||
if (!s_tsx_avx)
|
||||
{
|
||||
c.movups(x86::oword_ptr(x86::rsp, 0), x86::xmm6);
|
||||
c.movups(x86::oword_ptr(x86::rsp, 16), x86::xmm7);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Prepare registers
|
||||
build_swap_rdx_with(c, args, x86::r10);
|
||||
c.movabs(x86::rbp, reinterpret_cast<u64>(&vm::g_sudo_addr));
|
||||
c.mov(x86::rbp, x86::qword_ptr(x86::rbp));
|
||||
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
|
||||
c.and_(x86::rbp, -128);
|
||||
c.prefetchw(x86::byte_ptr(x86::rbp, 0));
|
||||
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
|
||||
c.movzx(args[0].r32(), args[0].r16());
|
||||
c.shr(args[0].r32(), 1);
|
||||
c.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
|
||||
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
|
||||
c.and_(x86::r11, -128 / 2);
|
||||
c.and_(args[0].r32(), 63);
|
||||
|
||||
// Prepare data
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovups(x86::ymm0, x86::ymmword_ptr(args[2], 0));
|
||||
c.vmovups(x86::ymm1, x86::ymmword_ptr(args[2], 32));
|
||||
c.vmovups(x86::ymm2, x86::ymmword_ptr(args[2], 64));
|
||||
c.vmovups(x86::ymm3, x86::ymmword_ptr(args[2], 96));
|
||||
}
|
||||
else
|
||||
{
|
||||
c.movaps(x86::xmm0, x86::oword_ptr(args[2], 0));
|
||||
c.movaps(x86::xmm1, x86::oword_ptr(args[2], 16));
|
||||
c.movaps(x86::xmm2, x86::oword_ptr(args[2], 32));
|
||||
c.movaps(x86::xmm3, x86::oword_ptr(args[2], 48));
|
||||
c.movaps(x86::xmm4, x86::oword_ptr(args[2], 64));
|
||||
c.movaps(x86::xmm5, x86::oword_ptr(args[2], 80));
|
||||
c.movaps(x86::xmm6, x86::oword_ptr(args[2], 96));
|
||||
c.movaps(x86::xmm7, x86::oword_ptr(args[2], 112));
|
||||
}
|
||||
|
||||
// Alloc r14 to stamp0
|
||||
const auto stamp0 = x86::r14;
|
||||
build_get_tsc(c, stamp0);
|
||||
|
||||
Label fail2 = c.newLabel();
|
||||
|
||||
Label tx1 = build_transaction_enter(c, fall, [&]()
|
||||
{
|
||||
build_get_tsc(c);
|
||||
c.sub(x86::rax, stamp0);
|
||||
c.movabs(x86::r13, reinterpret_cast<u64>(&g_rtm_tx_limit2));
|
||||
c.cmp(x86::rax, x86::qword_ptr(x86::r13));
|
||||
c.jae(fall);
|
||||
});
|
||||
|
||||
// Check pause flag
|
||||
c.bt(x86::dword_ptr(args[2], ::offset32(&ppu_thread::state) - ::offset32(&ppu_thread::rdata)), static_cast<u32>(cpu_flag::pause));
|
||||
c.jc(fall);
|
||||
c.xbegin(tx1);
|
||||
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
|
||||
c.vxorps(x86::ymm1, x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
|
||||
c.vxorps(x86::ymm2, x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
|
||||
c.vxorps(x86::ymm3, x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
|
||||
c.vorps(x86::ymm0, x86::ymm0, x86::ymm1);
|
||||
c.vorps(x86::ymm1, x86::ymm2, x86::ymm3);
|
||||
c.vorps(x86::ymm0, x86::ymm1, x86::ymm0);
|
||||
c.vptest(x86::ymm0, x86::ymm0);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.xorps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
|
||||
c.xorps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
|
||||
c.xorps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
|
||||
c.xorps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
|
||||
c.xorps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
|
||||
c.xorps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
|
||||
c.xorps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
|
||||
c.xorps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
|
||||
c.orps(x86::xmm0, x86::xmm1);
|
||||
c.orps(x86::xmm2, x86::xmm3);
|
||||
c.orps(x86::xmm4, x86::xmm5);
|
||||
c.orps(x86::xmm6, x86::xmm7);
|
||||
c.orps(x86::xmm0, x86::xmm2);
|
||||
c.orps(x86::xmm4, x86::xmm6);
|
||||
c.orps(x86::xmm0, x86::xmm4);
|
||||
c.ptest(x86::xmm0, x86::xmm0);
|
||||
}
|
||||
|
||||
c.jnz(fail);
|
||||
|
||||
// Store 8 bytes
|
||||
c.mov(x86::qword_ptr(x86::rbp, args[0], 1, 0), args[3]);
|
||||
|
||||
c.xend();
|
||||
c.lock().add(x86::qword_ptr(x86::r11), 64);
|
||||
build_get_tsc(c);
|
||||
c.sub(x86::rax, stamp0);
|
||||
c.jmp(_ret);
|
||||
|
||||
// XABORT is expensive so try to finish with xend instead
|
||||
c.bind(fail);
|
||||
|
||||
// Load old data to store back in rdata
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovaps(x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
|
||||
c.vmovaps(x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
|
||||
c.vmovaps(x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
|
||||
c.vmovaps(x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
|
||||
}
|
||||
else
|
||||
{
|
||||
c.movaps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
|
||||
c.movaps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
|
||||
c.movaps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
|
||||
c.movaps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
|
||||
c.movaps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
|
||||
c.movaps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
|
||||
c.movaps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
|
||||
c.movaps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
|
||||
}
|
||||
|
||||
c.xend();
|
||||
c.jmp(fail2);
|
||||
|
||||
c.bind(fall);
|
||||
c.mov(x86::rax, -1);
|
||||
c.jmp(_ret);
|
||||
|
||||
c.bind(fail2);
|
||||
c.lock().sub(x86::qword_ptr(x86::r11), 64);
|
||||
c.bind(load);
|
||||
|
||||
// Store previous data back to rdata
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 0), x86::ymm0);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 32), x86::ymm1);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 64), x86::ymm2);
|
||||
c.vmovaps(x86::ymmword_ptr(args[2], 96), x86::ymm3);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.movaps(x86::oword_ptr(args[2], 0), x86::xmm0);
|
||||
c.movaps(x86::oword_ptr(args[2], 16), x86::xmm1);
|
||||
c.movaps(x86::oword_ptr(args[2], 32), x86::xmm2);
|
||||
c.movaps(x86::oword_ptr(args[2], 48), x86::xmm3);
|
||||
c.movaps(x86::oword_ptr(args[2], 64), x86::xmm4);
|
||||
c.movaps(x86::oword_ptr(args[2], 80), x86::xmm5);
|
||||
c.movaps(x86::oword_ptr(args[2], 96), x86::xmm6);
|
||||
c.movaps(x86::oword_ptr(args[2], 112), x86::xmm7);
|
||||
}
|
||||
|
||||
c.mov(x86::rax, -1);
|
||||
c.mov(x86::qword_ptr(args[2], ::offset32(&ppu_thread::last_ftime) - ::offset32(&ppu_thread::rdata)), x86::rax);
|
||||
c.xor_(x86::eax, x86::eax);
|
||||
//c.jmp(_ret);
|
||||
|
||||
c.bind(_ret);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!s_tsx_avx)
|
||||
{
|
||||
c.vmovups(x86::xmm6, x86::oword_ptr(x86::rsp, 0));
|
||||
c.vmovups(x86::xmm7, x86::oword_ptr(x86::rsp, 16));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_tsx_avx)
|
||||
{
|
||||
c.vzeroupper();
|
||||
}
|
||||
|
||||
c.add(x86::rsp, 48);
|
||||
c.pop(x86::r14);
|
||||
c.pop(x86::r13);
|
||||
c.pop(x86::rbp);
|
||||
|
||||
maybe_flush_lbr(c);
|
||||
c.ret();
|
||||
#else
|
||||
UNUSED(args);
|
||||
|
||||
// Unimplemented should fail.
|
||||
c.brk(Imm(0x42));
|
||||
c.ret(a64::x30);
|
||||
#endif
|
||||
});
|
||||
|
||||
template <typename T>
|
||||
static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
{
|
||||
|
|
@ -3268,6 +3486,77 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (g_use_rtm) [[likely]]
|
||||
{
|
||||
switch (u64 count = ppu_stcx_accurate_tx(addr & -8, rtime, ppu.rdata, std::bit_cast<u64>(new_data)))
|
||||
{
|
||||
case umax:
|
||||
{
|
||||
auto& all_data = *vm::get_super_ptr<spu_rdata_t>(addr & -128);
|
||||
auto& sdata = *vm::get_super_ptr<atomic_be_t<u64>>(addr & -8);
|
||||
|
||||
const bool ok = cpu_thread::suspend_all<+3>(&ppu, {all_data, all_data + 64, &res}, [&]
|
||||
{
|
||||
if ((res & -128) == rtime && cmp_rdata(ppu.rdata, all_data))
|
||||
{
|
||||
sdata.release(new_data);
|
||||
res += 64;
|
||||
return true;
|
||||
}
|
||||
|
||||
mov_rdata_nt(ppu.rdata, all_data);
|
||||
res -= 64;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ppu.last_ftime = -1;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
if (ppu.last_faddr == addr)
|
||||
{
|
||||
ppu.last_fail++;
|
||||
}
|
||||
|
||||
if (ppu.last_ftime != umax)
|
||||
{
|
||||
ppu.last_faddr = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
utils::prefetch_read(ppu.rdata);
|
||||
utils::prefetch_read(ppu.rdata + 64);
|
||||
ppu.last_faddr = addr;
|
||||
ppu.last_ftime = res.load() & -128;
|
||||
ppu.last_ftsc = utils::get_tsc();
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (count > 20000 && g_cfg.core.perf_report) [[unlikely]]
|
||||
{
|
||||
perf_log.warning("STCX: took too long: %.3fus (%u c)", count / (utils::get_tsc_freq() / 1000'000.), count);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppu.last_faddr == addr)
|
||||
{
|
||||
ppu.last_succ++;
|
||||
}
|
||||
|
||||
ppu.last_faddr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Align address: we do not need the lower 7 bits anymore
|
||||
addr &= -128;
|
||||
|
||||
|
|
@ -3718,7 +4007,7 @@ extern void ppu_finalize(const ppu_module<lv2_obj>& info, bool force_mem_release
|
|||
#endif
|
||||
}
|
||||
|
||||
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_modules, bool is_fast_compilation)
|
||||
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_modules)
|
||||
{
|
||||
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
|
||||
{
|
||||
|
|
@ -4166,12 +4455,6 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
|||
break;
|
||||
}
|
||||
|
||||
if (is_fast_compilation)
|
||||
{
|
||||
// Skip overlays in fast mode
|
||||
break;
|
||||
}
|
||||
|
||||
if (!wait_for_memory())
|
||||
{
|
||||
// Emulation stopped
|
||||
|
|
@ -4466,7 +4749,7 @@ extern void ppu_initialize()
|
|||
|
||||
progress_dialog.reset();
|
||||
|
||||
ppu_precompile(dir_queue, &module_list, false);
|
||||
ppu_precompile(dir_queue, &module_list);
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
|
|
@ -5520,11 +5803,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
|
|||
std::unique_ptr<Module> _module = std::make_unique<Module>(obj_name, jit.get_context());
|
||||
|
||||
// Initialize target
|
||||
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
|
||||
_module->setTargetTriple(Triple(jit_compiler::triple1()));
|
||||
#else
|
||||
_module->setTargetTriple(jit_compiler::triple1());
|
||||
#endif
|
||||
_module->setDataLayout(jit.get_engine().getTargetMachine()->createDataLayout());
|
||||
|
||||
// Initialize translator
|
||||
|
|
|
|||
|
|
@ -416,6 +416,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
|
|||
assert(ptr_inst->getResultElementType() == m_ir->getPtrTy());
|
||||
|
||||
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
|
||||
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
|
||||
const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc;
|
||||
const auto pos = m_ir->CreateShl(pos_32, 1);
|
||||
const auto ptr = m_ir->CreatePtrAdd(m_exec, pos);
|
||||
|
|
@ -426,7 +427,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
|
|||
const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>());
|
||||
|
||||
// Store to jumptable
|
||||
m_ir->CreateStore(faddr, ptr);
|
||||
m_ir->CreateStore(faddr_int, ptr);
|
||||
m_ir->CreateStore(seg_val, seg_ptr);
|
||||
|
||||
// Increment index and branch back to loop
|
||||
|
|
@ -592,11 +593,6 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
|
|||
{
|
||||
callee = m_module->getOrInsertFunction(fmt::format("__0x%x", target_last - base), type);
|
||||
cast<Function>(callee.getCallee())->setCallingConv(CallingConv::GHC);
|
||||
|
||||
if (g_cfg.core.ppu_prof)
|
||||
{
|
||||
m_ir->CreateStore(GetAddr(target_last - m_addr), m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast<uint>(&m_cia - m_locals)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1119,24 +1115,7 @@ void PPUTranslator::VCFSX(ppu_opcode_t op)
|
|||
void PPUTranslator::VCFUX(ppu_opcode_t op)
|
||||
{
|
||||
const auto b = get_vr<u32[4]>(op.vb);
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
return set_vr(op.vd, fpcast<f32[4]>(b) * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
|
||||
#else
|
||||
if (m_use_avx512)
|
||||
{
|
||||
return set_vr(op.vd, fpcast<f32[4]>(b) * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
|
||||
}
|
||||
|
||||
constexpr int bit_shift = 9;
|
||||
const auto shifted = (b >> bit_shift);
|
||||
const auto cleared = shifted << bit_shift;
|
||||
const auto low_bits = b - cleared;
|
||||
const auto high_part = fpcast<f32[4]>(noncast<s32[4]>(shifted)) * fsplat<f32[4]>(static_cast<f32>(1u << bit_shift));
|
||||
const auto low_part = fpcast<f32[4]>(noncast<s32[4]>(low_bits));
|
||||
const auto temp = high_part + low_part;
|
||||
set_vr(op.vd, temp * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
|
||||
#endif
|
||||
set_vr(op.vd, fpcast<f32[4]>(b) * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
|
||||
}
|
||||
|
||||
void PPUTranslator::VCMPBFP(ppu_opcode_t op)
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
|||
c->cmp(SPU_OFF_32(state), 0);
|
||||
c->jnz(label_stop);
|
||||
|
||||
if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification)
|
||||
if (g_cfg.core.spu_prof && g_cfg.core.spu_verification)
|
||||
{
|
||||
c->mov(x86::rax, m_hash_start & -0xffff);
|
||||
c->mov(SPU_OFF_64(block_hash), x86::rax);
|
||||
|
|
@ -755,7 +755,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
|
|||
c->add(SPU_OFF_64(block_counter), ::size32(words) / (words_align / 4));
|
||||
|
||||
// Set block hash for profiling (if enabled)
|
||||
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
|
||||
if (g_cfg.core.spu_prof)
|
||||
{
|
||||
c->mov(x86::rax, m_hash_start | 0xffff);
|
||||
c->mov(SPU_OFF_64(block_hash), x86::rax);
|
||||
|
|
@ -1199,7 +1199,7 @@ void spu_recompiler::branch_set_link(u32 target)
|
|||
c->movdqa(x86::dqword_ptr(*cpu, *qw1, 0, ::offset32(&spu_thread::stack_mirror)), x86::xmm0);
|
||||
|
||||
// Set block hash for profiling (if enabled)
|
||||
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
|
||||
if (g_cfg.core.spu_prof)
|
||||
{
|
||||
c->mov(x86::rax, m_hash_start | 0xffff);
|
||||
c->mov(SPU_OFF_64(block_hash), x86::rax);
|
||||
|
|
@ -3212,7 +3212,7 @@ void spu_recompiler::ROTQBYI(spu_opcode_t op)
|
|||
}
|
||||
else if (s == 4 || s == 8 || s == 12)
|
||||
{
|
||||
c->pshufd(va, va, std::rotl<u8>(0xE4, s / 2));
|
||||
c->pshufd(va, va, utils::rol8(0xE4, s / 2));
|
||||
}
|
||||
else if (utils::has_ssse3())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,9 +38,26 @@ constexpr u32 s_reg_max = spu_recompiler_base::s_reg_max;
|
|||
template<typename T>
|
||||
struct span_less
|
||||
{
|
||||
static auto compare(const std::span<T>& lhs, const std::span<T>& rhs) noexcept
|
||||
static int compare(const std::span<T>& lhs, const std::span<T>& rhs) noexcept
|
||||
{
|
||||
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
// TODO: Replace with std::lexicographical_compare_three_way when it becomes available to all compilers
|
||||
for (usz i = 0, last = std::min(lhs.size(), rhs.size()); i != last; i++)
|
||||
{
|
||||
const T vl = lhs[i];
|
||||
const T vr = rhs[i];
|
||||
|
||||
if (vl != vr)
|
||||
{
|
||||
return vl < vr ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lhs.size() != rhs.size())
|
||||
{
|
||||
return lhs.size() < rhs.size() ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator()(const std::span<T>& lhs, const std::span<T>& rhs) const noexcept
|
||||
|
|
@ -720,19 +737,9 @@ void spu_cache::initialize(bool build_existing_cache)
|
|||
}
|
||||
|
||||
// SPU cache file (version + block size type)
|
||||
const std::string filename = "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
|
||||
const std::string loc = ppu_cache + filename;
|
||||
const std::string loc_debug = fs::get_cache_dir() + "DEBUG/" + filename;
|
||||
const std::string loc = ppu_cache + "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
|
||||
|
||||
bool is_debug = false;
|
||||
|
||||
if (fs::is_file(loc_debug))
|
||||
{
|
||||
spu_log.success("SPU Cache override applied!");
|
||||
is_debug = true;
|
||||
}
|
||||
|
||||
spu_cache cache(is_debug ? loc_debug : loc);
|
||||
spu_cache cache(loc);
|
||||
|
||||
if (!cache)
|
||||
{
|
||||
|
|
@ -1302,7 +1309,7 @@ bool spu_program::operator<(const spu_program& rhs) const noexcept
|
|||
std::span<const u32> lhs_data(data.data() + lhs_offs, data.size() - lhs_offs);
|
||||
std::span<const u32> rhs_data(rhs.data.data() + rhs_offs, rhs.data.size() - rhs_offs);
|
||||
|
||||
const auto cmp0 = span_less<const u32>::compare(lhs_data, rhs_data);
|
||||
const int cmp0 = span_less<const u32>::compare(lhs_data, rhs_data);
|
||||
|
||||
if (cmp0 < 0)
|
||||
return true;
|
||||
|
|
@ -1313,7 +1320,7 @@ bool spu_program::operator<(const spu_program& rhs) const noexcept
|
|||
lhs_data = {data.data(), lhs_offs};
|
||||
rhs_data = {rhs.data.data(), rhs_offs};
|
||||
|
||||
const auto cmp1 = span_less<const u32>::compare(lhs_data, rhs_data);
|
||||
const int cmp1 = span_less<const u32>::compare(lhs_data, rhs_data);
|
||||
|
||||
if (cmp1 < 0)
|
||||
return true;
|
||||
|
|
@ -2326,7 +2333,7 @@ std::vector<u32> spu_thread::discover_functions(u32 base_addr, std::span<const u
|
|||
// Search for BRSL LR and BRASL LR or BR
|
||||
// TODO: BISL
|
||||
const v128 inst = read_from_ptr<be_t<v128>>(ls.data(), i - base_addr);
|
||||
const v128 cleared_i16 = gv_and32(inst, v128::from32p(std::rotl<u32>(~0xffff, 7)));
|
||||
const v128 cleared_i16 = gv_and32(inst, v128::from32p(utils::rol32(~0xffff, 7)));
|
||||
const v128 eq_brsl = gv_eq32(cleared_i16, v128::from32p(0x66u << 23));
|
||||
const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask);
|
||||
const v128 eq_br = gv_eq32(cleared_i16, v128::from32p(0x64u << 23));
|
||||
|
|
@ -3079,39 +3086,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
values[op.rt] = pos + 4;
|
||||
}
|
||||
|
||||
const u32 pos_next = wa;
|
||||
|
||||
bool is_no_return = false;
|
||||
|
||||
if (pos_next >= lsa && pos_next < limit)
|
||||
{
|
||||
const u32 data_next = ls[pos_next / 4];
|
||||
const auto type_next = g_spu_itype.decode(data_next);
|
||||
const auto flag_next = g_spu_iflag.decode(data_next);
|
||||
const auto op_next = spu_opcode_t{data_next};
|
||||
|
||||
if (!(type_next & spu_itype::zregmod) && !(type_next & spu_itype::branch))
|
||||
{
|
||||
if (auto iflags = g_spu_iflag.decode(data_next))
|
||||
{
|
||||
if (+flag_next & +spu_iflag::use_ra)
|
||||
{
|
||||
is_no_return = is_no_return || (op_next.ra >= 4 && op_next.ra < 10);
|
||||
}
|
||||
|
||||
if (+flag_next & +spu_iflag::use_rb)
|
||||
{
|
||||
is_no_return = is_no_return || (op_next.rb >= 4 && op_next.rb < 10);
|
||||
}
|
||||
|
||||
if (type_next & spu_itype::_quadrop && +iflags & +spu_iflag::use_rc)
|
||||
{
|
||||
is_no_return = is_no_return || (op_next.ra >= 4 && op_next.rb < 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (af & vf::is_const)
|
||||
{
|
||||
const u32 target = spu_branch_target(av);
|
||||
|
|
@ -3148,7 +3122,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
limit = std::min<u32>(limit, target);
|
||||
}
|
||||
|
||||
if (!is_no_return && sl && g_cfg.core.spu_block_size != spu_block_size_type::safe)
|
||||
if (sl && g_cfg.core.spu_block_size != spu_block_size_type::safe)
|
||||
{
|
||||
m_ret_info[pos / 4 + 1] = true;
|
||||
m_entry_info[pos / 4 + 1] = true;
|
||||
|
|
@ -3165,7 +3139,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
u64 dabs = 0;
|
||||
u64 drel = 0;
|
||||
|
||||
for (u32 i = start, abs_fail = 0, rel_fail = 0; i < limit; i += 4)
|
||||
for (u32 i = start; i < limit; i += 4)
|
||||
{
|
||||
const u32 target = ls[i / 4];
|
||||
|
||||
|
|
@ -3175,39 +3149,16 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
break;
|
||||
}
|
||||
|
||||
if (target >= SPU_LS_SIZE && target <= 0u - SPU_LS_SIZE)
|
||||
{
|
||||
if (g_spu_itype.decode(target) != spu_itype::UNK)
|
||||
{
|
||||
// End of jumptable: valid instruction
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target >= lsa && target < SPU_LS_SIZE)
|
||||
{
|
||||
// Possible jump table entry (absolute)
|
||||
if (!abs_fail)
|
||||
{
|
||||
jt_abs.push_back(target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_fail++;
|
||||
jt_abs.push_back(target);
|
||||
}
|
||||
|
||||
if (target + start >= lsa && target + start < SPU_LS_SIZE)
|
||||
{
|
||||
// Possible jump table entry (relative)
|
||||
if (!rel_fail)
|
||||
{
|
||||
jt_rel.push_back(target + start);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rel_fail++;
|
||||
jt_rel.push_back(target + start);
|
||||
}
|
||||
|
||||
if (std::max(jt_abs.size(), jt_rel.size()) * 4 + start <= i)
|
||||
|
|
@ -3219,35 +3170,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
}
|
||||
}
|
||||
|
||||
for (usz i = 0; i < jt_abs.size(); i++)
|
||||
{
|
||||
if (jt_abs[i] == start + jt_abs.size() * 4)
|
||||
{
|
||||
// If jumptable contains absolute address of code start after the jumptable itself
|
||||
// It is likely an absolute-type jumptable
|
||||
|
||||
bool is_good_conclusion = true;
|
||||
|
||||
// For verification: make sure there is none like this in relative table
|
||||
|
||||
for (u32 target : jt_rel)
|
||||
{
|
||||
if (target == start + jt_rel.size() * 4)
|
||||
{
|
||||
is_good_conclusion = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_good_conclusion)
|
||||
{
|
||||
jt_rel.clear();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Choose position after the jt as an anchor and compute the average distance
|
||||
for (u32 target : jt_abs)
|
||||
{
|
||||
|
|
@ -3346,9 +3268,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
spu_log.notice("[0x%x] At 0x%x: ignoring indirect branch (SYNC)", entry_point, pos);
|
||||
}
|
||||
|
||||
if (type == spu_itype::BI || sl || is_no_return)
|
||||
if (type == spu_itype::BI || sl)
|
||||
{
|
||||
if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe || is_no_return)
|
||||
if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe)
|
||||
{
|
||||
m_targets[pos];
|
||||
}
|
||||
|
|
@ -3385,42 +3307,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
break;
|
||||
}
|
||||
|
||||
const u32 pos_next = wa;
|
||||
|
||||
bool is_no_return = false;
|
||||
|
||||
if (pos_next >= lsa && pos_next < limit)
|
||||
{
|
||||
const u32 data_next = ls[pos_next / 4];
|
||||
const auto type_next = g_spu_itype.decode(data_next);
|
||||
const auto flag_next = g_spu_iflag.decode(data_next);
|
||||
const auto op_next = spu_opcode_t{data_next};
|
||||
|
||||
if (!(type_next & spu_itype::zregmod) && !(type_next & spu_itype::branch))
|
||||
{
|
||||
if (auto iflags = g_spu_iflag.decode(data_next))
|
||||
{
|
||||
if (+flag_next & +spu_iflag::use_ra)
|
||||
{
|
||||
is_no_return = is_no_return || (op_next.ra >= 4 && op_next.ra < 10);
|
||||
}
|
||||
|
||||
if (+flag_next & +spu_iflag::use_rb)
|
||||
{
|
||||
is_no_return = is_no_return || (op_next.rb >= 4 && op_next.rb < 10);
|
||||
}
|
||||
|
||||
if (type_next & spu_itype::_quadrop && +iflags & +spu_iflag::use_rc)
|
||||
{
|
||||
is_no_return = is_no_return || (op_next.rc >= 4 && op_next.rc < 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_targets[pos].push_back(target);
|
||||
|
||||
if (!is_no_return && g_cfg.core.spu_block_size != spu_block_size_type::safe)
|
||||
if (g_cfg.core.spu_block_size != spu_block_size_type::safe)
|
||||
{
|
||||
m_ret_info[pos / 4 + 1] = true;
|
||||
m_entry_info[pos / 4 + 1] = true;
|
||||
|
|
@ -3428,7 +3317,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
add_block(pos + 4);
|
||||
}
|
||||
|
||||
if (!is_no_return && g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync)
|
||||
if (g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync)
|
||||
{
|
||||
m_entry_info[target / 4] = true;
|
||||
add_block(target);
|
||||
|
|
@ -4973,7 +4862,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
u32 lsa_last_pc = SPU_LS_SIZE; // PC of first LSA write
|
||||
u32 get_pc = SPU_LS_SIZE; // PC of GETLLAR
|
||||
u32 put_pc = SPU_LS_SIZE; // PC of PUTLLC
|
||||
u32 rdatomic_pc = SPU_LS_SIZE; // PC of last RdAtomcStat read
|
||||
reg_state_t ls{}; // state of LS load/store address register
|
||||
reg_state_t ls_offs = reg_state_t::from_value(0); // Added value to ls
|
||||
reg_state_t lsa{}; // state of LSA register on GETLLAR
|
||||
|
|
@ -4989,27 +4877,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
bool select_16_or_0_at_runtime = false;
|
||||
bool put_active = false; // PUTLLC happened
|
||||
bool get_rdatomic = false; // True if MFC_RdAtomicStat was read after GETLLAR
|
||||
u32 required_pc = SPU_LS_SIZE; // Require program to be location specific for this optimization (SPU_LS_SIZE - no requirement)
|
||||
u32 mem_count = 0;
|
||||
u32 break_cause = 100;
|
||||
u32 break_pc = SPU_LS_SIZE;
|
||||
|
||||
// Return old state for error reporting
|
||||
atomic16_t discard()
|
||||
{
|
||||
const u32 pc = lsa_pc;
|
||||
const u32 last_pc = lsa_last_pc;
|
||||
const u32 cause = break_cause;
|
||||
const u32 break_pos = break_pc;
|
||||
|
||||
const atomic16_t old = *this;
|
||||
*this = atomic16_t{};
|
||||
|
||||
// Keep some members
|
||||
this->lsa_pc = pc;
|
||||
this->lsa_last_pc = last_pc;
|
||||
this->break_cause = cause;
|
||||
this->break_pc = break_pos;
|
||||
lsa_pc = pc;
|
||||
lsa_last_pc = last_pc;
|
||||
return old;
|
||||
}
|
||||
|
||||
|
|
@ -5019,7 +4900,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
ls_invalid = true;
|
||||
ls_write |= write;
|
||||
|
||||
if (ls_write)
|
||||
if (write)
|
||||
{
|
||||
return discard();
|
||||
}
|
||||
|
|
@ -5216,17 +5097,15 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
{
|
||||
if (previous.active && likely_putllc_loop && getllar_starts.contains(previous.lsa_pc))
|
||||
{
|
||||
had_putllc_evaluation = true;
|
||||
const bool is_first = !std::exchange(getllar_starts[previous.lsa_pc], true);
|
||||
|
||||
if (cause != 24)
|
||||
if (!is_first)
|
||||
{
|
||||
atomic16->break_cause = cause;
|
||||
atomic16->break_pc = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
cause = atomic16->break_cause;
|
||||
getllar_starts[previous.lsa_pc] = true;
|
||||
had_putllc_evaluation = true;
|
||||
|
||||
g_fxo->get<putllc16_statistics_t>().breaking_reason[cause]++;
|
||||
|
||||
if (!spu_log.notice)
|
||||
|
|
@ -5234,7 +5113,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
return;
|
||||
}
|
||||
|
||||
std::string break_error = fmt::format("PUTLLC pattern breakage [%x mem=%d lsa_const=%d cause=%u] (lsa_pc=0x%x)", atomic16->break_pc, previous.mem_count, u32{!previous.ls_offs.is_const()} * 2 + previous.lsa.is_const(), cause, previous.lsa_pc);
|
||||
std::string break_error = fmt::format("PUTLLC pattern breakage [%x mem=%d lsa_const=%d cause=%u] (lsa_pc=0x%x)", pos, previous.mem_count, u32{!previous.ls_offs.is_const()} * 2 + previous.lsa.is_const(), cause, previous.lsa_pc);
|
||||
|
||||
const auto values = sort_breakig_reasons(g_fxo->get<putllc16_statistics_t>().breaking_reason);
|
||||
|
||||
|
|
@ -5517,7 +5396,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
const usz block_tail = duplicate_positions[it_begin - it_tail];
|
||||
|
||||
// Check if the distance is precisely two times from the end
|
||||
if (reg_state_it.size() - block_start != std::rotl<u64>(reg_state_it.size() - block_tail, 1))
|
||||
if (reg_state_it.size() - block_start != utils::rol64(reg_state_it.size() - block_tail, 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -6334,8 +6213,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
break;
|
||||
}
|
||||
|
||||
atomic16->rdatomic_pc = pos;
|
||||
|
||||
const auto it = atomic16_all.find(pos);
|
||||
|
||||
if (it == atomic16_all.end())
|
||||
|
|
@ -6398,7 +6275,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
existing.ls_invalid |= atomic16->ls_invalid;
|
||||
existing.ls_access |= atomic16->ls_access;
|
||||
existing.mem_count = std::max<u32>(existing.mem_count, atomic16->mem_count);
|
||||
existing.required_pc = std::min<u32>(existing.required_pc, atomic16->required_pc);
|
||||
existing.select_16_or_0_at_runtime |= atomic16->select_16_or_0_at_runtime;
|
||||
}
|
||||
|
||||
|
|
@ -6413,24 +6289,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
invalidate = false;
|
||||
}
|
||||
}
|
||||
else if (atomic16->break_cause != 100 && atomic16->lsa_pc != SPU_LS_SIZE)
|
||||
{
|
||||
const auto it = atomic16_all.find(pos);
|
||||
|
||||
if (it == atomic16_all.end())
|
||||
{
|
||||
// Ensure future failure
|
||||
atomic16_all.emplace(pos, *atomic16);
|
||||
break_putllc16(24, FN(x.active = true, x)(as_rvalue(*atomic16)));
|
||||
}
|
||||
else if (it->second.active && atomic16->break_cause != 100)
|
||||
{
|
||||
it->second = *atomic16;
|
||||
break_putllc16(24, FN(x.active = true, x)(as_rvalue(*atomic16)));
|
||||
}
|
||||
|
||||
atomic16->break_cause = 100;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -6501,10 +6359,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
|
||||
// Do not clear lower 16 bytes addressing because the program can move on 4-byte basis
|
||||
const u32 offs = spu_branch_target(pos - result.lower_bound, op.si16);
|
||||
const u32 true_offs = spu_branch_target(pos, op.si16);
|
||||
|
||||
// Make this optimization depend on the location of the program
|
||||
atomic16->required_pc = result.lower_bound;
|
||||
|
||||
if (atomic16->lsa.is_const() && [&]()
|
||||
{
|
||||
|
|
@ -6529,10 +6383,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
{
|
||||
// Ignore memory access in this case
|
||||
}
|
||||
else if (atomic16->lsa.is_const() && !atomic16->lsa.compare_with_mask_indifference(true_offs, SPU_LS_MASK_128))
|
||||
{
|
||||
// Same
|
||||
}
|
||||
else if (atomic16->ls_invalid && is_store)
|
||||
{
|
||||
break_putllc16(35, atomic16->set_invalid_ls(is_store));
|
||||
|
|
@ -7276,7 +7126,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
|
||||
for (const auto& [pc_commited, pattern] : atomic16_all)
|
||||
{
|
||||
if (!pattern.active || pattern.lsa_pc >= pattern.rdatomic_pc)
|
||||
if (!pattern.active)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -7286,44 +7136,27 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
continue;
|
||||
}
|
||||
|
||||
std::string pattern_hash;
|
||||
{
|
||||
sha1_context ctx;
|
||||
u8 output[20]{};
|
||||
|
||||
sha1_starts(&ctx);
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(result.data.data()) + (pattern.lsa_pc - result.lower_bound), pattern.rdatomic_pc - pattern.lsa_pc);
|
||||
sha1_finish(&ctx, output);
|
||||
fmt::append(pattern_hash, "%s", fmt::base57(output));
|
||||
}
|
||||
|
||||
union putllc16_or_0_info
|
||||
{
|
||||
u64 data;
|
||||
bf_t<u64, 32, 18> required_pc;
|
||||
bf_t<u64, 30, 2> type;
|
||||
bf_t<u64, 29, 1> runtime16_select;
|
||||
bf_t<u64, 28, 1> no_notify;
|
||||
bf_t<u64, 18, 8> reg;
|
||||
bf_t<u64, 0, 18> off18;
|
||||
bf_t<u64, 0, 8> reg2;
|
||||
} value{};
|
||||
|
||||
auto& stats = g_fxo->get<putllc16_statistics_t>();
|
||||
had_putllc_evaluation = true;
|
||||
|
||||
if (!pattern.ls_write)
|
||||
{
|
||||
if (pattern.required_pc != SPU_LS_SIZE)
|
||||
{
|
||||
value.required_pc = pattern.required_pc;
|
||||
}
|
||||
|
||||
// spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
|
||||
// add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data);
|
||||
spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
|
||||
add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa);
|
||||
continue;
|
||||
}
|
||||
|
||||
union putllc16_info
|
||||
{
|
||||
u32 data;
|
||||
bf_t<u32, 30, 2> type;
|
||||
bf_t<u32, 29, 1> runtime16_select;
|
||||
bf_t<u32, 28, 1> no_notify;
|
||||
bf_t<u32, 18, 8> reg;
|
||||
bf_t<u32, 0, 18> off18;
|
||||
bf_t<u32, 0, 8> reg2;
|
||||
} value{};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
v_const = 0,
|
||||
|
|
@ -7354,11 +7187,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
value.runtime16_select = pattern.select_16_or_0_at_runtime;
|
||||
value.reg = s_reg_max;
|
||||
|
||||
if (pattern.required_pc != SPU_LS_SIZE)
|
||||
{
|
||||
value.required_pc = pattern.required_pc;
|
||||
}
|
||||
|
||||
if (pattern.ls.is_const())
|
||||
{
|
||||
ensure(pattern.reg == s_reg_max && pattern.reg2 == s_reg_max && pattern.ls_offs.is_const(), "Unexpected register usage");
|
||||
|
|
@ -7387,35 +7215,16 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
value.reg2 = pattern.reg2;
|
||||
}
|
||||
|
||||
bool allow_pattern = true;
|
||||
|
||||
if (g_cfg.core.spu_accurate_reservations)
|
||||
{
|
||||
// The problem with PUTLLC16 optimization, that it is in theory correct at the bounds of the spu function.
|
||||
// But if the SPU code reuses the cache line data observed, it is not truly atomic.
|
||||
// So we may enable it only for known cases where SPU atomic data is not used after the function leaves.
|
||||
|
||||
// So the two options are:
|
||||
|
||||
// 1. Atomic compare exchange 16 bytes operation. (rest of data is not read) -> good for RPCS3 to optimize.
|
||||
// 2. Fetch 128 bytes (read them later), modify only 16 bytes. -> Bad for RPCS3 to optimize.
|
||||
|
||||
// This difference cannot be known at analyzer time but from observing callers.
|
||||
static constexpr std::initializer_list<std::string_view> allowed_patterns =
|
||||
{
|
||||
"620oYSe8uQqq9eTkhWfMqoEXX0us"sv, // CellSpurs JobChain acquire pattern
|
||||
};
|
||||
|
||||
allow_pattern = std::any_of(allowed_patterns.begin(), allowed_patterns.end(), FN(pattern_hash == x));
|
||||
// Because enabling it is a hack, as it turns out
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allow_pattern)
|
||||
{
|
||||
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
|
||||
}
|
||||
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
|
||||
|
||||
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s, pattern-hash=%s) (putllc0=%d, putllc16+0=%d, all=%d)"
|
||||
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, pattern_hash, +stats.nowrite, ++stats.single, +stats.all);
|
||||
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s) (putllc0=%d, putllc16+0=%d, all=%d)"
|
||||
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, +stats.nowrite, ++stats.single, +stats.all);
|
||||
}
|
||||
|
||||
for (const auto& [read_pc, pattern] : rchcnt_loop_all)
|
||||
|
|
@ -7433,7 +7242,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
|
||||
if (inst_attr attr = m_inst_attrs[(read_pc - entry_point) / 4]; attr == inst_attr::none)
|
||||
{
|
||||
add_pattern(false, inst_attr::rchcnt_loop, read_pc - result.entry_point, 0);
|
||||
add_pattern(false, inst_attr::rchcnt_loop, read_pc - result.entry_point);
|
||||
|
||||
spu_log.error("Channel Loop Pattern Detected! Report to developers! (read_pc=0x%x, branch_pc=0x%x, branch_target=0x%x, 0x%x-%s)", read_pc, pattern.branch_pc, pattern.branch_target, entry_point, func_hash);
|
||||
}
|
||||
|
|
@ -7449,26 +7258,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
|||
// Blocks starting from 0x0 or invalid instruction won't be compiled, may need special interpreter fallback
|
||||
}
|
||||
|
||||
if (!m_patterns.empty())
|
||||
{
|
||||
std::string out_dump;
|
||||
dump(result, out_dump);
|
||||
spu_log.notice("Dump SPU Function with pattern(s):\n%s", out_dump);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < result.data.size(); i++)
|
||||
{
|
||||
const be_t<u32> ls_val = ls[result.lower_bound / 4 + i];
|
||||
|
||||
if (result.data[i] && std::bit_cast<u32>(ls_val) != result.data[i])
|
||||
{
|
||||
std::string out_dump;
|
||||
dump(result, out_dump);
|
||||
spu_log.error("SPU Function Dump:\n%s", out_dump);
|
||||
fmt::throw_exception("SPU Analyzer failed: Instruction mismatch at 0x%x [read: 0x%x vs LS: 0x%x] (i=0x%x)", result.lower_bound + i * 4, std::bit_cast<be_t<u32>>(result.data[i]), ls_val, i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -8478,9 +8267,8 @@ std::array<reg_state_t, s_reg_max>& block_reg_info::evaluate_start_state(const s
|
|||
{
|
||||
// TODO: The true maximum occurence count need to depend on the amount of branching-outs passed through
|
||||
// Currently allow 2 for short-term code and 1 for long-term code
|
||||
// Ignore large jumptables as well
|
||||
const bool loop_terminator_detected = std::count(been_there.begin(), been_there.end(), prev_pc) >= (qi < 20 ? 2u : 1u);
|
||||
const bool avoid_extensive_analysis = qi >= (extensive_evaluation ? 22 : 16) || it->state_prev.size() >= 8;
|
||||
const bool avoid_extensive_analysis = qi >= (extensive_evaluation ? 22 : 16);
|
||||
|
||||
if (!loop_terminator_detected && !avoid_extensive_analysis)
|
||||
{
|
||||
|
|
@ -8519,10 +8307,19 @@ std::array<reg_state_t, s_reg_max>& block_reg_info::evaluate_start_state(const s
|
|||
return walkby_state;
|
||||
}
|
||||
|
||||
void spu_recompiler_base::add_pattern(bool fill_all, inst_attr attr, u32 start, u64 info)
|
||||
void spu_recompiler_base::add_pattern(bool fill_all, inst_attr attr, u32 start, u32 end)
|
||||
{
|
||||
m_patterns[start] = pattern_info{info};
|
||||
m_inst_attrs[start / 4] = attr;
|
||||
if (end == umax)
|
||||
{
|
||||
end = start;
|
||||
}
|
||||
|
||||
m_patterns[start] = pattern_info{utils::address_range32::start_end(start, end)};
|
||||
|
||||
for (u32 i = start; i <= (fill_all ? end : start); i += 4)
|
||||
{
|
||||
m_inst_attrs[i / 4] = attr;
|
||||
}
|
||||
}
|
||||
|
||||
extern std::string format_spu_func_info(u32 addr, cpu_thread* spu)
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ bool ROT(spu_thread& spu, spu_opcode_t op)
|
|||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
spu.gpr[op.rt]._u32[i] = std::rotl<u32>(a._u32[i], b._u32[i]);
|
||||
spu.gpr[op.rt]._u32[i] = utils::rol32(a._u32[i], b._u32[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -346,7 +346,7 @@ bool ROTH(spu_thread& spu, spu_opcode_t op)
|
|||
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
spu.gpr[op.rt]._u16[i] = std::rotl<u16>(a._u16[i], b._u16[i]);
|
||||
spu.gpr[op.rt]._u16[i] = utils::rol16(a._u16[i], b._u16[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1080,7 +1080,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
m_ir->SetInsertPoint(_body);
|
||||
}
|
||||
|
||||
void putllc16_pattern(const spu_program& /*prog*/, u64 pattern_info)
|
||||
void putllc16_pattern(const spu_program& /*prog*/, utils::address_range32 range)
|
||||
{
|
||||
// Prevent store elimination
|
||||
m_block->store_context_ctr[s_reg_mfc_eal]++;
|
||||
|
|
@ -1109,17 +1109,16 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
}
|
||||
};
|
||||
|
||||
const union putllc16_or_0_info
|
||||
const union putllc16_info
|
||||
{
|
||||
u64 data;
|
||||
bf_t<u64, 32, 18> required_pc;
|
||||
bf_t<u64, 30, 2> type;
|
||||
bf_t<u64, 29, 1> runtime16_select;
|
||||
bf_t<u64, 28, 1> no_notify;
|
||||
bf_t<u64, 18, 8> reg;
|
||||
bf_t<u64, 0, 18> off18;
|
||||
bf_t<u64, 0, 8> reg2;
|
||||
} info = std::bit_cast<putllc16_or_0_info>(pattern_info);
|
||||
u32 data;
|
||||
bf_t<u32, 30, 2> type;
|
||||
bf_t<u32, 29, 1> runtime16_select;
|
||||
bf_t<u32, 28, 1> no_notify;
|
||||
bf_t<u32, 18, 8> reg;
|
||||
bf_t<u32, 0, 18> off18;
|
||||
bf_t<u32, 0, 8> reg2;
|
||||
} info = std::bit_cast<putllc16_info>(range.end);
|
||||
|
||||
enum : u32
|
||||
{
|
||||
|
|
@ -1151,10 +1150,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
value_t<u32> eal_val;
|
||||
eal_val.value = _eal;
|
||||
|
||||
auto get_reg32 = [&](u64 reg_)
|
||||
auto get_reg32 = [&](u32 reg)
|
||||
{
|
||||
const u32 reg = static_cast<u32>(reg_);
|
||||
|
||||
if (get_reg_type(reg) != get_type<u32[4]>())
|
||||
{
|
||||
return get_reg_fixed(reg, get_type<u32>());
|
||||
|
|
@ -1173,19 +1170,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
}
|
||||
else if (info.type == v_relative)
|
||||
{
|
||||
if (info.required_pc && info.required_pc != SPU_LS_SIZE)
|
||||
{
|
||||
const auto short_op = llvm::BasicBlock::Create(m_context, "__putllc16_short_op", m_function);
|
||||
const auto heavy_op = llvm::BasicBlock::Create(m_context, "__putllc16_heavy_op", m_function);
|
||||
|
||||
m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->getInt32(info.required_pc), m_base_pc), heavy_op, short_op);
|
||||
m_ir->SetInsertPoint(heavy_op);
|
||||
update_pc();
|
||||
call("spu_exec_mfc_cmd", &exec_mfc_cmd<false>, m_thread);
|
||||
m_ir->CreateBr(_final);
|
||||
m_ir->SetInsertPoint(short_op);
|
||||
}
|
||||
|
||||
dest = m_ir->CreateAnd(get_pc(spu_branch_target(info.off18 + m_base)), 0x3fff0);
|
||||
}
|
||||
else if (info.type == v_reg_offs)
|
||||
|
|
@ -1284,18 +1268,17 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
const auto _new = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr(m_lsptr, dest), llvm::MaybeAlign{16});
|
||||
const auto _rdata = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr(spu_ptr(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x70)), llvm::MaybeAlign{16});
|
||||
|
||||
const bool is_accurate_op = true || !!g_cfg.core.spu_accurate_reservations;
|
||||
const bool is_accurate_op = !!g_cfg.core.spu_accurate_reservations;
|
||||
|
||||
const auto compare_data_change_res = m_ir->CreateICmpNE(_new, _rdata);
|
||||
const auto second_test_for_complete_op = is_accurate_op ? m_ir->getTrue() : compare_data_change_res;
|
||||
const auto compare_data_change_res = is_accurate_op ? m_ir->getTrue() : m_ir->CreateICmpNE(_new, _rdata);
|
||||
|
||||
if (info.runtime16_select)
|
||||
{
|
||||
m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpULT(diff, m_ir->getInt64(128)), second_test_for_complete_op), _begin_op, _inc_res, m_md_likely);
|
||||
m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpULT(diff, m_ir->getInt64(128)), compare_data_change_res), _begin_op, _inc_res, m_md_likely);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ir->CreateCondBr(second_test_for_complete_op, _begin_op, _inc_res, m_md_unlikely);
|
||||
m_ir->CreateCondBr(compare_data_change_res, _begin_op, _inc_res, m_md_unlikely);
|
||||
}
|
||||
|
||||
m_ir->SetInsertPoint(_begin_op);
|
||||
|
|
@ -1340,14 +1323,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
|
||||
if (!info.no_notify)
|
||||
{
|
||||
const auto notify_block = llvm::BasicBlock::Create(m_context, "__putllc16_block_notify", m_function);
|
||||
const auto notify_next = llvm::BasicBlock::Create(m_context, "__putllc16_block_notify_next", m_function);
|
||||
|
||||
m_ir->CreateCondBr(compare_data_change_res, notify_block, notify_next);
|
||||
m_ir->SetInsertPoint(notify_block);
|
||||
call("atomic_wait_engine::notify_all", static_cast<void(*)(const void*)>(atomic_wait_engine::notify_all), rptr);
|
||||
m_ir->CreateBr(notify_next);
|
||||
m_ir->SetInsertPoint(notify_next);
|
||||
}
|
||||
|
||||
m_ir->CreateBr(_success);
|
||||
|
|
@ -1397,7 +1373,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
m_ir->SetInsertPoint(_final);
|
||||
}
|
||||
|
||||
void putllc0_pattern(const spu_program& /*prog*/, u64 pattern_info)
|
||||
void putllc0_pattern(const spu_program& /*prog*/, utils::address_range32 /*range*/)
|
||||
{
|
||||
// Prevent store elimination
|
||||
m_block->store_context_ctr[s_reg_mfc_eal]++;
|
||||
|
|
@ -1425,18 +1401,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
}
|
||||
};
|
||||
|
||||
const union putllc16_or_0_info
|
||||
{
|
||||
u64 data;
|
||||
bf_t<u64, 32, 18> required_pc;
|
||||
bf_t<u64, 30, 2> type;
|
||||
bf_t<u64, 29, 1> runtime16_select;
|
||||
bf_t<u64, 28, 1> no_notify;
|
||||
bf_t<u64, 18, 8> reg;
|
||||
bf_t<u64, 0, 18> off18;
|
||||
bf_t<u64, 0, 8> reg2;
|
||||
} info = std::bit_cast<putllc16_or_0_info>(pattern_info);
|
||||
|
||||
const auto _next = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||
const auto _next0 = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||
const auto _fail = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||
|
|
@ -1445,19 +1409,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||
const auto _eal = (get_reg_fixed<u32>(s_reg_mfc_eal) & -128).eval(m_ir);
|
||||
const auto _raddr = m_ir->CreateLoad(get_type<u32>(), spu_ptr(&spu_thread::raddr));
|
||||
|
||||
if (info.required_pc && info.required_pc != SPU_LS_SIZE)
|
||||
{
|
||||
const auto short_op = llvm::BasicBlock::Create(m_context, "__putllc0_short_op", m_function);
|
||||
const auto heavy_op = llvm::BasicBlock::Create(m_context, "__putllc0_heavy_op", m_function);
|
||||
|
||||
m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->getInt32(info.required_pc), m_base_pc), heavy_op, short_op);
|
||||
m_ir->SetInsertPoint(heavy_op);
|
||||
update_pc();
|
||||
call("spu_exec_mfc_cmd", &exec_mfc_cmd<false>, m_thread);
|
||||
m_ir->CreateBr(_final);
|
||||
m_ir->SetInsertPoint(short_op);
|
||||
}
|
||||
|
||||
m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpEQ(_eal, _raddr), m_ir->CreateIsNotNull(_raddr)), _next, _fail, m_md_likely);
|
||||
m_ir->SetInsertPoint(_next);
|
||||
|
||||
|
|
@ -1647,11 +1598,7 @@ public:
|
|||
|
||||
// Create LLVM module
|
||||
std::unique_ptr<Module> _module = std::make_unique<Module>(m_hash + ".obj", m_context);
|
||||
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
|
||||
_module->setTargetTriple(Triple(jit_compiler::triple2()));
|
||||
#else
|
||||
_module->setTargetTriple(jit_compiler::triple2());
|
||||
#endif
|
||||
_module->setDataLayout(m_jit.get_engine().getTargetMachine()->createDataLayout());
|
||||
m_module = _module.get();
|
||||
|
||||
|
|
@ -1685,7 +1632,7 @@ public:
|
|||
m_ir->SetInsertPoint(label_test);
|
||||
|
||||
// Set block hash for profiling (if enabled)
|
||||
if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification)
|
||||
if (g_cfg.core.spu_prof && g_cfg.core.spu_verification)
|
||||
m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536)), spu_ptr(&spu_thread::block_hash));
|
||||
|
||||
if (!g_cfg.core.spu_verification)
|
||||
|
|
@ -2042,7 +1989,7 @@ public:
|
|||
set_function(m_functions[m_entry].chunk);
|
||||
|
||||
// Set block hash for profiling (if enabled)
|
||||
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
|
||||
if (g_cfg.core.spu_prof)
|
||||
m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (m_entry >> 2)), spu_ptr(&spu_thread::block_hash));
|
||||
|
||||
m_finfo = &m_functions[m_entry];
|
||||
|
|
@ -2192,12 +2139,12 @@ public:
|
|||
{
|
||||
case inst_attr::putllc0:
|
||||
{
|
||||
putllc0_pattern(func, m_patterns.at(m_pos - start).info);
|
||||
putllc0_pattern(func, m_patterns.at(m_pos - start).range);
|
||||
continue;
|
||||
}
|
||||
case inst_attr::putllc16:
|
||||
{
|
||||
putllc16_pattern(func, m_patterns.at(m_pos - start).info);
|
||||
putllc16_pattern(func, m_patterns.at(m_pos - start).range);
|
||||
continue;
|
||||
}
|
||||
case inst_attr::omit:
|
||||
|
|
@ -2280,12 +2227,6 @@ public:
|
|||
{
|
||||
for (auto& [a, b] : m_blocks)
|
||||
{
|
||||
if (has_gpr_memory_barriers)
|
||||
{
|
||||
// Dive deeper and inspect GPR store barriers
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the store occurs before any barrier in the block
|
||||
if (b.store[i] && b.store[i] != bs && b.store_context_first_id[i] == 1)
|
||||
{
|
||||
|
|
@ -2932,11 +2873,7 @@ public:
|
|||
|
||||
// Create LLVM module
|
||||
std::unique_ptr<Module> _module = std::make_unique<Module>("spu_interpreter.obj", m_context);
|
||||
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
|
||||
_module->setTargetTriple(Triple(jit_compiler::triple2()));
|
||||
#else
|
||||
_module->setTargetTriple(jit_compiler::triple2());
|
||||
#endif
|
||||
_module->setDataLayout(m_jit.get_engine().getTargetMachine()->createDataLayout());
|
||||
m_module = _module.get();
|
||||
|
||||
|
|
@ -4040,7 +3977,7 @@ public:
|
|||
|
||||
bool must_use_cpp_functions = !!g_cfg.core.spu_accurate_dma;
|
||||
|
||||
if (u64 cmdh = ci->getZExtValue() & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_RESULT_MASK); g_cfg.core.rsx_fifo_accuracy || g_cfg.video.strict_rendering_mode || /*!g_use_rtm*/ true)
|
||||
if (u64 cmdh = ci->getZExtValue() & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_RESULT_MASK); g_cfg.core.rsx_fifo_accuracy || g_cfg.video.strict_rendering_mode || !g_use_rtm)
|
||||
{
|
||||
// TODO: don't require TSX (current implementation is TSX-only)
|
||||
if (cmdh == MFC_PUT_CMD || cmdh == MFC_SNDSIG_CMD)
|
||||
|
|
|
|||
|
|
@ -397,12 +397,12 @@ protected:
|
|||
|
||||
struct pattern_info
|
||||
{
|
||||
u64 info;
|
||||
utils::address_range32 range;
|
||||
};
|
||||
|
||||
std::unordered_map<u32, pattern_info> m_patterns;
|
||||
|
||||
void add_pattern(bool fill_all, inst_attr attr, u32 start, u64 info);
|
||||
void add_pattern(bool fill_all, inst_attr attr, u32 start, u32 end = -1);
|
||||
|
||||
private:
|
||||
// For private use
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -901,8 +901,7 @@ public:
|
|||
|
||||
// Returns true if reservation existed but was just discovered to be lost
|
||||
// It is safe to use on any address, even if not directly accessed by SPU (so it's slower)
|
||||
// Optionally pass a known allocated address for internal optimization (the current Effective-Address of the MFC command)
|
||||
bool reservation_check(u32 addr, const decltype(rdata)& data, u32 current_eal = 0) const;
|
||||
bool reservation_check(u32 addr, const decltype(rdata)& data) const;
|
||||
static bool reservation_check(u32 addr, u32 hash, atomic_t<u64, 64>* range_lock);
|
||||
usz register_cache_line_waiter(u32 addr);
|
||||
void deregister_cache_line_waiter(usz index);
|
||||
|
|
|
|||
|
|
@ -1036,6 +1036,7 @@ lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mo
|
|||
error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_open(path=%s, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
|
||||
|
||||
|
|
@ -1084,6 +1085,7 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
|
|||
error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread);
|
||||
|
||||
|
|
@ -1120,11 +1122,6 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, v
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (nbytes >= 0x100000 && file->type != lv2_file_type::regular)
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
}
|
||||
|
||||
std::unique_lock lock(file->mp->mutex);
|
||||
|
||||
if (!file->file)
|
||||
|
|
@ -1157,6 +1154,7 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, v
|
|||
error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite);
|
||||
|
||||
|
|
@ -1239,6 +1237,7 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
|
|||
error_code sys_fs_close(ppu_thread& ppu, u32 fd)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
|
||||
|
||||
|
|
@ -1315,6 +1314,7 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd)
|
|||
error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_opendir(path=%s, fd=*0x%x)", path, fd);
|
||||
|
||||
|
|
@ -1491,6 +1491,7 @@ error_code sys_fs_readdir(ppu_thread& ppu, u32 fd, vm::ptr<CellFsDirent> dir, vm
|
|||
error_code sys_fs_closedir(ppu_thread& ppu, u32 fd)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_closedir(fd=%d)", fd);
|
||||
|
||||
|
|
@ -1505,6 +1506,7 @@ error_code sys_fs_closedir(ppu_thread& ppu, u32 fd)
|
|||
error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_stat(path=%s, sb=*0x%x)", path, sb);
|
||||
|
||||
|
|
@ -1608,6 +1610,7 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
|
|||
error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb);
|
||||
|
||||
|
|
@ -1663,6 +1666,7 @@ error_code sys_fs_link(ppu_thread&, vm::cptr<char> from, vm::cptr<char> to)
|
|||
error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_mkdir(path=%s, mode=%#o)", path, mode);
|
||||
|
||||
|
|
@ -1724,6 +1728,7 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
|
|||
error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to);
|
||||
|
||||
|
|
@ -1789,6 +1794,7 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to
|
|||
error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_rmdir(path=%s)", path);
|
||||
|
||||
|
|
@ -1844,6 +1850,7 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
|
|||
error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr<char> path)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_unlink(path=%s)", path);
|
||||
|
||||
|
|
@ -1944,6 +1951,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
case 0x8000000a: // cellFsReadWithOffset
|
||||
case 0x8000000b: // cellFsWriteWithOffset
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const auto arg = vm::static_ptr_cast<lv2_file_op_rw>(_arg);
|
||||
|
||||
if (_size < arg.size())
|
||||
|
|
@ -1983,11 +1992,6 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
sys_fs.error("%s type: Writing %u bytes to FD=%d (path=%s)", file->type, arg->size, file->name.data());
|
||||
}
|
||||
|
||||
if (op == 0x8000000a && file->type != lv2_file_type::regular && arg->size >= 0x100000)
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
}
|
||||
|
||||
std::unique_lock wlock(file->mp->mutex, std::defer_lock);
|
||||
std::shared_lock rlock(file->mp->mutex, std::defer_lock);
|
||||
|
||||
|
|
@ -2043,6 +2047,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
|
||||
case 0x80000009: // cellFsSdataOpenByFd
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const auto arg = vm::static_ptr_cast<lv2_file_op_09>(_arg);
|
||||
|
||||
if (_size < arg.size())
|
||||
|
|
@ -2096,6 +2102,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
|
||||
case 0xc0000002: // cellFsGetFreeSize (TODO)
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const auto arg = vm::static_ptr_cast<lv2_file_c0000002>(_arg);
|
||||
|
||||
const auto& mp = g_fxo->get<lv2_fs_mount_info_map>().lookup("/dev_hdd0");
|
||||
|
|
@ -2410,6 +2418,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
|
||||
case 0xe0000012: // cellFsGetDirectoryEntries
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
const auto arg = vm::static_ptr_cast<lv2_file_op_dir::dir_info>(_arg);
|
||||
|
||||
if (_size < arg.size())
|
||||
|
|
@ -2424,6 +2434,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
ppu.check_state();
|
||||
|
||||
u32 read_count = 0;
|
||||
|
||||
// NOTE: This function is actually capable of reading only one entry at a time
|
||||
|
|
@ -2581,6 +2593,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
|
|||
error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
|
||||
|
||||
|
|
@ -2626,6 +2639,7 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
|
|||
error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_fdadasync(fd=%d)", fd);
|
||||
|
||||
|
|
@ -2636,8 +2650,6 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
|
|||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
std::lock_guard lock(file->mp->mutex);
|
||||
|
||||
if (!file->file)
|
||||
|
|
@ -2652,6 +2664,7 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
|
|||
error_code sys_fs_fsync(ppu_thread& ppu, u32 fd)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.trace("sys_fs_fsync(fd=%d)", fd);
|
||||
|
||||
|
|
@ -2662,8 +2675,6 @@ error_code sys_fs_fsync(ppu_thread& ppu, u32 fd)
|
|||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
std::lock_guard lock(file->mp->mutex);
|
||||
|
||||
if (!file->file)
|
||||
|
|
@ -2752,6 +2763,7 @@ error_code sys_fs_get_block_size(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u
|
|||
error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_truncate(path=%s, size=0x%llx)", path, size);
|
||||
|
||||
|
|
@ -2803,6 +2815,7 @@ error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
|
|||
error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size);
|
||||
|
||||
|
|
@ -3008,6 +3021,7 @@ error_code sys_fs_disk_free(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u64> t
|
|||
error_code sys_fs_utime(ppu_thread& ppu, vm::cptr<char> path, vm::cptr<CellFsUtimbuf> timep)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
sys_fs.warning("sys_fs_utime(path=%s, timep=*0x%x)", path, timep);
|
||||
sys_fs.warning("** actime=%u, modtime=%u", timep->actime, timep->modtime);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include "Emu/CPU/CPUThread.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
|
@ -214,8 +213,6 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid
|
|||
|
||||
if (alloc_addr)
|
||||
{
|
||||
sys_memory.notice("sys_memory_allocate_from_container(): Allocated 0x%x address (size=0x%x)", addr, size);
|
||||
|
||||
vm::lock_sudo(addr, static_cast<u32>(size));
|
||||
cpu.check_state();
|
||||
*alloc_addr = addr;
|
||||
|
|
@ -250,37 +247,17 @@ error_code sys_memory_free(cpu_thread& cpu, u32 addr)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_memory_get_page_attribute(ppu_thread& ppu, u32 addr, vm::ptr<sys_page_attr_t> attr)
|
||||
error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
cpu.state += cpu_flag::wait;
|
||||
|
||||
sys_memory.trace("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr);
|
||||
|
||||
if ((addr >> 28) == (ppu.stack_addr >> 28))
|
||||
vm::writer_lock rlock;
|
||||
|
||||
if (!vm::check_addr(addr) || addr >= SPU_FAKE_BASE_ADDR)
|
||||
{
|
||||
// Stack address: fast path
|
||||
if (!(addr >= ppu.stack_addr && addr < ppu.stack_addr + ppu.stack_size) && !vm::check_addr(addr))
|
||||
{
|
||||
return { CELL_EINVAL, addr };
|
||||
}
|
||||
|
||||
if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size()))
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE
|
||||
attr->access_right = SYS_MEMORY_ACCESS_RIGHT_PPU_THR;
|
||||
attr->page_size = 4096;
|
||||
attr->pad = 0; // Always write 0
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
const auto [ok, vm_flags] = vm::get_addr_flags(addr);
|
||||
|
||||
if (!ok || addr >= SPU_FAKE_BASE_ADDR)
|
||||
{
|
||||
return { CELL_EINVAL, addr };
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size()))
|
||||
|
|
@ -289,20 +266,19 @@ error_code sys_memory_get_page_attribute(ppu_thread& ppu, u32 addr, vm::ptr<sys_
|
|||
}
|
||||
|
||||
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE (TODO)
|
||||
attr->access_right = SYS_MEMORY_ACCESS_RIGHT_ANY; // TODO: Report accurately
|
||||
attr->access_right = addr >> 28 == 0xdu ? SYS_MEMORY_ACCESS_RIGHT_PPU_THR : SYS_MEMORY_ACCESS_RIGHT_ANY;// (TODO)
|
||||
|
||||
if (vm_flags & vm::page_1m_size)
|
||||
if (vm::check_addr(addr, vm::page_1m_size))
|
||||
{
|
||||
attr->page_size = 0x100000;
|
||||
}
|
||||
else if (vm_flags & vm::page_64k_size)
|
||||
else if (vm::check_addr(addr, vm::page_64k_size))
|
||||
{
|
||||
attr->page_size = 0x10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
//attr->page_size = 4096;
|
||||
fmt::throw_exception("Unreachable");
|
||||
attr->page_size = 4096;
|
||||
}
|
||||
|
||||
attr->pad = 0; // Always write 0
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include "Emu/Cell/ErrorCodes.h"
|
||||
|
||||
class cpu_thread;
|
||||
class ppu_thread;
|
||||
|
||||
enum lv2_mem_container_id : u32
|
||||
{
|
||||
|
|
@ -132,7 +131,7 @@ struct sys_memory_user_memory_stat_t
|
|||
error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr<u32> alloc_addr);
|
||||
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr);
|
||||
error_code sys_memory_free(cpu_thread& cpu, u32 start_addr);
|
||||
error_code sys_memory_get_page_attribute(ppu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr);
|
||||
error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr);
|
||||
error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info);
|
||||
error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_user_memory_stat_t> mem_stat);
|
||||
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size);
|
||||
|
|
|
|||
|
|
@ -468,11 +468,11 @@ error_code sys_ppu_thread_restart(ppu_thread& ppu)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 unk, s32 prio, u64 _stacksz, u64 flags, vm::cptr<char> threadname)
|
||||
error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 unk, s32 prio, u32 _stacksz, u64 flags, vm::cptr<char> threadname)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_ppu_thread.warning("_sys_ppu_thread_create(thread_id=*0x%x, param=*0x%x, arg=0x%llx, unk=0x%llx, prio=%d, stacksize=0x%llx, flags=0x%llx, threadname=*0x%x)",
|
||||
sys_ppu_thread.warning("_sys_ppu_thread_create(thread_id=*0x%x, param=*0x%x, arg=0x%llx, unk=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)",
|
||||
thread_id, param, arg, unk, prio, _stacksz, flags, threadname);
|
||||
|
||||
// thread_id is checked for null in stub -> CELL_ENOMEM
|
||||
|
|
@ -497,8 +497,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
|
|||
const u32 tls = param->tls;
|
||||
|
||||
// Compute actual stack size and allocate
|
||||
// 0 and UINT64_MAX both convert to 4096
|
||||
const u64 stack_size = FN(x ? x : 4096)(utils::align<u64>(_stacksz, 4096));
|
||||
const u32 stack_size = utils::align<u32>(std::max<u32>(_stacksz, 4096), 4096);
|
||||
|
||||
auto& dct = g_fxo->get<lv2_memory_container>();
|
||||
|
||||
|
|
@ -508,7 +507,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
|
|||
return {CELL_ENOMEM, dct.size - dct.used};
|
||||
}
|
||||
|
||||
const vm::addr_t stack_base{vm::alloc(static_cast<u32>(stack_size), vm::stack, 4096)};
|
||||
const vm::addr_t stack_base{vm::alloc(stack_size, vm::stack, 4096)};
|
||||
|
||||
if (!stack_base)
|
||||
{
|
||||
|
|
@ -533,7 +532,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
|
|||
{
|
||||
ppu_thread_params p;
|
||||
p.stack_addr = stack_base;
|
||||
p.stack_size = static_cast<u32>(stack_size);
|
||||
p.stack_size = stack_size;
|
||||
p.tls_addr = tls;
|
||||
p.entry = entry;
|
||||
p.arg0 = arg;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ error_code sys_ppu_thread_get_priority(ppu_thread& ppu, u32 thread_id, vm::ptr<s
|
|||
error_code sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp);
|
||||
error_code sys_ppu_thread_stop(ppu_thread& ppu, u32 thread_id);
|
||||
error_code sys_ppu_thread_restart(ppu_thread& ppu);
|
||||
error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 arg4, s32 prio, u64 stacksize, u64 flags, vm::cptr<char> threadname);
|
||||
error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 arg4, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname);
|
||||
error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id);
|
||||
error_code sys_ppu_thread_rename(ppu_thread& ppu, u32 thread_id, vm::cptr<char> name);
|
||||
error_code sys_ppu_thread_recover_page_fault(ppu_thread& ppu, u32 thread_id);
|
||||
|
|
|
|||
|
|
@ -767,12 +767,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
|
|||
}
|
||||
|
||||
// Read thread name
|
||||
std::string thread_name;
|
||||
|
||||
if (attr_data.name_len && !vm::read_string(attr_data.name.addr(), attr_data.name_len - 1, thread_name, true))
|
||||
{
|
||||
return { CELL_EFAULT, attr_data.name.addr() };
|
||||
}
|
||||
const std::string thread_name(attr_data.name.get_ptr(), std::max<u32>(attr_data.name_len, 1) - 1);
|
||||
|
||||
const auto group = idm::get_unlocked<lv2_spu_group>(group_id);
|
||||
|
||||
|
|
@ -911,7 +906,7 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<s32>
|
|||
return CELL_ESTAT;
|
||||
}
|
||||
|
||||
error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<reduced_sys_spu_thread_group_attribute> attr)
|
||||
error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
|
|
@ -919,32 +914,13 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
|||
|
||||
const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16;
|
||||
|
||||
sys_spu_thread_group_attribute attr_data{};
|
||||
{
|
||||
const reduced_sys_spu_thread_group_attribute attr_reduced = *attr;
|
||||
attr_data.name = attr_reduced.name;
|
||||
attr_data.nsize = attr_reduced.nsize;
|
||||
attr_data.type = attr_reduced.type;
|
||||
|
||||
// Read container-id member at offset 12 bytes conditionally (that's what LV2 does)
|
||||
if (attr_data.type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER)
|
||||
{
|
||||
attr_data.ct = vm::unsafe_ptr_cast<sys_spu_thread_group_attribute>(attr)->ct;
|
||||
}
|
||||
}
|
||||
const sys_spu_thread_group_attribute attr_data = *attr;
|
||||
|
||||
if (attr_data.nsize > 0x80 || !num)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
std::string group_name;
|
||||
|
||||
if (attr_data.nsize && !vm::read_string(attr_data.name.addr(), attr_data.nsize - 1, group_name, true))
|
||||
{
|
||||
return { CELL_EFAULT, attr_data.name.addr() };
|
||||
}
|
||||
|
||||
const s32 type = attr_data.type;
|
||||
|
||||
bool use_scheduler = true;
|
||||
|
|
@ -1099,7 +1075,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
|||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
const auto group = idm::make_ptr<lv2_spu_group>(std::move(group_name), num, prio, type, ct, use_scheduler, mem_size);
|
||||
const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr_data.name.get_ptr(), std::max<u32>(attr_data.nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size);
|
||||
|
||||
if (!group)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -82,16 +82,9 @@ enum spu_stop_syscall : u32
|
|||
SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE = 0x0120,
|
||||
};
|
||||
|
||||
struct reduced_sys_spu_thread_group_attribute
|
||||
{
|
||||
be_t<u32> nsize; // name length including NULL terminator
|
||||
vm::bcptr<char> name;
|
||||
be_t<s32> type;
|
||||
};
|
||||
|
||||
struct sys_spu_thread_group_attribute
|
||||
{
|
||||
be_t<u32> nsize;
|
||||
be_t<u32> nsize; // name length including NULL terminator
|
||||
vm::bcptr<char> name;
|
||||
be_t<s32> type;
|
||||
be_t<u32> ct; // memory container id
|
||||
|
|
@ -367,7 +360,7 @@ error_code _sys_spu_image_close(ppu_thread&, vm::ptr<sys_spu_image> img);
|
|||
error_code _sys_spu_image_get_segments(ppu_thread&, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_segment> segments, s32 nseg);
|
||||
error_code sys_spu_thread_initialize(ppu_thread&, vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image>, vm::ptr<sys_spu_thread_attribute>, vm::ptr<sys_spu_thread_argument>);
|
||||
error_code sys_spu_thread_set_argument(ppu_thread&, u32 id, vm::ptr<sys_spu_thread_argument> arg);
|
||||
error_code sys_spu_thread_group_create(ppu_thread&, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<reduced_sys_spu_thread_group_attribute> attr);
|
||||
error_code sys_spu_thread_group_create(ppu_thread&, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr);
|
||||
error_code sys_spu_thread_group_destroy(ppu_thread&, u32 id);
|
||||
error_code sys_spu_thread_group_start(ppu_thread&, u32 id);
|
||||
error_code sys_spu_thread_group_suspend(ppu_thread&, u32 id);
|
||||
|
|
|
|||
|
|
@ -210,10 +210,8 @@ error_code sys_ss_get_open_psid(vm::ptr<CellSsOpenPSID> psid)
|
|||
{
|
||||
sys_ss.notice("sys_ss_get_open_psid(psid=*0x%x)", psid);
|
||||
|
||||
const u128 configured_psid = g_cfg.sys.console_psid.get();
|
||||
|
||||
psid->high = static_cast<u64>(configured_psid >> 64);
|
||||
psid->low = static_cast<u64>(configured_psid);
|
||||
psid->high = g_cfg.sys.console_psid_high;
|
||||
psid->low = g_cfg.sys.console_psid_low;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
@ -261,8 +259,8 @@ error_code sys_ss_appliance_info_manager(u32 code, vm::ptr<u8> buffer)
|
|||
case 0x19005:
|
||||
{
|
||||
// AIM_get_open_ps_id
|
||||
const be_t<u128> psid = g_cfg.sys.console_psid.get();
|
||||
std::memcpy(buffer.get_ptr(), &psid, 16);
|
||||
be_t<u64> psid[2] = { +g_cfg.sys.console_psid_high, +g_cfg.sys.console_psid_low };
|
||||
std::memcpy(buffer.get_ptr(), psid, 16);
|
||||
break;
|
||||
}
|
||||
case 0x19006:
|
||||
|
|
@ -270,11 +268,7 @@ error_code sys_ss_appliance_info_manager(u32 code, vm::ptr<u8> buffer)
|
|||
// qa values (dex only) ??
|
||||
[[fallthrough]];
|
||||
}
|
||||
default:
|
||||
{
|
||||
sys_ss.todo("sys_ss_appliance_info_manager(code=0x%x, buffer=*0x%x)", code, buffer);
|
||||
break;
|
||||
}
|
||||
default: sys_ss.todo("sys_ss_appliance_info_manager(code=0x%x, buffer=*0x%x)", code, buffer);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include "Emu/Io/Skylander.h"
|
||||
#include "Emu/Io/Infinity.h"
|
||||
#include "Emu/Io/Dimensions.h"
|
||||
#include "Emu/Io/KamenRider.h"
|
||||
#include "Emu/Io/GHLtar.h"
|
||||
#include "Emu/Io/ghltar_config.h"
|
||||
#include "Emu/Io/guncon3_config.h"
|
||||
|
|
@ -176,7 +175,7 @@ private:
|
|||
{0x1430, 0x0150, 0x0150, "Skylanders Portal", &usb_device_skylander::get_num_emu_devices, &usb_device_skylander::make_instance},
|
||||
{0x0E6F, 0x0129, 0x0129, "Disney Infinity Base", &usb_device_infinity::get_num_emu_devices, &usb_device_infinity::make_instance},
|
||||
{0x0E6F, 0x0241, 0x0241, "Lego Dimensions Portal", &usb_device_dimensions::get_num_emu_devices, &usb_device_dimensions::make_instance},
|
||||
{0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal", &usb_device_kamen_rider::get_num_emu_devices, &usb_device_kamen_rider::make_instance},
|
||||
{0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal", nullptr, nullptr},
|
||||
|
||||
// Cameras
|
||||
// {0x1415, 0x0020, 0x2000, "Sony Playstation Eye", nullptr, nullptr}, // TODO: verifiy
|
||||
|
|
|
|||
|
|
@ -544,7 +544,9 @@ std::optional<std::array<u8, 32>> dimensions_toypad::pop_added_removed_response(
|
|||
std::lock_guard lock(m_dimensions_mutex);
|
||||
|
||||
if (m_figure_added_removed_responses.empty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::array<u8, 32> response = m_figure_added_removed_responses.front();
|
||||
m_figure_added_removed_responses.pop();
|
||||
|
|
@ -595,6 +597,7 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi
|
|||
{
|
||||
// Read Endpoint, if a request has not been sent via the write endpoint, set expected result as
|
||||
// EHCI_CC_HALTED so the game doesn't report the Toypad as being disconnected.
|
||||
std::lock_guard lock(m_query_mutex);
|
||||
std::optional<std::array<u8, 32>> response = g_dimensionstoypad.pop_added_removed_response();
|
||||
if (response)
|
||||
{
|
||||
|
|
@ -693,6 +696,7 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi
|
|||
break;
|
||||
}
|
||||
}
|
||||
std::lock_guard lock(m_query_mutex);
|
||||
m_queries.push(q_result);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,5 +79,6 @@ public:
|
|||
void isochronous_transfer(UsbTransfer* transfer) override;
|
||||
|
||||
protected:
|
||||
shared_mutex m_query_mutex;
|
||||
std::queue<std::array<u8, 32>> m_queries;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -258,13 +258,13 @@ void infinity_base::get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8
|
|||
reply_buf[11] = generate_checksum(reply_buf, 11);
|
||||
}
|
||||
|
||||
std::optional<std::array<u8, 32>> infinity_base::pop_added_removed_response()
|
||||
bool infinity_base::has_figure_been_added_removed() const
|
||||
{
|
||||
std::lock_guard lock(infinity_mutex);
|
||||
|
||||
if (m_figure_added_removed_responses.empty())
|
||||
return std::nullopt;
|
||||
return !m_figure_added_removed_responses.empty();
|
||||
}
|
||||
|
||||
std::array<u8, 32> infinity_base::pop_added_removed_response()
|
||||
{
|
||||
std::array<u8, 32> response = m_figure_added_removed_responses.front();
|
||||
m_figure_added_removed_responses.pop();
|
||||
return response;
|
||||
|
|
@ -399,10 +399,9 @@ void usb_device_infinity::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint
|
|||
{
|
||||
// Respond after FF command
|
||||
transfer->expected_time = get_timestamp() + 1000;
|
||||
std::optional<std::array<u8, 32>> response = g_infinitybase.pop_added_removed_response();
|
||||
if (response)
|
||||
if (g_infinitybase.has_figure_been_added_removed())
|
||||
{
|
||||
memcpy(buf, response.value().data(), 0x20);
|
||||
memcpy(buf, g_infinitybase.pop_added_removed_response().data(), 0x20);
|
||||
}
|
||||
else if (!m_queries.empty())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "Emu/Io/usb_device.h"
|
||||
#include "Utilities/mutex.h"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
struct infinity_figure
|
||||
|
|
@ -25,7 +24,8 @@ public:
|
|||
void query_block(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence);
|
||||
void write_block(u8 fig_num, u8 block, const u8* to_write_buf, std::array<u8, 32>& reply_buf, u8 sequence);
|
||||
void get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf);
|
||||
std::optional<std::array<u8, 32>> pop_added_removed_response();
|
||||
bool has_figure_been_added_removed() const;
|
||||
std::array<u8, 32> pop_added_removed_response();
|
||||
|
||||
bool remove_figure(u8 position);
|
||||
u32 load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file, u8 position);
|
||||
|
|
|
|||
|
|
@ -1,291 +0,0 @@
|
|||
#include "stdafx.h"
|
||||
#include "KamenRider.h"
|
||||
|
||||
LOG_CHANNEL(kamen_rider_log, "kamen_rider");
|
||||
|
||||
rider_gate g_ridergate;
|
||||
|
||||
void kamen_rider_figure::save()
|
||||
{
|
||||
if (!kamen_file)
|
||||
{
|
||||
kamen_rider_log.error("Tried to save kamen rider figure to file but no kamen rider figure is active!");
|
||||
return;
|
||||
}
|
||||
kamen_file.seek(0, fs::seek_set);
|
||||
kamen_file.write(data.data(), 0x14 * 0x10);
|
||||
}
|
||||
|
||||
u8 rider_gate::generate_checksum(const std::array<u8, 64>& data, u32 num_of_bytes) const
|
||||
{
|
||||
ensure(num_of_bytes <= data.size());
|
||||
int checksum = 0;
|
||||
for (u32 i = 0; i < num_of_bytes; i++)
|
||||
{
|
||||
checksum += data[i];
|
||||
}
|
||||
return (checksum & 0xFF);
|
||||
}
|
||||
|
||||
kamen_rider_figure& rider_gate::get_figure_by_uid(const std::array<u8, 7> uid)
|
||||
{
|
||||
for (kamen_rider_figure& figure : figures)
|
||||
{
|
||||
if (figure.uid == uid)
|
||||
{
|
||||
return figure;
|
||||
}
|
||||
}
|
||||
return figures[7];
|
||||
}
|
||||
|
||||
void rider_gate::get_blank_response(u8 command, u8 sequence, std::array<u8, 64>& reply_buf)
|
||||
{
|
||||
reply_buf = {0x55, 0x02, command, sequence};
|
||||
reply_buf[4] = generate_checksum(reply_buf, 4);
|
||||
}
|
||||
|
||||
void rider_gate::wake_rider_gate(std::array<u8, 64>& reply_buf, u8 command, u8 sequence)
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
m_is_awake = true;
|
||||
reply_buf = {0x55, 0x1a, command, sequence, 0x00, 0x07, 0x00, 0x03, 0x02,
|
||||
0x09, 0x20, 0x03, 0xf5, 0x00, 0x19, 0x42, 0x52, 0xb7,
|
||||
0xb9, 0xa1, 0xae, 0x2b, 0x88, 0x42, 0x05, 0xfe, 0xe0, 0x1c, 0xac};
|
||||
}
|
||||
|
||||
void rider_gate::get_list_tags(std::array<u8, 64>& reply_buf, u8 command, u8 sequence)
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
reply_buf = {0x55, 0x02, command, sequence};
|
||||
u8 index = 4;
|
||||
for (const kamen_rider_figure& figure : figures)
|
||||
{
|
||||
if (figure.present)
|
||||
{
|
||||
reply_buf[index] = 0x09;
|
||||
memcpy(&reply_buf[index + 1], figure.data.data(), 7);
|
||||
index += 8;
|
||||
reply_buf[1] += 8;
|
||||
}
|
||||
}
|
||||
reply_buf[index] = generate_checksum(reply_buf, index);
|
||||
}
|
||||
|
||||
void rider_gate::query_block(std::array<u8, 64>& reply_buf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block)
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
reply_buf = {0x55, 0x13, command, sequence, 0x00};
|
||||
|
||||
const std::array<u8, 7> uid_array = {uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
|
||||
|
||||
const kamen_rider_figure& figure = get_figure_by_uid(uid_array);
|
||||
if (figure.present)
|
||||
{
|
||||
if (sector < 5 && block < 4)
|
||||
{
|
||||
memcpy(&reply_buf[5], &figure.data[(sector * 4 * 16) + (block * 16)], 16);
|
||||
}
|
||||
}
|
||||
reply_buf[21] = generate_checksum(reply_buf, 21);
|
||||
}
|
||||
|
||||
void rider_gate::write_block(std::array<u8, 64>& replyBuf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block, const u8* to_write_buf)
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
const std::array<u8, 7> uid_array = {uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
|
||||
|
||||
kamen_rider_figure& figure = get_figure_by_uid(uid_array);
|
||||
if (figure.present)
|
||||
{
|
||||
if (sector < 5 && block < 4)
|
||||
{
|
||||
memcpy(&figure.data[(sector * 4 * 16) + (block * 16)], to_write_buf, 16);
|
||||
}
|
||||
}
|
||||
|
||||
get_blank_response(command, sequence, replyBuf);
|
||||
}
|
||||
|
||||
std::optional<std::array<u8, 64>> rider_gate::pop_added_removed_response()
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
if (m_figure_added_removed_responses.empty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::array<u8, 64> response = m_figure_added_removed_responses.front();
|
||||
m_figure_added_removed_responses.pop();
|
||||
return response;
|
||||
}
|
||||
|
||||
bool rider_gate::remove_figure(u8 index)
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
auto& figure = figures[index];
|
||||
|
||||
if (figure.present)
|
||||
{
|
||||
figure.present = false;
|
||||
figure.save();
|
||||
figure.kamen_file.close();
|
||||
if (m_is_awake)
|
||||
{
|
||||
std::array<u8, 64> figure_removed_response = {0x56, 0x09, 0x09, 0x00};
|
||||
memcpy(&figure_removed_response[4], figure.uid.data(), figure.uid.size());
|
||||
figure_removed_response[11] = generate_checksum(figure_removed_response, 11);
|
||||
m_figure_added_removed_responses.push(std::move(figure_removed_response));
|
||||
}
|
||||
figure.uid = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 rider_gate::load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file)
|
||||
{
|
||||
std::lock_guard lock(kamen_mutex);
|
||||
|
||||
u8 found_slot = 0xFF;
|
||||
|
||||
// mimics spot retaining on the portal
|
||||
for (auto i = 0; i < 7; i++)
|
||||
{
|
||||
if (!figures[i].present)
|
||||
{
|
||||
if (i < found_slot)
|
||||
{
|
||||
found_slot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_slot != 0xFF)
|
||||
{
|
||||
auto& figure = figures[found_slot];
|
||||
memcpy(figure.data.data(), buf.data(), buf.size());
|
||||
figure.kamen_file = std::move(in_file);
|
||||
figure.uid = {buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]};
|
||||
figure.present = true;
|
||||
|
||||
if (m_is_awake)
|
||||
{
|
||||
std::array<u8, 64> figure_added_response = {0x56, 0x09, 0x09, 0x01};
|
||||
memcpy(&figure_added_response[4], figure.uid.data(), figure.uid.size());
|
||||
figure_added_response[11] = generate_checksum(figure_added_response, 11);
|
||||
m_figure_added_removed_responses.push(std::move(figure_added_response));
|
||||
}
|
||||
}
|
||||
return found_slot;
|
||||
}
|
||||
|
||||
usb_device_kamen_rider::usb_device_kamen_rider(const std::array<u8, 7>& location)
|
||||
: usb_device_emulated(location)
|
||||
{
|
||||
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x200, 0x0, 0x0, 0x0, 0x40, 0x0E6F, 0x200A, 0x100, 0x1, 0x2, 0x3, 0x1});
|
||||
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x29, 0x1, 0x1, 0x0, 0x80, 0xFA}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x3, 0x40, 0x1}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x1, 0x3, 0x40, 0x1}));
|
||||
}
|
||||
|
||||
usb_device_kamen_rider::~usb_device_kamen_rider()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<usb_device> usb_device_kamen_rider::make_instance(u32, const std::array<u8, 7>& location)
|
||||
{
|
||||
return std::make_shared<usb_device_kamen_rider>(location);
|
||||
}
|
||||
|
||||
u16 usb_device_kamen_rider::get_num_emu_devices()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void usb_device_kamen_rider::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer)
|
||||
{
|
||||
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
|
||||
}
|
||||
|
||||
void usb_device_kamen_rider::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer)
|
||||
{
|
||||
ensure(buf_size == 0x40);
|
||||
|
||||
transfer->fake = true;
|
||||
transfer->expected_count = buf_size;
|
||||
transfer->expected_result = HC_CC_NOERR;
|
||||
|
||||
if (endpoint == 0x81)
|
||||
{
|
||||
// Respond after FF command
|
||||
transfer->expected_time = get_timestamp() + 1000;
|
||||
std::optional<std::array<u8, 64>> response = g_ridergate.pop_added_removed_response();
|
||||
if (response)
|
||||
{
|
||||
memcpy(buf, response.value().data(), 0x40);
|
||||
}
|
||||
else if (!m_queries.empty())
|
||||
{
|
||||
memcpy(buf, m_queries.front().data(), 0x20);
|
||||
m_queries.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
transfer->expected_count = 0;
|
||||
transfer->expected_result = EHCI_CC_HALTED;
|
||||
}
|
||||
}
|
||||
else if (endpoint == 0x01)
|
||||
{
|
||||
const u8 command = buf[2];
|
||||
const u8 sequence = buf[3];
|
||||
|
||||
std::array<u8, 64> q_result{};
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case 0xB0: // Wake
|
||||
{
|
||||
g_ridergate.wake_rider_gate(q_result, command, sequence);
|
||||
break;
|
||||
}
|
||||
case 0xC0:
|
||||
case 0xC3: // Color Commands
|
||||
{
|
||||
g_ridergate.get_blank_response(command, sequence, q_result);
|
||||
break;
|
||||
}
|
||||
case 0xD0: // Tag List
|
||||
{
|
||||
// Return list of figure UIDs, separated by an 09
|
||||
g_ridergate.get_list_tags(q_result, command, sequence);
|
||||
break;
|
||||
}
|
||||
case 0xD2: // Read
|
||||
{
|
||||
// Read 16 bytes from figure with UID buf[4] - buf[10]
|
||||
g_ridergate.query_block(q_result, command, sequence, &buf[4], buf[11], buf[12]);
|
||||
break;
|
||||
}
|
||||
case 0xD3:
|
||||
{
|
||||
// Write 16 bytes to figure with UID buf[4] - buf[10]
|
||||
g_ridergate.write_block(q_result, command, sequence, &buf[4], buf[11], buf[12], &buf[13]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
kamen_rider_log.error("Unhandled Query Type: 0x%02X", command);
|
||||
break;
|
||||
}
|
||||
m_queries.push(std::move(q_result));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/Io/usb_device.h"
|
||||
#include "Utilities/mutex.h"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
struct kamen_rider_figure
|
||||
{
|
||||
fs::file kamen_file;
|
||||
std::array<u8, 0x14 * 0x10> data{};
|
||||
std::array<u8, 7> uid{};
|
||||
bool present = false;
|
||||
void save();
|
||||
};
|
||||
|
||||
class rider_gate
|
||||
{
|
||||
public:
|
||||
void get_blank_response(u8 command, u8 sequence, std::array<u8, 64>& reply_buf);
|
||||
void wake_rider_gate(std::array<u8, 64>& replyBuf, u8 command, u8 sequence);
|
||||
void get_list_tags(std::array<u8, 64>& replyBuf, u8 command, u8 sequence);
|
||||
void query_block(std::array<u8, 64>& replyBuf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block);
|
||||
void write_block(std::array<u8, 64>& replyBuf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block, const u8* to_write_buf);
|
||||
std::optional<std::array<u8, 64>> pop_added_removed_response();
|
||||
|
||||
bool remove_figure(u8 position);
|
||||
u8 load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file);
|
||||
|
||||
protected:
|
||||
shared_mutex kamen_mutex;
|
||||
std::array<kamen_rider_figure, 8> figures{};
|
||||
|
||||
private:
|
||||
u8 generate_checksum(const std::array<u8, 64>& data, u32 num_of_bytes) const;
|
||||
kamen_rider_figure& get_figure_by_uid(const std::array<u8, 7> uid);
|
||||
|
||||
std::queue<std::array<u8, 64>> m_figure_added_removed_responses;
|
||||
|
||||
bool m_is_awake = false;
|
||||
};
|
||||
|
||||
extern rider_gate g_ridergate;
|
||||
|
||||
class usb_device_kamen_rider : public usb_device_emulated
|
||||
{
|
||||
public:
|
||||
usb_device_kamen_rider(const std::array<u8, 7>& location);
|
||||
~usb_device_kamen_rider();
|
||||
|
||||
static std::shared_ptr<usb_device> make_instance(u32 controller_index, const std::array<u8, 7>& location);
|
||||
static u16 get_num_emu_devices();
|
||||
|
||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||
|
||||
protected:
|
||||
std::queue<std::array<u8, 64>> m_queries;
|
||||
};
|
||||
|
|
@ -170,7 +170,7 @@ u16 PadHandlerBase::ConvertAxis(f32 value)
|
|||
|
||||
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
|
||||
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
|
||||
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
|
||||
{
|
||||
|
|
@ -208,21 +208,6 @@ void PadHandlerBase::init_configs()
|
|||
}
|
||||
}
|
||||
|
||||
pad_capabilities PadHandlerBase::get_capabilities(const std::string& /*pad_id*/)
|
||||
{
|
||||
return pad_capabilities
|
||||
{
|
||||
.has_led = b_has_rgb,
|
||||
.has_mono_led = b_has_led,
|
||||
.has_player_led = b_has_player_led,
|
||||
.has_battery_led = b_has_battery_led,
|
||||
.has_rumble = b_has_rumble,
|
||||
.has_accel = b_has_motion,
|
||||
.has_gyro = b_has_motion,
|
||||
.has_pressure_sensitivity = b_has_pressure_intensity_button
|
||||
};
|
||||
}
|
||||
|
||||
cfg_pad* PadHandlerBase::get_config(const std::string& pad_id)
|
||||
{
|
||||
int index = 0;
|
||||
|
|
@ -346,13 +331,12 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri
|
|||
if (callback)
|
||||
{
|
||||
pad_preview_values preview_values = get_preview_values(data);
|
||||
pad_capabilities capabilities = get_capabilities(pad_id);
|
||||
const u32 battery_level = get_battery_level(pad_id);
|
||||
|
||||
if (pressed_button.value > 0)
|
||||
callback(pressed_button.value, pressed_button.name, pad_id, battery_level, std::move(preview_values), std::move(capabilities));
|
||||
callback(pressed_button.value, pressed_button.name, pad_id, battery_level, std::move(preview_values));
|
||||
else
|
||||
callback(0, "", pad_id, battery_level, std::move(preview_values), std::move(capabilities));
|
||||
callback(0, "", pad_id, battery_level, std::move(preview_values));
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -81,20 +81,8 @@ struct pad_list_entry
|
|||
{}
|
||||
};
|
||||
|
||||
struct pad_capabilities
|
||||
{
|
||||
bool has_led = false;
|
||||
bool has_mono_led = false;
|
||||
bool has_player_led = false;
|
||||
bool has_battery_led = false;
|
||||
bool has_rumble = false;
|
||||
bool has_accel = false;
|
||||
bool has_gyro = false;
|
||||
bool has_pressure_sensitivity = false;
|
||||
};
|
||||
|
||||
using pad_preview_values = std::array<int, 6>;
|
||||
using pad_callback = std::function<void(u16 /*button_value*/, std::string /*button_name*/, std::string /*pad_name*/, u32 /*battery_level*/, pad_preview_values, pad_capabilities)>;
|
||||
using pad_callback = std::function<void(u16 /*button_value*/, std::string /*button_name*/, std::string /*pad_name*/, u32 /*battery_level*/, pad_preview_values /*preview_values*/)>;
|
||||
using pad_fail_callback = std::function<void(std::string /*pad_name*/)>;
|
||||
|
||||
using motion_preview_values = std::array<u16, 4>;
|
||||
|
|
@ -338,8 +326,6 @@ public:
|
|||
bool has_analog_limiter_button() const { return b_has_analog_limiter_button; }
|
||||
bool has_orientation() const { return b_has_orientation; }
|
||||
|
||||
virtual pad_capabilities get_capabilities(const std::string& /*pad_id*/);
|
||||
|
||||
u16 NormalizeStickInput(u16 raw_value, s32 threshold, s32 multiplier, bool ignore_threshold = false) const;
|
||||
void convert_stick_values(u16& x_out, u16& y_out, s32 x_in, s32 y_in, u32 deadzone, u32 anti_deadzone, u32 padsquircling) const;
|
||||
void set_trigger_recognition_mode(trigger_recognition_mode mode) { m_trigger_recognition_mode = mode; }
|
||||
|
|
|
|||
|
|
@ -88,8 +88,8 @@ struct cfg_pad final : cfg::node
|
|||
cfg::uint<0, 1000000> rstick_anti_deadzone{ this, "Right Stick Anti-Deadzone", 0 };
|
||||
cfg::uint<0, 1000000> ltriggerthreshold{ this, "Left Trigger Threshold", 0 };
|
||||
cfg::uint<0, 1000000> rtriggerthreshold{ this, "Right Trigger Threshold", 0 };
|
||||
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 4000 };
|
||||
cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 4000 };
|
||||
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 8000 };
|
||||
cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 8000 };
|
||||
|
||||
cfg::uint<0, 255> colorR{ this, "Color Value R", 0 };
|
||||
cfg::uint<0, 255> colorG{ this, "Color Value G", 0 };
|
||||
|
|
|
|||
|
|
@ -217,12 +217,6 @@ bool Pad::get_analog_limiter_button_active(bool is_toggle_mode, u32 player_id)
|
|||
|
||||
const Button& analog_limiter_button = m_buttons[m_analog_limiter_button_index];
|
||||
|
||||
if (analog_limiter_button.m_key_codes.empty())
|
||||
{
|
||||
// Active by default if no button was assigned
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_toggle_mode)
|
||||
{
|
||||
const bool pressed = analog_limiter_button.m_pressed;
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ namespace vm
|
|||
|
||||
void reservation_update(u32 addr)
|
||||
{
|
||||
u64 old = -1;
|
||||
const auto cpu = get_current_cpu_thread();
|
||||
|
||||
const bool had_wait = cpu && cpu->state & cpu_flag::wait;
|
||||
|
|
@ -125,6 +126,8 @@ namespace vm
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
old = rtime;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -547,13 +550,6 @@ namespace vm
|
|||
{
|
||||
to_clear = for_all_range_locks(to_clear & ~get_range_lock_bits(true), [&](u64 addr2, u32 size2)
|
||||
{
|
||||
constexpr u32 range_size_loc = vm::range_pos - 32;
|
||||
|
||||
if ((size2 >> range_size_loc) == (vm::range_readable >> vm::range_pos))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Split and check every 64K page separately
|
||||
for (u64 hi = addr2 >> 16, max = (addr2 + size2 - 1) >> 16; hi <= max; hi++)
|
||||
{
|
||||
|
|
@ -957,7 +953,7 @@ namespace vm
|
|||
return true;
|
||||
}
|
||||
|
||||
static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm, std::vector<std::pair<u64, u64>>& unmap_events, bool is_block_termination = false)
|
||||
static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm, std::vector<std::pair<u64, u64>>& unmap_events)
|
||||
{
|
||||
perf_meter<"PAGE_UNm"_u64> perf0;
|
||||
|
||||
|
|
@ -1028,11 +1024,7 @@ namespace vm
|
|||
ppu_remove_hle_instructions(addr, size);
|
||||
|
||||
// Actually unmap memory
|
||||
if (is_block_termination && (!shm || is_noop))
|
||||
{
|
||||
// We can skip it if the block is freed
|
||||
}
|
||||
else if (is_noop)
|
||||
if (is_noop)
|
||||
{
|
||||
std::memset(g_sudo_addr + addr, 0, size);
|
||||
}
|
||||
|
|
@ -1338,17 +1330,7 @@ namespace vm
|
|||
const auto size = it->second.first;
|
||||
|
||||
std::vector<std::pair<u64, u64>> event_data;
|
||||
ensure(size == _page_unmap(it->first, size, this->flags, it->second.second.get(), unmapped ? *unmapped : event_data, true));
|
||||
|
||||
if (it->second.second && addr < 0xE0000000)
|
||||
{
|
||||
if (it->second.second.use_count() != 1)
|
||||
{
|
||||
fmt::throw_exception("External memory usage at block 0x%x (addr=0x%x, size=0x%x)", this->addr, it->first, size);
|
||||
}
|
||||
|
||||
it->second.second.reset();
|
||||
}
|
||||
ensure(size == _page_unmap(it->first, size, this->flags, it->second.second.get(), unmapped ? *unmapped : event_data));
|
||||
|
||||
it = next;
|
||||
}
|
||||
|
|
@ -1359,8 +1341,6 @@ namespace vm
|
|||
#ifdef _WIN32
|
||||
m_common->unmap_critical(vm::get_super_ptr(addr));
|
||||
#endif
|
||||
ensure(m_common.use_count() == 1);
|
||||
m_common.reset();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1372,7 +1352,6 @@ namespace vm
|
|||
block_t::~block_t()
|
||||
{
|
||||
ensure(!is_valid());
|
||||
ensure(!m_common || m_common.use_count() == 1);
|
||||
}
|
||||
|
||||
u32 block_t::alloc(const u32 orig_size, const std::shared_ptr<utils::shm>* src, u32 align, u64 flags)
|
||||
|
|
@ -2268,11 +2247,7 @@ namespace vm
|
|||
|
||||
for (auto& block : g_locations)
|
||||
{
|
||||
if (block)
|
||||
{
|
||||
_unmap_block(block);
|
||||
ensure(block.use_count() == 1);
|
||||
}
|
||||
if (block) _unmap_block(block);
|
||||
}
|
||||
|
||||
g_locations.clear();
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ namespace vm
|
|||
bool check_addr(u32 addr, u8 flags, u32 size);
|
||||
|
||||
template <u32 Size = 1>
|
||||
inline bool check_addr(u32 addr, u8 flags = page_readable)
|
||||
bool check_addr(u32 addr, u8 flags = page_readable)
|
||||
{
|
||||
extern std::array<memory_page, 0x100000000 / 4096> g_pages;
|
||||
|
||||
|
|
@ -94,16 +94,6 @@ namespace vm
|
|||
return !(~g_pages[addr / 4096] & (flags | page_allocated));
|
||||
}
|
||||
|
||||
// Like check_addr but should only be used in lock-free context with care
|
||||
inline std::pair<bool, u8> get_addr_flags(u32 addr) noexcept
|
||||
{
|
||||
extern std::array<memory_page, 0x100000000 / 4096> g_pages;
|
||||
|
||||
const u8 flags = g_pages[addr / 4096].load();
|
||||
|
||||
return std::make_pair(!!(flags & page_allocated), flags);
|
||||
}
|
||||
|
||||
// Read string in a safe manner (page aware) (bool true = if null-termination)
|
||||
bool read_string(u32 addr, u32 max_size, std::string& out_string, bool check_pages = true) noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#include "util/tsc.hpp"
|
||||
#include <functional>
|
||||
|
||||
extern bool g_use_rtm;
|
||||
extern u64 g_rtm_tx_limit2;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
extern "C"
|
||||
{
|
||||
|
|
@ -140,7 +143,7 @@ namespace vm
|
|||
void reservation_op_internal(u32 addr, std::function<bool()> func);
|
||||
|
||||
template <bool Ack = false, typename CPU, typename T, typename AT = u32, typename F>
|
||||
inline SAFE_BUFFERS(auto) reservation_op(CPU& /*cpu*/, _ptr_base<T, AT> ptr, F op)
|
||||
inline SAFE_BUFFERS(auto) reservation_op(CPU& cpu, _ptr_base<T, AT> ptr, F op)
|
||||
{
|
||||
// Atomic operation will be performed on aligned 128 bytes of data, so the data size and alignment must comply
|
||||
static_assert(sizeof(T) <= 128 && alignof(T) == sizeof(T), "vm::reservation_op: unsupported type");
|
||||
|
|
@ -159,6 +162,188 @@ namespace vm
|
|||
auto& res = vm::reservation_acquire(addr);
|
||||
//_m_prefetchw(&res);
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
if (g_use_rtm)
|
||||
{
|
||||
// Stage 1: single optimistic transaction attempt
|
||||
unsigned status = -1;
|
||||
u64 _old = 0;
|
||||
|
||||
auto stamp0 = utils::get_tsc(), stamp1 = stamp0, stamp2 = stamp0;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__asm__ goto ("xbegin %l[stage2];" ::: "memory" : stage2);
|
||||
#else
|
||||
status = _xbegin();
|
||||
if (status == umax)
|
||||
#endif
|
||||
{
|
||||
if (res & rsrv_unique_lock)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend; mov $-1, %%eax;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
goto stage2;
|
||||
}
|
||||
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<F, T&>>)
|
||||
{
|
||||
std::invoke(op, *sptr);
|
||||
const u64 old_time = res.fetch_add(128);
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
if constexpr (Ack)
|
||||
reservation_notifier_notify(addr, old_time);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto result = std::invoke(op, *sptr))
|
||||
{
|
||||
const u64 old_time = res.fetch_add(128);
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
if constexpr (Ack)
|
||||
reservation_notifier_notify(addr, old_time);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage2:
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("mov %%eax, %0;" : "=r" (status) :: "memory");
|
||||
#endif
|
||||
stamp1 = utils::get_tsc();
|
||||
|
||||
// Stage 2: try to lock reservation first
|
||||
_old = res.fetch_add(1);
|
||||
|
||||
// Compute stamps excluding memory touch
|
||||
stamp2 = utils::get_tsc() - (stamp1 - stamp0);
|
||||
|
||||
// Start lightened transaction
|
||||
for (; !(_old & vm::rsrv_unique_lock) && stamp2 - stamp0 <= g_rtm_tx_limit2; stamp2 = utils::get_tsc())
|
||||
{
|
||||
if (cpu.has_pause_flag())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__asm__ goto ("xbegin %l[retry];" ::: "memory" : retry);
|
||||
#else
|
||||
status = _xbegin();
|
||||
|
||||
if (status != umax) [[unlikely]]
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<F, T&>>)
|
||||
{
|
||||
std::invoke(op, *sptr);
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
res += 127;
|
||||
if (Ack)
|
||||
reservation_notifier_notify(addr, _old);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto result = std::invoke(op, *sptr))
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
res += 127;
|
||||
if (Ack)
|
||||
reservation_notifier_notify(addr, _old);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("xend;" ::: "memory");
|
||||
#else
|
||||
_xend();
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
#ifndef _MSC_VER
|
||||
__asm__ volatile ("mov %%eax, %0;" : "=r" (status) :: "memory");
|
||||
#endif
|
||||
|
||||
if (!status)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Stage 3: all failed, heavyweight fallback (see comments at the bottom)
|
||||
if constexpr (std::is_void_v<std::invoke_result_t<F, T&>>)
|
||||
{
|
||||
vm::reservation_op_internal(addr, [&]
|
||||
{
|
||||
std::invoke(op, *sptr);
|
||||
return true;
|
||||
});
|
||||
|
||||
if constexpr (Ack)
|
||||
reservation_notifier_notify(addr, _old);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result = std::invoke_result_t<F, T&>();
|
||||
|
||||
vm::reservation_op_internal(addr, [&]
|
||||
{
|
||||
if ((result = std::invoke(op, *sptr)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (Ack && result)
|
||||
reservation_notifier_notify(addr, _old);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static_cast<void>(cpu);
|
||||
#endif /* ARCH_X64 */
|
||||
|
||||
// Lock reservation and perform heavyweight lock
|
||||
reservation_shared_lock_internal(res);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include "Emu/Cell/PPUCallback.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/Modules/cellSysutil.h"
|
||||
#include "np_helpers.h"
|
||||
|
||||
LOG_CHANNEL(sceNp2);
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ void generic_async_transaction_context::set_result_and_wake(error_code err)
|
|||
|
||||
tus_ctx::tus_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase)
|
||||
{
|
||||
ensure(communicationId && np::validate_communication_id(*communicationId), "tus_ctx::tus_ctx: Invalid SceNpCommunicationId");
|
||||
ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
|
||||
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
|
||||
memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase));
|
||||
}
|
||||
|
|
@ -97,7 +96,7 @@ bool destroy_tus_transaction_context(s32 ctx_id)
|
|||
|
||||
score_ctx::score_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase)
|
||||
{
|
||||
ensure(communicationId && np::validate_communication_id(*communicationId), "score_ctx::score_ctx: Invalid SceNpCommunicationId");
|
||||
ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
|
||||
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
|
||||
memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase));
|
||||
}
|
||||
|
|
@ -141,7 +140,7 @@ bool destroy_score_transaction_context(s32 ctx_id)
|
|||
|
||||
match2_ctx::match2_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase, s32 option)
|
||||
{
|
||||
ensure(communicationId && np::validate_communication_id(*communicationId), "match2_ctx::match2_ctx: Invalid SceNpCommunicationId");
|
||||
ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
|
||||
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
|
||||
memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase));
|
||||
|
||||
|
|
@ -150,7 +149,7 @@ match2_ctx::match2_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<
|
|||
}
|
||||
u16 create_match2_context(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase, s32 option)
|
||||
{
|
||||
sceNp2.notice("Creating match2 context with communicationId: <%s>", std::string_view(communicationId->data, 9));
|
||||
sceNp2.notice("Creating match2 context with communicationId: <%s>", static_cast<const char*>(communicationId->data));
|
||||
return static_cast<u16>(idm::make<match2_ctx>(communicationId, passphrase, option));
|
||||
}
|
||||
bool destroy_match2_context(u16 ctx_id)
|
||||
|
|
@ -168,7 +167,7 @@ shared_ptr<match2_ctx> get_match2_context(u16 ctx_id)
|
|||
|
||||
lookup_title_ctx::lookup_title_ctx(vm::cptr<SceNpCommunicationId> communicationId)
|
||||
{
|
||||
ensure(communicationId && np::validate_communication_id(*communicationId), "lookup_title_ctx::lookup_title_ctx: Invalid SceNpCommunicationId");
|
||||
ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
|
||||
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
|
||||
}
|
||||
s32 create_lookup_title_context(vm::cptr<SceNpCommunicationId> communicationId)
|
||||
|
|
|
|||
|
|
@ -646,7 +646,7 @@ namespace np
|
|||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
strcpy_trunc(ifr.ifr_name, it->ifr_name);
|
||||
strcpy(ifr.ifr_name, it->ifr_name);
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0)
|
||||
{
|
||||
if (!(ifr.ifr_flags & IFF_LOOPBACK))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#include "Emu/Cell/Modules/sceNp.h"
|
||||
#include "stdafx.h"
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
|
@ -23,15 +22,9 @@ namespace np
|
|||
return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
|
||||
}
|
||||
|
||||
bool validate_communication_id(const SceNpCommunicationId& com_id)
|
||||
{
|
||||
return std::all_of(com_id.data, com_id.data + 9, [](char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); }) && com_id.num <= 99;
|
||||
}
|
||||
|
||||
std::string communication_id_to_string(const SceNpCommunicationId& communicationId)
|
||||
{
|
||||
std::string_view com_id_data(communicationId.data, 9);
|
||||
return fmt::format("%s_%02d", com_id_data, communicationId.num);
|
||||
return fmt::format("%s_%02d", communicationId.data, communicationId.num);
|
||||
}
|
||||
|
||||
void strings_to_userinfo(std::string_view npid, std::string_view online_name, std::string_view avatar_url, SceNpUserInfo& user_info)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue