Merge branch 'master' of eden:eden-emu/eden into feat/android-emuready

This commit is contained in:
Producdevity 2025-07-23 17:57:24 +02:00
commit 4155efc7b9
222 changed files with 8410 additions and 7277 deletions

View file

@ -3,7 +3,6 @@
# SPDX-FileCopyrightText: 2025 eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
export ARCH="$(uname -m)"
case "$1" in
amd64|"")
@ -11,15 +10,15 @@ case "$1" in
ARCH="amd64_v3"
ARCH_FLAGS="-march=x86-64-v3"
;;
steamdeck)
steamdeck|zen2)
echo "Making Steam Deck (Zen 2) optimized build of Eden"
ARCH="steamdeck"
ARCH_FLAGS="-march=znver2 -mtune=znver2"
;;
rog-ally|allyx)
rog-ally|allyx|zen4)
echo "Making ROG Ally X (Zen 4) optimized build of Eden"
ARCH="rog-ally-x"
ARCH_FLAGS="-march=znver3 -mtune=znver4" # GH actions runner is a Zen 3 CPU, so a small workaround
ARCH_FLAGS="-march=znver4 -mtune=znver4"
;;
legacy)
echo "Making amd64 generic build of Eden"
@ -36,15 +35,21 @@ case "$1" in
ARCH=armv9
ARCH_FLAGS="-march=armv9-a -mtune=generic -w"
;;
native)
echo "Making native build of Eden"
ARCH="$(uname -m)"
ARCH_FLAGS="-march=native -mtune=native"
;;
*)
echo "Invalid target $1 specified, must be one of native, amd64, steamdeck, zen2, allyx, rog-ally, zen4, legacy, aarch64, armv9"
exit 1
;;
esac
export ARCH_FLAGS="$ARCH_FLAGS -O3"
NPROC="$2"
if [ -z "$NPROC" ]; then
NPROC="$(nproc)"
else
shift
fi
if [ "$1" != "" ]; then shift; fi
@ -60,11 +65,27 @@ if [ "$DEVEL" != "true" ]; then
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DENABLE_QT_UPDATE_CHECKER=ON)
fi
if [ "$USE_WEBENGINE" = "true" ]; then
WEBENGINE=ON
else
WEBENGINE=OFF
fi
if [ "$USE_MULTIMEDIA" = "false" ]; then
MULTIMEDIA=OFF
else
MULTIMEDIA=ON
fi
if [ -z "$BUILD_TYPE" ]; then
export BUILD_TYPE="Release"
fi
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
mkdir -p build && cd build
cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_QT_TRANSLATION=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
@ -74,8 +95,8 @@ cmake .. -G Ninja \
-DYUZU_USE_BUNDLED_SDL2=OFF \
-DYUZU_USE_EXTERNAL_SDL2=ON \
-DYUZU_TESTS=OFF \
-DYUZU_USE_QT_MULTIMEDIA=ON \
-DYUZU_USE_QT_WEB_ENGINE=ON \
-DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \
-DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \
-DYUZU_USE_FASTER_LD=ON \
-DYUZU_ENABLE_LTO=ON \
"${EXTRA_CMAKE_FLAGS[@]}"

View file

@ -16,11 +16,11 @@ case "$1" in
echo "Packaging amd64-v3 optimized build of Eden"
ARCH="amd64_v3"
;;
steamdeck)
steamdeck|zen2)
echo "Packaging Steam Deck (Zen 2) optimized build of Eden"
ARCH="steamdeck"
;;
rog-ally|allyx)
rog-ally|allyx|zen4)
echo "Packaging ROG Ally X (Zen 4) optimized build of Eden"
ARCH="rog-ally-x"
;;
@ -36,6 +36,11 @@ case "$1" in
echo "Packaging armv9-a build of Eden"
ARCH=armv9
;;
native)
echo "Packaging native build of Eden"
ARCH="$BASE_ARCH"
;;
esac
export BUILDDIR="$2"

View file

@ -17,16 +17,32 @@ else
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DYUZU_USE_BUNDLED_QT=OFF)
fi
if [ -z "$BUILD_TYPE" ]; then
export BUILD_TYPE="Release"
fi
if [ "$WINDEPLOYQT" == "" ]; then
echo "You must supply the WINDEPLOYQT environment variable."
exit 1
fi
if [ "$USE_WEBENGINE" = "true" ]; then
WEBENGINE=ON
else
WEBENGINE=OFF
fi
if [ "$USE_MULTIMEDIA" = "false" ]; then
MULTIMEDIA=OFF
else
MULTIMEDIA=ON
fi
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
mkdir -p build && cd build
cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_QT_TRANSLATION=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DYUZU_USE_BUNDLED_SDL2=OFF \
@ -34,8 +50,8 @@ cmake .. -G Ninja \
-DYUZU_TESTS=OFF \
-DYUZU_CMD=OFF \
-DYUZU_ROOM_STANDALONE=OFF \
-DYUZU_USE_QT_MULTIMEDIA=ON \
-DYUZU_USE_QT_WEB_ENGINE=ON \
-DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \
-DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \
-DYUZU_ENABLE_LTO=ON \
"${EXTRA_CMAKE_FLAGS[@]}"

View file

@ -1,19 +0,0 @@
echo off
call C:\tools\cygwin\cygwinsetup.exe -q -P autoconf,automake,libtool,make,pkg-config
REM Create wrapper batch files for Cygwin tools in a directory that will be in PATH
REM uncomment this for first-run only
REM call mkdir C:\cygwin-wrappers
REM Create autoconf.bat wrapper
call echo @echo off > C:\cygwin-wrappers\autoconf.bat
call echo C:\tools\cygwin\bin\bash.exe -l -c "autoconf %%*" >> C:\cygwin-wrappers\autoconf.bat
REM Add other wrappers if needed for other Cygwin tools
call echo @echo off > C:\cygwin-wrappers\automake.bat
call echo C:\tools\cygwin\bin\bash.exe -l -c "automake %%*" >> C:\cygwin-wrappers\automake.bat
REM Add the wrappers directory to PATH
call echo C:\cygwin-wrappers>>"%GITHUB_PATH%"
call echo C:\tools\cygwin\bin>>"%GITHUB_PATH%"

View file

@ -3,7 +3,7 @@
$ErrorActionPreference = "Stop"
$VulkanSDKVer = "1.3.250.1"
$VulkanSDKVer = "1.4.321.1"
$ExeFile = "VulkanSDK-$VulkanSDKVer-Installer.exe"
$Uri = "https://sdk.lunarg.com/sdk/download/$VulkanSDKVer/windows/$ExeFile"
$Destination = "./$ExeFile"

View file

@ -1,7 +0,0 @@
# This is specific to the CI runner and is unlikely to work on your machine.
QTDIR="/c/Qt/6.9.0/msvc2022_64"
export QT_ROOT_DIR="$QTDIR"
export QT_PLUGIN_PATH="$QTDIR/plugins"
export QML2_IMPORT_PATH="$QTDIR/qml"
export PATH="${PATH};$QTDIR/bin"

4
.gitignore vendored
View file

@ -5,7 +5,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# Build directory
[Bb]uild*/
/[Bb]uild*/
doc-build/
AppDir/
uruntime
@ -33,6 +33,7 @@ CMakeLists.txt.user*
# Visual Studio CMake settings
CMakeSettings.json
.cache/
# OSX global filetypes
# Created by Finder or Spotlight in directories for various OS functionality (indexing, etc)
@ -51,4 +52,3 @@ Thumbs.db
eden-windows-msvc
artifacts
*.AppImage*
*.patch

4
.gitmodules vendored
View file

@ -12,7 +12,7 @@
url = https://github.com/KhronosGroup/Vulkan-Headers.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
url = https://github.com/Lizzie841/xbyak.git
[submodule "opus"]
path = externals/opus
url = https://github.com/xiph/opus.git
@ -51,7 +51,7 @@
url = https://github.com/Lizzie841/unordered_dense.git
[submodule "externals/dynarmic/externals/xbyak"]
path = externals/dynarmic/externals/xbyak
url = https://github.com/herumi/xbyak.git
url = https://github.com/Lizzie841/xbyak.git
[submodule "externals/dynarmic/externals/zycore-c"]
path = externals/dynarmic/externals/zycore-c
url = https://github.com/zyantific/zycore-c.git

View file

@ -0,0 +1,80 @@
diff --git a/quazip/quazipdir.cpp b/quazip/quazipdir.cpp
index d43f1c1..eb24bf1 100644
--- a/quazip/quazipdir.cpp
+++ b/quazip/quazipdir.cpp
@@ -293,8 +293,8 @@ bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1,
}
template<typename TFileInfoList>
-bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
- QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const
+bool QuaZipDirPrivate::entryInfoList(QStringList _nameFilters,
+ QDir::Filters _filter, QDir::SortFlags sort, TFileInfoList &result) const
{
QString basePath = simplePath();
if (!basePath.isEmpty())
@@ -305,12 +305,12 @@ bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
if (!zip->goToFirstFile()) {
return zip->getZipError() == UNZ_OK;
}
- QDir::Filters fltr = filter;
+ QDir::Filters fltr = _filter;
if (fltr == QDir::NoFilter)
fltr = this->filter;
if (fltr == QDir::NoFilter)
fltr = QDir::AllEntries;
- QStringList nmfltr = nameFilters;
+ QStringList nmfltr = _nameFilters;
if (nmfltr.isEmpty())
nmfltr = this->nameFilters;
QSet<QString> dirsFound;
diff --git a/quazip/quazipfile.cpp b/quazip/quazipfile.cpp
index 4a5f2f9..f7865f5 100644
--- a/quazip/quazipfile.cpp
+++ b/quazip/quazipfile.cpp
@@ -241,14 +241,14 @@ void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs
p->caseSensitivity=cs;
}
-void QuaZipFilePrivate::setZipError(int zipError) const
+void QuaZipFilePrivate::setZipError(int _zipError) const
{
QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
- fakeThis->zipError=zipError;
- if(zipError==UNZ_OK)
+ fakeThis->zipError = _zipError;
+ if(_zipError == UNZ_OK)
q->setErrorString(QString());
else
- q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError));
+ q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(_zipError));
}
bool QuaZipFile::open(OpenMode mode)
diff --git a/quazip/unzip.c b/quazip/unzip.c
index a39365d..ee7b487 100644
--- a/quazip/unzip.c
+++ b/quazip/unzip.c
@@ -1054,7 +1054,7 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
/* ZIP64 extra fields */
if (headerId == 0x0001)
{
- uLong uL;
+ uLong _uL;
if(file_info.uncompressed_size == (ZPOS64_T)0xFFFFFFFFu)
{
@@ -1078,7 +1078,7 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
if(file_info.disk_num_start == 0xFFFFFFFFu)
{
/* Disk Start Number */
- if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ if (unz64local_getLong(&s->z_filefunc, s->filestream, &_uL) != UNZ_OK)
err=UNZ_ERRNO;
}
@@ -2151,3 +2151,4 @@ int ZEXPORT unzClearFlags(unzFile file, unsigned flags)
s->flags &= ~flags;
return UNZ_OK;
}
+

View file

@ -0,0 +1,26 @@
diff --git a/quazip/minizip_crypt.h b/quazip/minizip_crypt.h
index 2e833f7..ea9d277 100644
--- a/quazip/minizip_crypt.h
+++ b/quazip/minizip_crypt.h
@@ -90,13 +90,14 @@ static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t FAR
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
# endif
-static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
- const char *passwd; /* password string */
- unsigned char *buf; /* where to write header */
- int bufSize;
- unsigned long* pkeys;
- const z_crc_t FAR * pcrc_32_tab;
- unsigned long crcForCrypting;
+static int crypthead(
+ const char *passwd, /* password string */
+ unsigned char *buf, /* where to write header */
+ int bufSize,
+ unsigned long* pkeys,
+ const z_crc_t FAR * pcrc_32_tab,
+ unsigned long crcForCrypting
+)
{
int n; /* index in random header */
int t; /* temporary */

View file

@ -0,0 +1,19 @@
diff --git a/quazip/zip.c b/quazip/zip.c
index 7788b88..f4e21aa 100644
--- a/quazip/zip.c
+++ b/quazip/zip.c
@@ -645,6 +645,14 @@ local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
return relativeOffset;
}
+// compilers hate this ONE SIMPLE TRICK!
+static int LoadCentralDirectoryRecord(zip64_internal* pziinit);
+static int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local, uLong version_to_extract);
+static int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip);
+static int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip);
+static int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip);
+static int Write_GlobalComment(zip64_internal* zi, const char* global_comment);
+
int LoadCentralDirectoryRecord(zip64_internal* pziinit)
{
int err=ZIP_OK;

View file

@ -0,0 +1,400 @@
"Debloats" QuaZip by removing some unneeded stuff (Qt <6, bzip2, emscripten...)
This is completely optional.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b376fb2..4aac4ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,64 +3,16 @@ cmake_minimum_required(VERSION 3.15...3.18)
project(QuaZip VERSION 1.5)
-include(cmake/clone-repo.cmake)
-
set(QUAZIP_LIB_VERSION ${QuaZip_VERSION})
set(QUAZIP_LIB_SOVERSION 1.5.0)
-if(EMSCRIPTEN)
- #option(ZLIB_INCLUDE "Path to include dir" "")
- #option(ZLIB_LIBRARY "Path to library dir" "")
- option(BUILD_SHARED_LIBS "" OFF)
- option(QUAZIP_INSTALL "" OFF)
- option(QUAZIP_USE_QT_ZLIB "" OFF)
- option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF)
-else()
- option(BUILD_SHARED_LIBS "" ON)
- option(QUAZIP_INSTALL "" ON)
- option(QUAZIP_USE_QT_ZLIB "" OFF)
- option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF)
-endif()
+option(BUILD_SHARED_LIBS "" ON)
+option(QUAZIP_INSTALL "" ON)
+option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF)
OPTION(ZLIB_CONST "Sets ZLIB_CONST preprocessor definition" OFF)
-# Make BZIP2 optional
-option(QUAZIP_BZIP2 "Enables BZIP2 compression" ON)
-option(QUAZIP_BZIP2_STDIO "Output BZIP2 errors to stdio" ON)
-
-option(QUAZIP_FETCH_LIBS "Enables fetching third-party libraries if not found" ${WIN32})
-option(QUAZIP_FORCE_FETCH_LIBS "Enables fetching third-party libraries always" OFF)
-
-if (QUAZIP_USE_QT_ZLIB AND BUILD_SHARED_LIBS)
- message(FATAL_ERROR "Using BUILD_SHARED_LIBS=ON together with QUAZIP_USE_QT_ZLIB=ON is not supported." )
-endif()
-
-# Set the default value of `${QUAZIP_QT_MAJOR_VERSION}`.
-# We search quietly for Qt6, Qt5 and Qt4 in that order.
-# Qt6 and Qt5 provide config files for CMake.
-# Qt4 relies on `FindQt4.cmake`.
-find_package(
- QT NAMES Qt6 Qt5
- QUIET COMPONENTS Core
-)
-if (NOT QT_FOUND)
- find_package(Qt4 QUIET COMPONENTS QtCore)
- if (Qt4_FOUND)
- set(QT_VERSION_MAJOR 4)
- else()
- # If neither 6, 5 nor 4 are found, we default to 5.
- # The setup will fail further down.
- set(QT_VERSION_MAJOR 5)
- endif()
-endif()
-
-set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}")
-
-if (QUAZIP_QT_MAJOR_VERSION EQUAL 6)
- set(CMAKE_CXX_STANDARD 17)
-else()
- set(CMAKE_CXX_STANDARD 14)
-endif()
+set(CMAKE_CXX_STANDARD 17)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RELEASE)
@@ -77,92 +29,17 @@ set(QUAZIP_LIB_TARGET_NAME QuaZip)
set(QUAZIP_DIR_NAME QuaZip-Qt${QUAZIP_QT_MAJOR_VERSION}-${QUAZIP_LIB_VERSION})
set(QUAZIP_PACKAGE_NAME QuaZip-Qt${QUAZIP_QT_MAJOR_VERSION})
-message(STATUS "QUAZIP_QT_MAJOR_VERSION set to ${QUAZIP_QT_MAJOR_VERSION}")
-message(STATUS "CMAKE_CXX_STANDARD set to ${CMAKE_CXX_STANDARD}")
-
-if(QUAZIP_QT_MAJOR_VERSION EQUAL 6)
- find_package(Qt6 REQUIRED COMPONENTS Core Core5Compat
- OPTIONAL_COMPONENTS Network Test)
- message(STATUS "Found Qt version ${Qt6_VERSION} at ${Qt6_DIR}")
- set(QUAZIP_QT_ZLIB_COMPONENT BundledZLIB)
- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT ZlibPrivate)
- set(QUAZIP_LIB_LIBRARIES Qt6::Core Qt6::Core5Compat)
- set(QUAZIP_TEST_QT_LIBRARIES Qt6::Core Qt6::Core5Compat Qt6::Network Qt6::Test)
- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt6Core")
-elseif(QUAZIP_QT_MAJOR_VERSION EQUAL 5)
- find_package(Qt5 REQUIRED COMPONENTS Core
- OPTIONAL_COMPONENTS Network Test)
- message(STATUS "Found Qt version ${Qt5_VERSION} at ${Qt5_DIR}")
- set(QUAZIP_QT_ZLIB_COMPONENT Zlib)
- set(QUAZIP_LIB_LIBRARIES Qt5::Core)
- set(QUAZIP_TEST_QT_LIBRARIES Qt5::Core Qt5::Network Qt5::Test)
- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt5Core")
-elseif(QUAZIP_QT_MAJOR_VERSION EQUAL 4)
- find_package(Qt4 4.5.0 REQUIRED COMPONENTS QtCore
- OPTIONAL_COMPONENTS QtNetwork QtTest)
- set(QUAZIP_QT_ZLIB_COMPONENT Zlib)
- set(QUAZIP_LIB_LIBRARIES Qt4::QtCore)
- set(QUAZIP_TEST_QT_LIBRARIES Qt4::QtCore Qt4::QtNetwork Qt4::QtTest)
- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, QtCore")
-else()
- message(FATAL_ERROR "Qt version ${QUAZIP_QT_MAJOR_VERSION} is not supported")
-endif()
-
-message(STATUS "Using Qt version ${QUAZIP_QT_MAJOR_VERSION}")
-
-set(QUAZIP_QT_ZLIB_USED OFF)
-if(QUAZIP_USE_QT_ZLIB)
- find_package(Qt${QUAZIP_QT_MAJOR_VERSION} OPTIONAL_COMPONENTS ${QUAZIP_QT_ZLIB_COMPONENT})
- set(QUAZIP_QT_ZLIB_COMPONENT_FOUND Qt${QUAZIP_QT_MAJOR_VERSION}${QUAZIP_QT_ZLIB_COMPONENT}_FOUND)
- if (DEFINED QUAZIP_QT_ZLIB_HEADER_COMPONENT)
- find_package(Qt${QUAZIP_QT_MAJOR_VERSION} OPTIONAL_COMPONENTS ${QUAZIP_QT_ZLIB_HEADER_COMPONENT})
- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND Qt${QUAZIP_QT_MAJOR_VERSION}${QUAZIP_QT_ZLIB_HEADER_COMPONENT}_FOUND)
- else()
- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND ON)
- endif()
- if(QUAZIP_QT_ZLIB_COMPONENT_FOUND AND QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND)
- message(STATUS "Qt component ${QUAZIP_QT_ZLIB_COMPONENT} found")
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} Qt${QUAZIP_QT_MAJOR_VERSION}::${QUAZIP_QT_ZLIB_COMPONENT})
- if(DEFINED QUAZIP_QT_ZLIB_HEADER_COMPONENT)
- message(STATUS "Qt component ${QUAZIP_QT_ZLIB_HEADER_COMPONENT} found")
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} Qt${QUAZIP_QT_MAJOR_VERSION}::${QUAZIP_QT_ZLIB_HEADER_COMPONENT})
- endif()
- set(QUAZIP_QT_ZLIB_USED ON)
- else()
- message(FATAL_ERROR "QUAZIP_USE_QT_ZLIB was set but bundled zlib was not found. Terminating to prevent accidental linking to system libraries.")
- endif()
-endif()
-
-if(QUAZIP_QT_ZLIB_USED AND QUAZIP_QT_ZLIB_COMPONENT STREQUAL BundledZLIB)
- # Qt's new BundledZLIB uses z-prefix in zlib
- add_compile_definitions(Z_PREFIX)
-endif()
-
-if(NOT QUAZIP_QT_ZLIB_USED)
-
- if(EMSCRIPTEN)
- if(NOT DEFINED ZLIB_LIBRARY)
- message(WARNING "ZLIB_LIBRARY is not set")
- endif()
+find_package(Qt6 REQUIRED COMPONENTS Core Core5Compat
+ OPTIONAL_COMPONENTS Network Test)
+message(STATUS "Found Qt version ${Qt6_VERSION} at ${Qt6_DIR}")
+set(QUAZIP_QT_ZLIB_COMPONENT BundledZLIB)
+set(QUAZIP_QT_ZLIB_HEADER_COMPONENT ZlibPrivate)
+set(QUAZIP_LIB_LIBRARIES Qt6::Core Qt6::Core5Compat)
+set(QUAZIP_TEST_QT_LIBRARIES Qt6::Core Qt6::Core5Compat Qt6::Network Qt6::Test)
+set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt6Core")
- if(NOT DEFINED ZLIB_INCLUDE)
- message(WARNING "ZLIB_INCLUDE is not set")
- else()
- include_directories(${ZLIB_INCLUDE})
- endif()
-
- if(NOT DEFINED ZCONF_INCLUDE)
- message(WARNING "ZCONF_INCLUDE is not set")
- else()
- include_directories(${ZCONF_INCLUDE})
- endif()
-
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ${ZLIB_LIBRARY})
- else()
- find_package(ZLIB REQUIRED)
- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ZLIB::ZLIB)
- endif()
-endif()
+find_package(ZLIB REQUIRED)
+set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ZLIB::ZLIB)
if (ZLIB_CONST)
add_compile_definitions(ZLIB_CONST)
@@ -173,65 +50,4 @@ set(QUAZIP_INC)
set(QUAZIP_LIB)
set(QUAZIP_LBD)
-if(QUAZIP_BZIP2)
- # Check if bzip2 is present
- set(QUAZIP_BZIP2 ON)
-
- if(NOT QUAZIP_FORCE_FETCH_LIBS)
- find_package(BZip2 QUIET)
- endif()
-
- if(BZIP2_FOUND AND NOT QUAZIP_FORCE_FETCH_LIBS)
- message(STATUS "Using BZIP2 ${BZIP2_VERSION_STRING}")
-
- list(APPEND QUAZIP_INC ${BZIP2_INCLUDE_DIRS})
- list(APPEND QUAZIP_LIB ${BZIP2_LIBRARIES})
- list(APPEND QUAZIP_LBD ${BZIP2_LIBRARY_DIRS})
-
- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lbzip2")
- elseif(QUAZIP_FETCH_LIBS)
- clone_repo(bzip2 https://sourceware.org/git/bzip2.git)
-
- # BZip2 repository does not support cmake so we have to create
- # the bzip2 library ourselves
- set(BZIP2_SRC
- ${BZIP2_SOURCE_DIR}/blocksort.c
- ${BZIP2_SOURCE_DIR}/bzlib.c
- ${BZIP2_SOURCE_DIR}/compress.c
- ${BZIP2_SOURCE_DIR}/crctable.c
- ${BZIP2_SOURCE_DIR}/decompress.c
- ${BZIP2_SOURCE_DIR}/huffman.c
- ${BZIP2_SOURCE_DIR}/randtable.c)
-
- set(BZIP2_HDR
- ${BZIP2_SOURCE_DIR}/bzlib.h
- ${BZIP2_SOURCE_DIR}/bzlib_private.h)
-
- add_library(bzip2 STATIC ${BZIP2_SRC} ${BZIP2_HDR})
-
- if(NOT QUAZIP_BZIP2_STDIO)
- target_compile_definitions(bzip2 PRIVATE -DBZ_NO_STDIO)
- endif()
-
- list(APPEND QUAZIP_DEP bzip2)
- list(APPEND QUAZIP_LIB bzip2)
- list(APPEND QUAZIP_INC ${BZIP2_SOURCE_DIR})
- else()
- message(STATUS "BZip2 library not found")
-
- set(QUAZIP_BZIP2 OFF)
- endif()
-
- if(QUAZIP_BZIP2)
- find_package(BZip2)
- add_compile_definitions(HAVE_BZIP2)
- endif()
-endif()
-
add_subdirectory(quazip)
-
-if(QUAZIP_ENABLE_TESTS)
- message(STATUS "Building QuaZip tests")
- enable_testing()
- add_subdirectory(qztest)
-endif()
diff --git a/quazip/CMakeLists.txt b/quazip/CMakeLists.txt
index 6cfdf4e..66bc4cb 100644
--- a/quazip/CMakeLists.txt
+++ b/quazip/CMakeLists.txt
@@ -46,10 +46,6 @@ set(QUAZIP_INCLUDE_PATH ${QUAZIP_DIR_NAME}/quazip)
set(QUAZIP_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake)
set(QUAZIP_PKGCONFIG_NAME quazip${QuaZip_VERSION_MAJOR}-qt${QUAZIP_QT_MAJOR_VERSION})
-if(EMSCRIPTEN)
- set(BUILD_SHARED_LIBS OFF)
-endif()
-
add_library(${QUAZIP_LIB_TARGET_NAME} ${QUAZIP_SOURCES})
add_library(QuaZip::QuaZip ALIAS ${QUAZIP_LIB_TARGET_NAME})
diff --git a/quazip/quazip_qt_compat.h b/quazip/quazip_qt_compat.h
index 0dde011..41f9dd1 100644
--- a/quazip/quazip_qt_compat.h
+++ b/quazip/quazip_qt_compat.h
@@ -14,16 +14,11 @@
// Legacy encodings are still everywhere, but the Qt team decided we
// don't need them anymore and moved them out of Core in Qt 6.
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
-# include <QtCore5Compat/QTextCodec>
-#else
-# include <QtCore/QTextCodec>
-#endif
+#include <QtCore5Compat/QTextCodec>
// QSaveFile terribly breaks the is-a idiom (Liskov substitution principle):
// QSaveFile is-a QIODevice, but it makes close() private and aborts
// if you call it through the base class. Hence this ugly hack:
-#if (QT_VERSION >= 0x050100)
#include <QtCore/QSaveFile>
inline bool quazip_close(QIODevice *device) {
QSaveFile *file = qobject_cast<QSaveFile*>(device);
@@ -34,74 +29,35 @@ inline bool quazip_close(QIODevice *device) {
device->close();
return true;
}
-#else
-inline bool quazip_close(QIODevice *device) {
- device->close();
- return true;
-}
-#endif
-// this is yet another stupid move and deprecation
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
using Qt::SkipEmptyParts;
-#else
-#include <QtCore/QString>
-const auto SkipEmptyParts = QString::SplitBehavior::SkipEmptyParts;
-#endif
// and yet another... (why didn't they just make qSort delegate to std::sort?)
#include <QtCore/QList>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
#include <algorithm>
template<typename T, typename C>
inline void quazip_sort(T begin, T end, C comparator) {
std::sort(begin, end, comparator);
}
-#else
-#include <QtCore/QtAlgorithms>
-template<typename T, typename C>
-inline void quazip_sort(T begin, T end, C comparator) {
- qSort(begin, end, comparator);
-}
-#endif
// this is a stupid rename...
#include <QtCore/QDateTime>
#include <QtCore/QFileInfo>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
inline QDateTime quazip_ctime(const QFileInfo &fi) {
return fi.birthTime();
}
-#else
-inline QDateTime quazip_ctime(const QFileInfo &fi) {
- return fi.created();
-}
-#endif
// this is just a slightly better alternative
#include <QtCore/QFileInfo>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
inline bool quazip_is_symlink(const QFileInfo &fi) {
return fi.isSymbolicLink();
}
-#else
-inline bool quazip_is_symlink(const QFileInfo &fi) {
- // also detects *.lnk on Windows, but better than nothing
- return fi.isSymLink();
-}
-#endif
// I'm not even sure what this one is, but nevertheless
#include <QtCore/QFileInfo>
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
inline QString quazip_symlink_target(const QFileInfo &fi) {
return fi.symLinkTarget();
}
-#else
-inline QString quazip_symlink_target(const QFileInfo &fi) {
- return fi.readLink(); // What's the difference? I've no idea.
-}
-#endif
// deprecation
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
@@ -125,40 +81,19 @@ inline QDateTime quazip_since_epoch_ntfs() {
// this is not a deprecation but an improvement, for a change
#include <QtCore/QDateTime>
-#if (QT_VERSION >= 0x040700)
inline quint64 quazip_ntfs_ticks(const QDateTime &time, int fineTicks) {
QDateTime base = quazip_since_epoch_ntfs();
return base.msecsTo(time) * 10000 + fineTicks;
}
-#else
-inline quint64 quazip_ntfs_ticks(const QDateTime &time, int fineTicks) {
- QDateTime base = quazip_since_epoch_ntfs();
- QDateTime utc = time.toUTC();
- return (static_cast<qint64>(base.date().daysTo(utc.date()))
- * Q_INT64_C(86400000)
- + static_cast<qint64>(base.time().msecsTo(utc.time())))
- * Q_INT64_C(10000) + fineTicks;
-}
-#endif
// yet another improvement...
#include <QtCore/QDateTime>
-#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // Yay! Finally a way to get time as qint64!
inline qint64 quazip_to_time64_t(const QDateTime &time) {
return time.toSecsSinceEpoch();
}
-#else
-inline qint64 quazip_to_time64_t(const QDateTime &time) {
- return static_cast<qint64>(time.toTime_t()); // 32 bits only, but better than nothing
-}
-#endif
#include <QtCore/QTextStream>
-// and another stupid move
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
const auto quazip_endl = Qt::endl;
-#else
-const auto quazip_endl = endl;
-#endif
#endif // QUAZIP_QT_COMPAT_H
+

View file

@ -29,10 +29,10 @@ elseif (TARGET SDL2::SDL2-shared)
endif()
# Set bundled sdl2/qt as dependent options.
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "ENABLE_SDL2;NOT MSVC" OFF)
else()
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
@ -50,6 +50,7 @@ option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF)
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" OFF)
@ -79,6 +80,8 @@ option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
@ -120,7 +123,7 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
set(DEFAULT_ENABLE_OPENSSL ON)
if (ANDROID OR WIN32 OR APPLE)
if (ANDROID OR WIN32 OR APPLE OR ${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
set(DEFAULT_ENABLE_OPENSSL OFF)
endif()
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
@ -344,7 +347,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(enet 1.3 MODULE)
find_package(fmt 8 REQUIRED)
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
find_package(LLVM MODULE COMPONENTS Demangle)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE)
@ -412,7 +415,7 @@ if(ENABLE_OPENSSL)
find_package(OpenSSL 1.1.1 REQUIRED)
endif()
if (UNIX AND NOT APPLE)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT ANDROID)
find_package(gamemode 1.7 MODULE)
endif()
@ -465,12 +468,10 @@ if (ENABLE_QT)
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
endif()
# QT6 Multimedia pulls in unneeded audio systems (ALSA, Pulseaudio) for FreeBSD
# ALSA is the default sound system on Linux, but FreeBSD uses OSS which works well enough
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent)
else()
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
if (YUZU_USE_QT_MULTIMEDIA)
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
endif()
if (UNIX AND NOT APPLE)

24
CMakeModules/CPM.cmake Normal file
View file

@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.42.0)
set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})

View file

@ -94,7 +94,7 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
else()
set(host "linux")
set(type "desktop")
set(arch "gcc_64")
set(arch "linux_gcc_64")
set(arch_path "linux")
endif()
@ -133,12 +133,26 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
else()
set(prefix "${base_path}/${target}/${arch_path}")
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt3d qt5compat qtactiveqt qtcharts qtconnectivity qtdatavis3d qtgraphs qtgrpc qthttpserver qtimageformats qtlanguageserver qtlocation qtlottie qtmultimedia qtnetworkauth qtpdf qtpositioning qtquick3d qtquick3dphysics qtquickeffectmaker qtquicktimeline qtremoteobjects qtscxml qtsensors qtserialbus qtserialport qtshadertools qtspeech qtvirtualkeyboard qtwebchannel qtwebengine qtwebsockets qtwebview)
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt_base)
if (YUZU_USE_QT_MULTIMEDIA)
set(install_args ${install_args} qtmultimedia)
endif()
if (YUZU_USE_QT_WEB_ENGINE)
set(install_args ${install_args} qtpositioning qtwebchannel qtwebengine)
endif()
if (NOT ${YUZU_QT_MIRROR} STREQUAL "")
message(STATUS "Using Qt mirror ${YUZU_QT_MIRROR}")
set(install_args ${install_args} -b ${YUZU_QT_MIRROR})
endif()
endif()
message(STATUS "Install Args ${install_args}")
if (NOT EXISTS "${prefix}")
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.2.1")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0")
if (WIN32)
set(aqt_path "${base_path}/aqt.exe")
if (NOT EXISTS "${aqt_path}")

View file

@ -9,13 +9,13 @@
<h1 align="center">
<br>
<a href="https://git.eden-emu.dev/eden-emu/eden"><img src="https://git.eden-emu.dev/eden-emu/eden/raw/branch/master/dist/qt_themes/default/icons/256x256/eden_named.png" alt="Eden" width="200"></a>
<a href="https://git.eden-emu.dev/eden-emu/eden"><img src="./dist/qt_themes/default/icons/256x256/eden_named.png" alt="Eden" width="200"></a>
<br>
<b>Eden</b>
<br>
</h1>
<h4 align="center"><b>Eden</b> is the world's most popular open-source Nintendo Switch emulator, forked from the Yuzu emulator — started by former Citron developer Camille LaVey and the Eden team.
<h4 align="center"><b>Eden</b> is a open-source Nintendo Switch emulator, forked from the Yuzu emulator — started by former Citron developer Camille LaVey and the Eden team.
<br>
It is written in C++ with portability in mind, and we actively maintain builds for Windows, Linux and Android.
</h4>
@ -54,13 +54,15 @@ You can also contact any of the developers on Discord to learn more about the cu
## Building
* **Windows**: [Windows Building Guide](https://git.eden-emu.dev/eden-emu/eden/wiki/Building-for-Windows.-)
* **Linux**: [Linux Building Guide](https://git.eden-emu.dev/eden-emu/eden/wiki/Building-for-Linux.-)
* **Android**: [Android Building Guide](https://git.eden-emu.dev/eden-emu/eden/wiki/Building-for-Android.-)
* **Windows**: [Windows Building Guide](./docs/build/Windows.md)
* **Linux**: [Linux Building Guide](./docs/build/Linux.md)
* **Android**: [Android Building Guide](./docs/build/Android.md)
* **FreeBSD**: [FreeBSD Building Guide](./docs/build/FreeBSD.md)
* **macOS**: [macOS Building Guide](./docs/build/macOS.md)
## Download
You will be able to download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).
You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).
## Support

94
docs/Solaris.md Normal file
View file

@ -0,0 +1,94 @@
# Building for Solaris
## Dependencies.
Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability.
Run the usual update + install of essential toolings: `sudo pkg update && sudo pkg install git cmake`.
- **gcc**: `sudo pkg install developer/gcc-14`.
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
Then install the libraies: `sudo pkg install qt6 boost glslang libzip library/lz4 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm`.
fmtlib is not available on repositories and has to be manually built:
```sh
git clone --recurisve --depth=1 https://github.com/fmtlib/fmt.git
cd fmt
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
sudo cmake --install build
```
pkg lz4 doesn't provide a proper CMakeFile to find the library, has to also be manually built:
```sh
git clone --depth=1 https://github.com/lz4/lz4.git
cd lz4
gmake
sudo gmake install
```
Same goes for zstd:
```sh
git clone --depth=1 https://github.com/facebook/zstd.git
cd zstd
cmake -DCMAKE_BUILD_TYPE=Release -B build0 -S build/cmake
cmake --build build0
cd build0
sudo gmake install
```
pkg SDL2 is also not nice to work with on CMake, save yourself some pain and compile it yourself:
```sh
git clone --depth=1 --branch=release-2.32.8 https://github.com/libsdl-org/SDL
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
sudo cmake --install build
```
Audio is broken in OpenIndiana [see this issue](https://github.com/libsdl-org/SDL/issues/13405), go into `SDL/CMakeLists.txt` and comment out lines 1468:
```diff
+# set(SDL_AUDIO_DRIVER_SUNAUDIO 1)
+# file(GLOB SUN_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/sun/*.c)
+# list(APPEND SOURCE_FILES ${SUN_AUDIO_SOURCES})
+# set(HAVE_SDL_AUDIO TRUE)
```
For Solaris this issue does not exist - however PulseAudio crashes on Solaris - so use a different backend.
---
### Build preparations:
Run the following command to clone eden with git:
```sh
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
```
You usually want to add the `--recursive` parameter as it also takes care of the external dependencies for you.
Now change into the eden directory and create a build directory there:
```sh
cd eden
mkdir build
```
Change into that build directory: `cd build`
Now choose one option either 1 or 2, but not both as one option overwrites the other.
### Building
```sh
# Needed for some dependencies that call cc directly (tz)
echo '#!/bin/sh' >cc
echo 'gcc $@' >>cc
chmod +x cc
export PATH="$PATH:$PWD"
```
- **Configure**: `cmake -B build -DYUZU_TESTS=OFF -DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF -DYUZU_USE_LLVM_DEMANGLE=OFF -DYUZU_USE_QT_MULTIMEDIA=OFF -DYUZU_USE_QT_WEB_ENGINE=OFF -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_USE_BUNDLED_QT=OFF -DENABLE_QT=OFF -DSDL_AUDIO=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_QT_UPDATE_CHECKER=OFF`.
- **Build**: `cmake --build build`.
- **Installing**: `sudo cmake --install build`.
### Notes
- Modify the generated ffmpeg.make (in build dir) if using multiple threads (base system `make` doesn't use `-j4`, so change for `gmake`).
- If using OpenIndiana, due to a bug in SDL2 cmake configuration; Audio driver defaults to SunOS `<sys/audioio.h>`, which does not exist on OpenIndiana.
- Enabling OpenSSL requires compiling OpenSSL manually instead of using the provided one from repositores.

42
docs/build/Android.md vendored Normal file
View file

@ -0,0 +1,42 @@
# Note: These build instructions are a work-in-progress.
## Dependencies
* [Android Studio](https://developer.android.com/studio)
* [NDK 25.2.9519653 and CMake 3.22.1](https://developer.android.com/studio/projects/install-ndk#default-version)
* [Git](https://git-scm.com/download)
### WINDOWS ONLY - Additional Dependencies
* **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select "Desktop development with C++" support in the installer. Make sure to update to the latest version if already installed.**
* **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.**
- A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`.
## Cloning Eden with Git
```
git clone --recursive https://git.eden-emu.dev/eden-emu/eden.git
```
Eden by default will be cloned into -
* `C:\Users\<user-name>\eden` on Windows
* `~/eden` on Linux
* And wherever on macOS
## Building
1. Start Android Studio, on the startup dialog select `Open`.
2. Navigate to the `eden/src/android` directory and click on `OK`.
3. In `Build > Select Build Variant`, select `release` or `relWithDebInfo` as the "Active build variant".
4. Build the project with `Build > Make Project` or run it on an Android device with `Run > Run 'app'`.
## Building with Terminal
1. Download the SDK and NDK from Android Studio.
2. Navigate to SDK and NDK paths.
3. Then set ANDROID_SDK_ROOT and ANDROID_NDK_ROOT in terminal via
`export ANDROID_SDK_ROOT=path/to/sdk`
`export ANDROID_NDK_ROOT=path/to/ndk`.
4. Navigate to `eden/src/android`.
5. Then Build with `./gradlew assemblerelWithDebInfo`.
6. To build the optimised build use `./gradlew assembleGenshinSpoofRelWithDebInfo`.
### Script
A convenience script for building is provided in `.ci/android/build.sh`. The built APK can be put into an `artifacts` directory via `.ci/android/package.sh`. On Windows, these must be done in the Git Bash or MinGW terminal.
### Additional Resources
https://developer.android.com/studio/intro

81
docs/build/FreeBSD.md vendored Normal file
View file

@ -0,0 +1,81 @@
## One word of caution before proceeding.
This is not the usual or preferred way to build programs on FreeBSD.
As of writing there is no official fresh port available for eden-emu, but it is in the works.
After it is available you can find a link to the eden-emu fresh port here and on Escarys github repo.
See this build as an App Image alternative for FreeBSD.
## Dependencies.
Before we start we need some dependencies.
These dependencies are generally needed to build eden-emu on FreeBSD.
```
devel/cmake
devel/sdl20
devel/boost-libs
devel/catch2
devel/libfmt
devel/nlohmann-json
devel/ninja
devel/nasm
devel/autoconf
devel/pkg-config
devel/qt6-base
multimedia/ffnvcodec-headers
multimedia/ffmpeg
audio/opus
archivers/liblz4
lang/gcc12
graphics/glslang
graphics/vulkan-utility-libraries
```
---
### Build preparations:
Run the following command to clone eden with git:
```sh
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
```
You usually want to add the `--recursive` parameter as it also takes care of the external dependencies for you.
Now change into the eden directory and create a build directory there:
```sh
cd eden
mkdir build
```
Change into that build directory:
```sh
cd build
```
Now choose one option either 1 or 2, but not both as one option overwrites the other.
#### 1. Building in Release Mode (usually preferred and the most performant choice):
```sh
cmake .. -GNinja -DYUZU_TESTS=OFF
```
#### 2. Building in Release Mode with debugging symbols (useful if you want to debug errors for a eventual fix):
```sh
cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_TESTS=ON
```
Build the emulator locally:
```sh
ninja
```
Optional: If you wish to install eden globally onto your system issue the following command:
```sh
sudo ninja install
```
OR
```sh
doas -- ninja install
```

135
docs/build/Linux.md vendored Normal file
View file

@ -0,0 +1,135 @@
### Dependencies
You'll need to download and install the following to build Eden:
* [GCC](https://gcc.gnu.org/) v11+ (for C++20 support) & misc
* If GCC 12 is installed, [Clang](https://clang.llvm.org/) v14+ is required for compiling
* [CMake](https://www.cmake.org/) 3.22+
The following are handled by Eden's externals:
* [FFmpeg](https://ffmpeg.org/)
* [SDL2](https://www.libsdl.org/download-2.0.php) 2.0.18+
* [opus](https://opus-codec.org/downloads/)
All other dependencies will be downloaded by [vcpkg](https://vcpkg.io/) if needed:
* [Boost](https://www.boost.org/users/download/) 1.79.0+
* [Catch2](https://github.com/catchorg/Catch2) 2.13.7 - 2.13.9
* [fmt](https://fmt.dev/) 8.0.1+
* [lz4](http://www.lz4.org) 1.8+
* [nlohmann_json](https://github.com/nlohmann/json) 3.8+
* [OpenSSL](https://www.openssl.org/source/)
* [ZLIB](https://www.zlib.net/) 1.2+
* [zstd](https://facebook.github.io/zstd/) 1.5+
If an ARM64 build is intended, export `VCPKG_FORCE_SYSTEM_BINARIES=1`.
Dependencies are listed here as commands that can be copied/pasted. Of course, they should be inspected before being run.
- Arch / Manjaro:
- `sudo pacman -Syu --needed base-devel boost catch2 cmake ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip`
- Building with QT Web Engine requires `qt6-webengine` as well.
- Proper wayland support requires `qt6-wayland`
- GCC 11 or later is required.
- Ubuntu / Linux Mint / Debian:
- `sudo apt-get install autoconf cmake g++-11 gcc-11 git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qtbase6-dev qtbase6-private-dev qtwebengine6-dev qtmultimedia6-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev`
- Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
- Users need to manually specify building with QT Web Engine enabled. This is done using the parameter `-DYUZU_USE_QT_WEB_ENGINE=ON` when running CMake.
- Users need to manually specify building with GCC 11. This can be done by adding the parameters `-DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11` when running CMake. i.e.
- Users need to manually disable building SDL2 from externals if they intend to use the version provided by their system by adding the parameters `-DYUZU_USE_EXTERNAL_SDL2=OFF`
```
git submodule update --init --recursive
cmake .. -GNinja -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11
```
- Fedora:
- `sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt5-linguist qt5-qtbase{-private,}-devel qt5-qtwebengine-devel qt5-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel`
- Fedora 32 or later is required.
- Due to GCC 12, Fedora 36 or later users need to install `clang`, and configure CMake to use it via `-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang`
- CMake arguments to force system libraries:
- SDL2: `-DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF`
- FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF`
- [RPM Fusion](https://rpmfusion.org/) (free) is required to install `ffmpeg-devel`
### Cloning Eden with Git
**Master:**
```bash
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
cd eden
```
The `--recursive` option automatically clones the required Git submodules.
### Building Eden in Release Mode (Optimised)
If you need to run ctests, you can disable `-DYUZU_TESTS=OFF` and install Catch2.
```bash
mkdir build && cd build
cmake .. -GNinja -DYUZU_TESTS=OFF
ninja
sudo ninja install
```
You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..`
`-DYUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS=OFF` might be needed if ninja command failed with `undefined reference to symbol 'spvOptimizerOptionsCreate`, reason currently unknown
Optionally, you can use `cmake-gui ..` to adjust various options (e.g. disable the Qt GUI).
### Building Eden in Debug Mode (Slow)
```bash
mkdir build && cd build
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug -DYUZU_TESTS=OFF
ninja
```
### Building with debug symbols
```bash
mkdir build && cd build
cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU -DYUZU_TESTS=OFF
ninja
```
### Building with Scripts
A convenience script for building is provided in `.ci/linux/build.sh`. You must provide an arch target for optimization, e.g. `.ci/linux/build.sh amd64`. Valid targets:
- `legacy`: x86_64 generic, only needed for CPUs older than 2013 or so
- `amd64`: x86_64-v3, for CPUs newer than 2013 or so
- `steamdeck` / `zen2`: For Steam Deck or Zen >= 2 AMD CPUs (untested on Intel)
- `rog-ally` / `allyx` / `zen4`: For ROG Ally X or Zen >= 4 AMD CPUs (untested on Intel)
- `aarch64`: For armv8-a CPUs, older than mid-2021 or so
- `armv9`: For armv9-a CPUs, newer than mid-2021 or so
- `native`: Optimize to your native host architecture
Extra flags to pass to CMake should be passed after the arch target.
Additional environment variables can be used to control building:
- `NPROC`: Number of threads to use for compilation (defaults to all)
- `TARGET`: Set to `appimage` to disable standalone `eden-cli` and `eden-room` executables
- `BUILD_TYPE`: Sets the build type to use. Defaults to `Release`
The following environment variables are boolean flags. Set to `true` to enable or `false` to disable:
- `DEVEL` (default FALSE): Disable Qt update checker
- `USE_WEBENGINE` (default FALSE): Enable Qt WebEngine
- `USE_MULTIMEDIA` (default TRUE): Enable Qt Multimedia
After building, an AppImage can be packaged via `.ci/linux/package.sh`. This script takes the same arch targets as the build script. If the build was created in a different directory, you can specify its path relative to the source directory, e.g. `.ci/linux/package.sh amd64 build-appimage`. Additionally, set the `DEVEL` environment variable to `true` to change the app name to `Eden Nightly`.
### Running without installing
After building, the binaries `eden` and `eden-cmd` (depending on your build options) will end up in `build/bin/`.
```bash
# SDL
cd build/bin/
./eden-cmd
# Qt
cd build/bin/
./eden
```

195
docs/build/Windows.md vendored Normal file
View file

@ -0,0 +1,195 @@
# THIS GUIDE IS INTENDED FOR DEVELOPERS ONLY, SUPPORT WILL ONLY BE GIVEN IF YOU'RE A DEVELOPER.
## Method I: MSVC Build for Windows
### Minimal Dependencies
On Windows, all library dependencies are automatically included within the `externals` folder, or can be downloaded on-demand. To build Eden, you need to install:
* **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select C++ support in the installer. Make sure to update to the latest version if already installed.**
* **[CMake](https://cmake.org/download/)** - Used to generate Visual Studio project files. Does not matter if either 32-bit or 64-bit version is installed.
* **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.**
- A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`.
![2](https://i.imgur.com/giDwuTm.png)
* **Git** - We recommend [Git for Windows](https://gitforwindows.org).
![3](https://i.imgur.com/UeSzkBw.png)
* While installing Git Bash, you should tell it to include Git in your system path. (Choose the "Git from the command line and also from 3rd-party software" option.) If you missed that, don't worry, you'll just have to manually tell CMake where your git.exe is, since it's used to include version info into the built executable.
![4](https://i.imgur.com/x0rRs1t.png)
### Cloning Eden with Git
**Master:**
```cmd
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
cd eden
```
![9](https://i.imgur.com/CcxIAht.png)
* *(Note: eden by default downloads to `C:\Users\<user-name>\eden` (Master)
### Building
* Open the CMake GUI application and point it to the `eden` (Master)
![10](https://i.imgur.com/qOslIWv.png)
* For the build directory, use a `/build` subdirectory inside the source directory or some other directory of your choice. (Tell CMake to create it.)
* Click the "Configure" button and choose `Visual Studio 17 2022`, with `x64` for the optional platform.
![12](https://i.imgur.com/DKiREaK.png)
* *(Note: If you used GitHub's own app to clone, run `git submodule update --init --recursive` to get the remaining dependencies)*
* If you get an error about missing packages, enable `YUZU_USE_BUNDLED_VCPKG`, and then click Configure again.
* *(You may also want to disable `YUZU_TESTS` in this case since Catch2 is not yet supported with this.)*
![13](https://user-images.githubusercontent.com/22451773/180585999-07316d6e-9751-4d11-b957-1cf57cd7cd58.png)
* Click "Generate" to create the project files.
![15](https://i.imgur.com/5LKg92k.png)
* Open the solution file `yuzu.sln` in Visual Studio 2022, which is located in the build folder.
![16](https://i.imgur.com/208yMml.png)
* Depending if you want a graphical user interface or not (`eden` has the graphical user interface, while `eden-cmd` doesn't), select `eden` or `eden-cmd` in the Solution Explorer, right-click and `Set as StartUp Project`.
![17](https://i.imgur.com/nPMajnn.png) ![18](https://i.imgur.com/BDMLzRZ.png)
* Select the appropriate build type, Debug for debug purposes or Release for performance (in case of doubt choose Release).
![19](https://i.imgur.com/qxg4roC.png)
* Right-click the project you want to build and press Build in the submenu or press F5.
![20](https://i.imgur.com/CkQgOFW.png)
## Method II: MinGW-w64 Build with MSYS2
### Prerequisites to install
* [MSYS2](https://www.msys2.org)
* [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) - **Make sure to select Latest SDK.**
* Make sure to follow the instructions and update to the latest version by running `pacman -Syu` as many times as needed.
### Install eden dependencies for MinGW-w64
* Open the `MSYS2 MinGW 64-bit` (mingw64.exe) shell
* Download and install all dependencies using: `pacman -Syu git make mingw-w64-x86_64-SDL2 mingw-w64-x86_64-cmake mingw-w64-x86_64-python-pip mingw-w64-x86_64-qt6 mingw-w64-x86_64-toolchain autoconf libtool automake-wrapper`
* Add MinGW binaries to the PATH: `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc`
* Add glslangValidator to the PATH: `echo 'PATH=$(readlink -e /c/VulkanSDK/*/Bin/):$PATH' >> ~/.bashrc`
### Clone the eden repository with Git
```bash
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
cd eden
```
### Run the following commands to build eden (dynamically linked build)
```bash
mkdir build && cd build
cmake -G "MSYS Makefiles" -DYUZU_USE_BUNDLED_VCPKG=ON -DYUZU_TESTS=OFF ..
make -j$(nproc)
# test eden out with
./bin/eden.exe
```
* *(Note: This build is not a static build meaning that you need to include all of the DLLs with the .exe in order to use it!)*
e.g.
```Bash
cp externals/ffmpeg-*/bin/*.dll bin/
```
Bonus Note: Running programs from inside `MSYS2 MinGW x64` shell has a different %PATH% than directly from explorer. This different %PATH% has the locations of the other DLLs required.
![image](https://user-images.githubusercontent.com/190571/165000848-005e8428-8a82-41b1-bb4d-4ce7797cdac8.png)
### Building without Qt (Optional)
Doesn't require the rather large Qt dependency, but you will lack a GUI frontend:
* Pass the `-DENABLE_QT=no` flag to cmake
## Method III: CLion Environment Setup
### Minimal Dependencies
To build eden, you need to install the following:
* [CLion](https://www.jetbrains.com/clion/) - This IDE is not free; for a free alternative, check Method I
* [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) - Make sure to select the Latest SDK.
### Cloning eden with CLion
* Clone the Repository:
![1](https://user-images.githubusercontent.com/42481638/216899046-0d41d7d6-8e4d-4ed2-9587-b57088af5214.png)
![2](https://user-images.githubusercontent.com/42481638/216899061-b2ea274a-e88c-40ae-bf0b-4450b46e9fea.png)
![3](https://user-images.githubusercontent.com/42481638/216899076-0e5988c4-d431-4284-a5ff-9ecff973db76.png)
### Building & Setup
* Once Cloned, You will be taken to a prompt like the image below:
![4](https://user-images.githubusercontent.com/42481638/216899092-3fe4cec6-a540-44e3-9e1e-3de9c2fffc2f.png)
* Set the settings to the image below:
* Change `Build type: Release`
* Change `Name: Release`
* Change `Toolchain Visual Studio`
* Change `Generator: Let CMake decide`
* Change `Build directory: build`
![5](https://user-images.githubusercontent.com/42481638/216899164-6cee8482-3d59-428f-b1bc-e6dc793c9b20.png)
* Click OK; now Clion will build a directory and index your code to allow for IntelliSense. Please be patient.
* Once this process has been completed (No loading bar bottom right), you can now build eden
* In the top right, click on the drop-down menu, select all configurations, then select eden
![6](https://user-images.githubusercontent.com/42481638/216899226-975048e9-bc6d-4ec1-bc2d-bd8a1e15ed04.png)
* Now run by clicking the play button or pressing Shift+F10, and eden will auto-launch once built.
![7](https://user-images.githubusercontent.com/42481638/216899275-d514ec6a-e563-470e-81e2-3e04f0429b68.png)
## Building from the command line with MSVC
```cmd
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
cd eden
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release
```
### Building with Scripts
A convenience script for building is provided in `.ci/windows/build.sh`. You must run this with Bash, e.g. Git Bash or MinGW TTY. To use this script, you must have windeployqt installed (usually bundled with Qt) and set the `WINDEPLOYQT` environment variable to its canonical Bash location, e.g. `WINDEPLOYQT="/c/Qt/6.9.1/msvc2022_64/bin/windeployqt6.exe" .ci/windows/build.sh`.
Extra CMake flags should be placed in the arguments of the script.
Additional environment variables can be used to control building:
- `BUILD_TYPE`: Sets the build type to use. Defaults to `Release`
The following environment variables are boolean flags. Set to `true` to enable or `false` to disable:
- `DEVEL` (default FALSE): Disable Qt update checker
- `USE_WEBENGINE` (default FALSE): Enable Qt WebEngine
- `USE_MULTIMEDIA` (default TRUE): Enable Qt Multimedia
- `BUNDLE_QT` (default FALSE): Use bundled Qt
* Note that using system Qt requires you to include the Qt CMake directory in `CMAKE_PREFIX_PATH`, e.g. `.ci/windows/build.sh -DCMAKE_PREFIX_PATH=C:/Qt/6.9.0/msvc2022_64/lib/cmake/Qt6`
After building, a zip can be packaged via `.ci/windows/package.sh`. Note that you must have 7-zip installed and in your PATH. The resulting zip will be placed into `artifacts` in the source directory.

105
docs/build/macOS.md vendored Normal file
View file

@ -0,0 +1,105 @@
Please note this article is intended for development, and eden on macOS is not currently ready for regular use.
This article was written for developers. eden support for macOS is not ready for casual use.
## Method I: ninja
---
If you are compiling on Intel Mac or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` to `/usr/local`.
Install dependencies from Homebrew:
```sh
brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zlib zstd cmake Catch2 molten-vk vulkan-loader
```
Clone the repo
```sh
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
cd eden
```
Build for release
```sh
mkdir build && cd build
export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake"
export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib
cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=ON -DENABLE_LIBUSB=OFF -DCLANG_FORMAT=ON -DSDL2_DISABLE_INSTALL=ON -DSDL_ALTIVEC=ON
ninja
```
You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..`
Build with debug symbols (vcpkg is not currently used due to broken boost-context library):
```sh
mkdir build && cd build
export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake"
cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_LIBUSB=OFF
ninja
```
Run the output:
```
bin/eden.app/Contents/MacOS/eden
```
## Method II: Xcode
---
If you are compiling on Intel Mac or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` to `/usr/local`.
Install dependencies from Homebrew:
```sh
brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zlib zstd cmake Catch2 molten-vk vulkan-loader
```
Clone the repo
```sh
git clone --recursive https://git.eden-emu.dev/eden-emu/eden
cd eden
```
Build for release
```sh
mkdir build && cd build
export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake"
export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib
cmake .. -GXcode -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=ON -DENABLE_LIBUSB=OFF -DCLANG_FORMAT=ON -DSDL2_DISABLE_INSTALL=ON -DSDL_ALTIVEC=ON
xcodebuild build -project eden.xcodeproj -scheme "eden" -configuration "RelWithDebInfo"
```
You may also want to include support for Discord Rich Presence by adding `-DUSE_DISCORD_PRESENCE=ON` after `cmake ..`
Build with debug symbols (vcpkg is not currently used due to broken boost-context library):
```sh
mkdir build && cd build
export Qt6_DIR="/opt/homebrew/opt/qt@6/lib/cmake"
cmake .. -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DYUZU_USE_BUNDLED_VCPKG=OFF -DYUZU_TESTS=OFF -DENABLE_WEB_SERVICE=OFF -DENABLE_LIBUSB=OFF
ninja
```
Run the output:
```
bin/eden.app/Contents/MacOS/eden
```
---
To run with MoltenVK, install additional dependencies:
```sh
brew install molten-vk vulkan-loader
```
Run with Vulkan loader path:
```sh
export LIBVULKAN_PATH=/opt/homebrew/lib/libvulkan.dylib
bin/eden.app/Contents/MacOS/eden
```

View file

@ -211,7 +211,7 @@ if (ANDROID)
endif()
endif()
if (UNIX AND NOT APPLE AND NOT TARGET gamemode::headers)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT ANDROID AND NOT TARGET gamemode::headers)
add_library(gamemode INTERFACE)
target_include_directories(gamemode INTERFACE gamemode)
add_library(gamemode::headers ALIAS gamemode)

View file

@ -98,8 +98,7 @@ else()
-Wextra
-Wcast-qual
-pedantic
-Wno-missing-braces
-Wstack-usage=4096)
-Wno-missing-braces)
if (ARCHITECTURE STREQUAL "x86_64")
list(APPEND DYNARMIC_CXX_FLAGS -mtune=core2)
@ -123,12 +122,15 @@ else()
# GCC knows that the variable is actually a Reg64. isMEM() will never return true for a
# Reg64, but GCC doesn't know that.
list(APPEND DYNARMIC_CXX_FLAGS -Wno-array-bounds)
list(APPEND DYNARMIC_CXX_FLAGS -Wstack-usage=4096)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
# And this in turns limits the size of a std::array.
list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024)
# Clang mistakenly blames CMake for using unused arguments during compilation
list(APPEND DYNARMIC_CXX_FLAGS -Wno-unused-command-line-argument)
endif()
endif()

View file

@ -125,52 +125,6 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/translate/a32_translate.h
frontend/A32/translate/conditional_state.cpp
frontend/A32/translate/conditional_state.h
frontend/A32/translate/impl/a32_branch.cpp
frontend/A32/translate/impl/a32_crc32.cpp
frontend/A32/translate/impl/a32_exception_generating.cpp
frontend/A32/translate/impl/a32_translate_impl.cpp
frontend/A32/translate/impl/a32_translate_impl.h
frontend/A32/translate/impl/asimd_load_store_structures.cpp
frontend/A32/translate/impl/asimd_misc.cpp
frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp
frontend/A32/translate/impl/asimd_three_regs.cpp
frontend/A32/translate/impl/asimd_two_regs_misc.cpp
frontend/A32/translate/impl/asimd_two_regs_scalar.cpp
frontend/A32/translate/impl/asimd_two_regs_shift.cpp
frontend/A32/translate/impl/barrier.cpp
frontend/A32/translate/impl/coprocessor.cpp
frontend/A32/translate/impl/data_processing.cpp
frontend/A32/translate/impl/divide.cpp
frontend/A32/translate/impl/extension.cpp
frontend/A32/translate/impl/hint.cpp
frontend/A32/translate/impl/load_store.cpp
frontend/A32/translate/impl/misc.cpp
frontend/A32/translate/impl/multiply.cpp
frontend/A32/translate/impl/packing.cpp
frontend/A32/translate/impl/parallel.cpp
frontend/A32/translate/impl/reversal.cpp
frontend/A32/translate/impl/saturated.cpp
frontend/A32/translate/impl/status_register_access.cpp
frontend/A32/translate/impl/synchronization.cpp
frontend/A32/translate/impl/thumb16.cpp
frontend/A32/translate/impl/thumb32_branch.cpp
frontend/A32/translate/impl/thumb32_control.cpp
frontend/A32/translate/impl/thumb32_coprocessor.cpp
frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp
frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp
frontend/A32/translate/impl/thumb32_data_processing_register.cpp
frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp
frontend/A32/translate/impl/thumb32_load_byte.cpp
frontend/A32/translate/impl/thumb32_load_halfword.cpp
frontend/A32/translate/impl/thumb32_load_store_dual.cpp
frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
frontend/A32/translate/impl/thumb32_load_word.cpp
frontend/A32/translate/impl/thumb32_long_multiply.cpp
frontend/A32/translate/impl/thumb32_misc.cpp
frontend/A32/translate/impl/thumb32_multiply.cpp
frontend/A32/translate/impl/thumb32_parallel.cpp
frontend/A32/translate/impl/thumb32_store_single_data_item.cpp
frontend/A32/translate/impl/vfp.cpp
frontend/A32/translate/translate_arm.cpp
frontend/A32/translate/translate_thumb.cpp
interface/A32/a32.h
@ -194,65 +148,6 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS)
frontend/A64/decoder/a64.inc
frontend/A64/translate/a64_translate.cpp
frontend/A64/translate/a64_translate.h
frontend/A64/translate/impl/a64_branch.cpp
frontend/A64/translate/impl/a64_exception_generating.cpp
frontend/A64/translate/impl/data_processing_addsub.cpp
frontend/A64/translate/impl/data_processing_bitfield.cpp
frontend/A64/translate/impl/data_processing_conditional_compare.cpp
frontend/A64/translate/impl/data_processing_conditional_select.cpp
frontend/A64/translate/impl/data_processing_crc32.cpp
frontend/A64/translate/impl/data_processing_logical.cpp
frontend/A64/translate/impl/data_processing_multiply.cpp
frontend/A64/translate/impl/data_processing_pcrel.cpp
frontend/A64/translate/impl/data_processing_register.cpp
frontend/A64/translate/impl/data_processing_shift.cpp
frontend/A64/translate/impl/floating_point_compare.cpp
frontend/A64/translate/impl/floating_point_conditional_compare.cpp
frontend/A64/translate/impl/floating_point_conditional_select.cpp
frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp
frontend/A64/translate/impl/floating_point_conversion_integer.cpp
frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp
frontend/A64/translate/impl/floating_point_data_processing_three_register.cpp
frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp
frontend/A64/translate/impl/impl.cpp
frontend/A64/translate/impl/impl.h
frontend/A64/translate/impl/load_store_exclusive.cpp
frontend/A64/translate/impl/load_store_load_literal.cpp
frontend/A64/translate/impl/load_store_multiple_structures.cpp
frontend/A64/translate/impl/load_store_no_allocate_pair.cpp
frontend/A64/translate/impl/load_store_register_immediate.cpp
frontend/A64/translate/impl/load_store_register_pair.cpp
frontend/A64/translate/impl/load_store_register_register_offset.cpp
frontend/A64/translate/impl/load_store_register_unprivileged.cpp
frontend/A64/translate/impl/load_store_single_structure.cpp
frontend/A64/translate/impl/move_wide.cpp
frontend/A64/translate/impl/simd_across_lanes.cpp
frontend/A64/translate/impl/simd_aes.cpp
frontend/A64/translate/impl/simd_copy.cpp
frontend/A64/translate/impl/simd_crypto_four_register.cpp
frontend/A64/translate/impl/simd_crypto_three_register.cpp
frontend/A64/translate/impl/simd_extract.cpp
frontend/A64/translate/impl/simd_modified_immediate.cpp
frontend/A64/translate/impl/simd_permute.cpp
frontend/A64/translate/impl/simd_scalar_pairwise.cpp
frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp
frontend/A64/translate/impl/simd_scalar_three_same.cpp
frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp
frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp
frontend/A64/translate/impl/simd_sha.cpp
frontend/A64/translate/impl/simd_sha512.cpp
frontend/A64/translate/impl/simd_shift_by_immediate.cpp
frontend/A64/translate/impl/simd_table_lookup.cpp
frontend/A64/translate/impl/simd_three_different.cpp
frontend/A64/translate/impl/simd_three_same.cpp
frontend/A64/translate/impl/simd_three_same_extra.cpp
frontend/A64/translate/impl/simd_two_register_misc.cpp
frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp
frontend/A64/translate/impl/sys_dc.cpp
frontend/A64/translate/impl/sys_ic.cpp
frontend/A64/translate/impl/system.cpp
frontend/A64/translate/impl/system_flag_format.cpp
frontend/A64/translate/impl/system_flag_manipulation.cpp
interface/A64/a64.h
interface/A64/config.h
ir/opt/a64_callback_config_pass.cpp

View file

@ -59,13 +59,12 @@ constexpr RegisterList ToRegList(oaknut::Reg reg) {
}
if (reg.index() == 31) {
throw std::out_of_range("ZR not allowed in reg list");
ASSERT_FALSE("ZR not allowed in reg list");
}
if (reg.index() == -1) {
return RegisterList{1} << 31;
}
return RegisterList{1} << reg.index();
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2019 MerryMage
* SPDX-License-Identifier: 0BSD
@ -13,6 +16,9 @@
# ifndef __OpenBSD__
# include <ucontext.h>
# endif
# ifdef __sun__
# include <sys/regset.h>
# endif
#endif
#include <cstring>
@ -145,9 +151,9 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
#ifndef MCL_ARCHITECTURE_RISCV
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(raw_context);
# ifndef __OpenBSD__
#ifndef __OpenBSD__
auto& mctx = ucontext->uc_mcontext;
# endif
#endif
#endif
#if defined(MCL_ARCHITECTURE_X86_64)
@ -167,6 +173,9 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
# elif defined(__OpenBSD__)
# define CTX_RIP (ucontext->sc_rip)
# define CTX_RSP (ucontext->sc_rsp)
# elif defined(__sun__)
# define CTX_RIP (mctx.gregs[REG_RIP])
# define CTX_RSP (mctx.gregs[REG_RSP])
# else
# error "Unknown platform"
# endif

View file

@ -14,29 +14,26 @@ namespace Dynarmic::Backend::RV64 {
class CodeBlock {
public:
explicit CodeBlock(std::size_t size)
: memsize(size) {
explicit CodeBlock(std::size_t size) noexcept : memsize(size) {
mem = (u8*)mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
if (mem == nullptr)
throw std::bad_alloc{};
ASSERT_FALSE("out of memory");
}
~CodeBlock() {
~CodeBlock() noexcept {
if (mem == nullptr)
return;
munmap(mem, memsize);
}
template<typename T>
T ptr() const {
T ptr() const noexcept {
static_assert(std::is_pointer_v<T> || std::is_same_v<T, uptr> || std::is_same_v<T, sptr>);
return reinterpret_cast<T>(mem);
}
protected:
u8* mem;
u8* mem = nullptr;
size_t memsize = 0;
};
} // namespace Dynarmic::Backend::RV64

View file

@ -124,9 +124,9 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
EmitCondPrelude(ctx);
for (auto iter = block.begin(); iter != block.end(); ++iter) {
IR::Inst* inst = &*iter;
auto const loop_all_inst = [this, &block, &ctx](auto const func) {
for (auto iter = block.begin(); iter != block.end(); ++iter) [[likely]] {
auto* inst = &*iter;
// Call the relevant Emit* member function.
switch (inst->GetOpcode()) {
#define OPCODE(name, type, ...) \
@ -135,24 +135,25 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
break;
#define A32OPC(name, type, ...) \
case IR::Opcode::A32##name: \
A32EmitX64::EmitA32##name(ctx, inst); \
A32EmitX64::EmitA32##name(ctx, inst);\
break;
#define A64OPC(...)
#include "dynarmic/ir/opcodes.inc"
#undef OPCODE
#undef A32OPC
#undef A64OPC
default:
ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode());
break;
default: [[unlikely]] ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode());
}
reg_alloc.EndOfAllocScope();
if (conf.very_verbose_debugging_output) {
EmitVerboseDebuggingOutput(reg_alloc);
func(reg_alloc);
}
};
if (!conf.very_verbose_debugging_output) [[likely]] {
loop_all_inst([](auto&) { /*noop*/ });
} else [[unlikely]] {
loop_all_inst([this](auto& reg_alloc) {
EmitVerboseDebuggingOutput(reg_alloc);
});
}
reg_alloc.AssertNoMoreUses();
@ -229,7 +230,7 @@ void A32EmitX64::GenTerminalHandlers() {
terminal_handler_pop_rsb_hint = code.getCurr<const void*>();
calculate_location_descriptor();
code.mov(eax, dword[r15 + offsetof(A32JitState, rsb_ptr)]);
code.sub(eax, 1);
code.dec(eax);
code.and_(eax, u32(A32JitState::RSBPtrMask));
code.mov(dword[r15 + offsetof(A32JitState, rsb_ptr)], eax);
code.cmp(rbx, qword[r15 + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]);

View file

@ -198,18 +198,19 @@ void A64EmitX64::GenTerminalHandlers() {
code.or_(rbx, rcx);
};
Xbyak::Label fast_dispatch_cache_miss, rsb_cache_miss;
Xbyak::Label fast_dispatch_cache_miss;
Xbyak::Label rsb_cache_miss;
code.align();
terminal_handler_pop_rsb_hint = code.getCurr<const void*>();
calculate_location_descriptor();
code.mov(eax, dword[r15 + offsetof(A64JitState, rsb_ptr)]);
code.sub(eax, 1);
code.dec(eax);
code.and_(eax, u32(A64JitState::RSBPtrMask));
code.mov(dword[r15 + offsetof(A64JitState, rsb_ptr)], eax);
code.cmp(rbx, qword[r15 + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]);
if (conf.HasOptimization(OptimizationFlag::FastDispatch)) {
code.jne(rsb_cache_miss);
code.jne(rsb_cache_miss, code.T_NEAR);
} else {
code.jne(code.GetReturnFromRunCodeAddress());
}

View file

@ -33,13 +33,13 @@ void A64EmitX64::GenMemory128Accessors() {
#ifdef _WIN32
Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCallWithReturnPointer(code, [&](Xbyak::Reg64 return_value_ptr, [[maybe_unused]] RegList args) {
code.mov(code.ABI_PARAM3, code.ABI_PARAM2);
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (8 + 16 + ABI_SHADOW_SPACE)]);
code.lea(return_value_ptr, ptr[rsp + ABI_SHADOW_SPACE]);
});
code.movups(xmm1, xword[code.ABI_RETURN]);
code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE);
#else
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCall(code);
if (code.HasHostFeature(HostFeature::SSE41)) {
code.movq(xmm1, code.ABI_RETURN);
@ -57,13 +57,13 @@ void A64EmitX64::GenMemory128Accessors() {
code.align();
memory_write_128 = code.getCurr<void (*)()>();
#ifdef _WIN32
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (8 + 16 + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
code.movaps(xword[code.ABI_PARAM3], xmm1);
Devirtualize<&A64::UserCallbacks::MemoryWrite128>(conf.callbacks).EmitCall(code);
code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE);
#else
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
if (code.HasHostFeature(HostFeature::SSE41)) {
code.movq(code.ABI_PARAM3, xmm1);
code.pextrq(code.ABI_PARAM4, xmm1, 1);
@ -81,7 +81,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.align();
memory_exclusive_write_128 = code.getCurr<void (*)()>();
#ifdef _WIN32
code.sub(rsp, 8 + 32 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (8 + 32 + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
code.lea(code.ABI_PARAM4, ptr[rsp + ABI_SHADOW_SPACE + 16]);
code.movaps(xword[code.ABI_PARAM3], xmm1);
@ -89,7 +89,7 @@ void A64EmitX64::GenMemory128Accessors() {
Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive128>(conf.callbacks).EmitCall(code);
code.add(rsp, 8 + 32 + ABI_SHADOW_SPACE);
#else
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
if (code.HasHostFeature(HostFeature::SSE41)) {
code.movq(code.ABI_PARAM3, xmm1);
code.pextrq(code.ABI_PARAM4, xmm1, 1);
@ -131,8 +131,8 @@ void A64EmitX64::GenFastmemFallbacks() {
{64, Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive64>(conf.callbacks)},
}};
for (bool ordered : {false, true}) {
for (int vaddr_idx : idxes) {
for (auto const ordered : {false, true}) {
for (auto const vaddr_idx : idxes) {
if (vaddr_idx == 4 || vaddr_idx == 15) {
continue;
}

View file

@ -63,7 +63,8 @@ public:
uint8_t* alloc(size_t size) override {
void* p = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
if (p == nullptr) {
throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC);
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
}
return static_cast<uint8_t*>(p);
}
@ -95,7 +96,8 @@ public:
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0);
if (p == MAP_FAILED) {
throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC);
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
}
std::memcpy(p, &size, sizeof(size_t));
return static_cast<uint8_t*>(p) + DYNARMIC_PAGE_SIZE;
@ -514,7 +516,8 @@ size_t BlockOfCode::GetTotalCodeSize() const {
void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) {
if (size_ + alloc_size >= maxSize_) {
throw Xbyak::Error(Xbyak::ERR_CODE_IS_TOO_BIG);
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CODE_IS_TOO_BIG);
}
EnsureMemoryCommitted(alloc_size);

View file

@ -104,7 +104,7 @@ void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, I
}
void EmitX64::EmitVerboseDebuggingOutput(RegAlloc& reg_alloc) {
code.sub(rsp, sizeof(RegisterData));
code.lea(rsp, ptr[rsp - sizeof(RegisterData)]);
code.stmxcsr(dword[rsp + offsetof(RegisterData, mxcsr)]);
for (int i = 0; i < 16; i++) {
if (rsp.getIdx() == i) {
@ -223,7 +223,7 @@ void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize);
code.test(value, value);
code.lahf();
code.mov(al, 0);
code.xor_(al, al);
ctx.reg_alloc.DefineValue(inst, nzcv);
}
@ -270,7 +270,6 @@ void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) {
code.shr(nzcv, 28);
code.imul(nzcv, nzcv, NZCV::to_x64_multiplier);
code.and_(nzcv, NZCV::x64_mask);
ctx.reg_alloc.DefineValue(inst, nzcv);
}
}
@ -331,10 +330,8 @@ Xbyak::Label EmitX64::EmitCond(IR::Cond cond) {
code.jle(pass);
break;
default:
ASSERT_MSG(false, "Unknown cond {}", static_cast<size_t>(cond));
break;
UNREACHABLE();
}
return pass;
}

View file

@ -992,7 +992,6 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
code.seto(overflow);
ctx.reg_alloc.DefineValue(overflow_inst, overflow);
}
ctx.reg_alloc.DefineValue(inst, result);
}

View file

@ -33,6 +33,23 @@
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
@ -60,23 +77,6 @@ constexpr u64 f64_max_s32 = 0x41dfffffffc00000u; // 2147483647 as a double
constexpr u64 f64_max_u32 = 0x41efffffffe00000u; // 4294967295 as a double
constexpr u64 f64_max_s64_lim = 0x43e0000000000000u; // 2^63 as a double (actual maximum unrepresentable)
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
template<size_t fsize>
void ForceDenormalsToZero(BlockOfCode& code, std::initializer_list<Xbyak::Xmm> to_daz) {
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
@ -473,7 +473,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
}
template<size_t fsize, bool is_max>
static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) noexcept {
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT default_nan = FP::FPInfo<FPT>::DefaultNaN();
@ -701,15 +701,14 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
// x64 rounds before flushing to zero
// AArch64 rounds after flushing to zero
// This difference of behaviour is noticable if something would round to a smallest normalized number
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
code.movq(code.ABI_PARAM3, operand3);
code.mov(code.ABI_PARAM4.cvt32(), ctx.FPCR().Value());
#ifdef _WIN32
code.sub(rsp, 16 + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (16 + ABI_SHADOW_SPACE)]);
code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.mov(qword[rsp + ABI_SHADOW_SPACE], rax);
code.CallFunction(fallback_fn);
@ -735,13 +734,13 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.vmovaps(xmm0, code.Const(xword, FP::FPInfo<FPT>::mantissa_msb));
FCODE(ucomis)(operand2, operand3);
code.jp(has_nan);
code.jp(has_nan, code.T_NEAR);
FCODE(ucomis)(operand1, operand1);
code.jnp(indeterminate);
code.jnp(indeterminate, code.T_NEAR);
// AArch64 specifically emits a default NaN for the case when the addend is a QNaN and the two other arguments are {inf, zero}
code.ptest(operand1, xmm0);
code.jz(op1_snan);
code.jz(op1_snan, code.T_NEAR);
FCODE(vmuls)(xmm0, operand2, operand3); // check if {op2, op3} are {inf, zero}/{zero, inf}
FCODE(ucomis)(xmm0, xmm0);
code.jnp(*end);
@ -753,10 +752,10 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.L(has_nan);
FCODE(ucomis)(operand1, operand1);
code.jnp(op1_done);
code.jnp(op1_done, code.T_NEAR);
code.movaps(result, operand1); // this is done because of NaN behavior of vfmadd231s (priority of op2, op3, op1)
code.ptest(operand1, xmm0);
code.jnz(op1_done);
code.jnz(op1_done, code.T_NEAR);
code.L(op1_snan);
code.vorps(result, operand1, xmm0);
code.jmp(*end);
@ -774,9 +773,9 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.L(op2_done);
FCODE(ucomis)(operand3, operand3);
code.jnp(op3_done);
code.jnp(op3_done, code.T_NEAR);
code.ptest(operand3, xmm0);
code.jnz(op3_done);
code.jnz(op3_done, code.T_NEAR);
code.vorps(result, operand3, xmm0);
code.jmp(*end);
code.L(op3_done);
@ -1019,7 +1018,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
@ -1204,9 +1203,9 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
}
// a > 0 && a < 0x00800000;
code.sub(tmp, 1);
code.dec(tmp);
code.cmp(tmp, 0x007FFFFF);
code.jb(fallback);
code.jb(fallback, code.T_NEAR); //within -127,128
needs_fallback = true;
}
@ -1235,17 +1234,17 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
code.ucomisd(value, result);
if (ctx.FPCR().DN()) {
code.jc(default_nan);
code.je(zero);
code.jc(default_nan, code.T_NEAR);
code.je(zero, code.T_NEAR);
} else {
code.jp(nan);
code.je(zero);
code.jc(default_nan);
code.jp(nan, code.T_NEAR);
code.je(zero, code.T_NEAR);
code.jc(default_nan, code.T_NEAR);
}
if (!ctx.FPCR().FZ()) {
needs_fallback = true;
code.jmp(fallback);
code.jmp(fallback, code.T_NEAR);
} else {
// result = 0
code.jmp(*end, code.T_NEAR);
@ -1278,7 +1277,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
code.L(fallback);
if (needs_fallback) {
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
@ -1361,7 +1360,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst*
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
code.movq(code.ABI_PARAM1, operand1);
code.movq(code.ABI_PARAM2, operand2);
@ -2132,3 +2131,6 @@ void EmitX64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
} // namespace Dynarmic::Backend::X64
#undef FCODE
#undef ICODE

View file

@ -161,8 +161,7 @@ template<>
template<>
[[maybe_unused]] Xbyak::RegExp EmitFastmemVAddr<A64EmitContext>(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling, std::optional<Xbyak::Reg64> tmp) {
const size_t unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits;
auto const unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits;
if (unused_top_bits == 0) {
return r13 + vaddr;
} else if (ctx.conf.silently_mirror_fastmem) {
@ -306,7 +305,7 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int
code.L(loop);
code.lock();
code.cmpxchg16b(xword[addr]);
code.jnz(loop);
code.jnz(loop, code.T_NEAR);
break;
}
default:
@ -373,7 +372,7 @@ void EmitExclusiveTestAndClear(BlockOfCode& code, const UserConfig& conf, Xbyak:
Xbyak::Label ok;
code.mov(pointer, mcl::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, processor_index)));
code.cmp(qword[pointer], vaddr);
code.jne(ok);
code.jne(ok, code.T_NEAR);
code.mov(qword[pointer], tmp);
code.L(ok);
}

View file

@ -33,13 +33,6 @@
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
namespace mp = mcl::mp;
namespace {
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
@ -57,6 +50,13 @@ namespace {
} \
}
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
namespace mp = mcl::mp;
namespace {
template<typename Lambda>
void MaybeStandardFPSCRValue(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, Lambda lambda) {
const bool switch_mxcsr = ctx.FPCR(fpcr_controlled) != ctx.FPCR();
@ -122,11 +122,11 @@ void HandleNaNs(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, std::
const Xbyak::Xmm result = xmms[0];
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
const size_t stack_space = xmms.size() * 16;
code.sub(rsp, static_cast<u32>(stack_space + ABI_SHADOW_SPACE));
code.lea(rsp, ptr[rsp - static_cast<u32>(stack_space + ABI_SHADOW_SPACE)]);
for (size_t i = 0; i < xmms.size(); ++i) {
code.movaps(xword[rsp + ABI_SHADOW_SPACE + i * 16], xmms[i]);
}
@ -443,7 +443,7 @@ void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak
const u32 fpcr = ctx.FPCR(fpcr_controlled).Value();
constexpr u32 stack_space = 2 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.mov(code.ABI_PARAM3.cvt32(), fpcr);
@ -479,7 +479,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby
#ifdef _WIN32
constexpr u32 stack_space = 4 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]);
@ -488,7 +488,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby
code.mov(qword[rsp + ABI_SHADOW_SPACE + 0], rax);
#else
constexpr u32 stack_space = 3 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
@ -536,7 +536,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya
#ifdef _WIN32
constexpr u32 stack_space = 5 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]);
@ -546,7 +546,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya
code.mov(qword[rsp + ABI_SHADOW_SPACE + 8], rax);
#else
constexpr u32 stack_space = 4 * 16;
code.sub(rsp, stack_space + ABI_SHADOW_SPACE);
code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]);
code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]);
code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]);
@ -1371,7 +1371,7 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
if (needs_rounding_correction && needs_nan_correction) {
EmitFourOpFallbackWithoutRegAlloc<LoadPreviousResult::Yes>(code, ctx, result, xmm_a, xmm_b, xmm_c, EmitFPVectorMulAddFallback<FPT, true, true>, fpcr_controlled);
@ -1635,7 +1635,7 @@ static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
@ -1812,7 +1812,7 @@ static void EmitRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* ins
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*bad_values);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitTwoOpFallbackWithoutRegAlloc(code, ctx, result, operand, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
@ -1898,7 +1898,7 @@ static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
code.L(*fallback);
code.sub(rsp, 8);
code.lea(rsp, ptr[rsp - 8]);
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx()));
@ -2180,3 +2180,6 @@ void EmitX64::EmitFPVectorToUnsignedFixed64(EmitContext& ctx, IR::Inst* inst) {
}
} // namespace Dynarmic::Backend::X64
#undef FCODE
#undef ICODE

View file

@ -338,3 +338,6 @@ void EmitX64::EmitVectorUnsignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst)
}
} // namespace Dynarmic::Backend::X64
#undef FCODE
#undef ICODE

View file

@ -186,7 +186,7 @@ struct ExceptionHandler::Impl final {
code.cmp(code.rax, static_cast<u32>(code.GetTotalCodeSize()));
code.ja(exception_handler_without_cb);
code.sub(code.rsp, 8);
code.lea(code.rsp, code.ptr[code.rsp - 8]);
code.mov(code.ABI_PARAM1, mcl::bit_cast<u64>(&cb));
code.mov(code.ABI_PARAM2, code.ABI_PARAM3);
code.CallLambda(

View file

@ -15,7 +15,7 @@
namespace Dynarmic::A32 {
enum class ArchVersion;
enum class ArchVersion : std::uint8_t;
enum class CoprocReg;
enum class Exception;
enum class ExtReg;
@ -27,12 +27,11 @@ enum class Reg;
* The user of this class updates `current_location` as appropriate.
*/
class IREmitter : public IR::IREmitter {
IR::U64 ImmCurrentLocationDescriptor();
public:
IREmitter(IR::Block& block, LocationDescriptor descriptor, ArchVersion arch_version)
: IR::IREmitter(block), current_location(descriptor), arch_version(arch_version) {}
LocationDescriptor current_location;
size_t ArchVersion() const;
u32 PC() const;
@ -107,10 +106,9 @@ public:
IR::U64 CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm);
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option);
private:
public:
LocationDescriptor current_location;
enum ArchVersion arch_version;
IR::U64 ImmCurrentLocationDescriptor();
};
} // namespace Dynarmic::A32

View file

@ -33,13 +33,11 @@ inline size_t ToFastLookupIndexArm(u32 instruction) {
} // namespace detail
template<typename V>
ArmDecodeTable<V> GetArmDecodeTable() {
constexpr ArmDecodeTable<V> GetArmDecodeTable() {
std::vector<ArmMatcher<V>> list = {
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./arm.inc"
#undef INST
};
// If a matcher has more bits in its mask it is more specific, so it should come first.
@ -62,9 +60,10 @@ ArmDecodeTable<V> GetArmDecodeTable() {
template<typename V>
std::optional<std::reference_wrapper<const ArmMatcher<V>>> DecodeArm(u32 instruction) {
static const auto table = GetArmDecodeTable<V>();
const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); };
alignas(64) static const auto table = GetArmDecodeTable<V>();
const auto matches_instruction = [instruction](const auto& matcher) {
return matcher.Matches(instruction);
};
const auto& subtable = table[detail::ToFastLookupIndexArm(instruction)];
auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction);

View file

@ -25,3 +25,51 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
}
} // namespace Dynarmic::A32
// ls -l | awk '{print "#include \"dynarmic/frontend/A32/translate/impl/" $9 "\""}'
#include "dynarmic/frontend/A32/translate/impl/a32_branch.cpp"
#include "dynarmic/frontend/A32/translate/impl/a32_crc32.cpp"
#include "dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp"
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp"
//#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp"
#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp"
#include "dynarmic/frontend/A32/translate/impl/barrier.cpp"
#include "dynarmic/frontend/A32/translate/impl/coprocessor.cpp"
#include "dynarmic/frontend/A32/translate/impl/data_processing.cpp"
#include "dynarmic/frontend/A32/translate/impl/divide.cpp"
#include "dynarmic/frontend/A32/translate/impl/extension.cpp"
#include "dynarmic/frontend/A32/translate/impl/hint.cpp"
#include "dynarmic/frontend/A32/translate/impl/load_store.cpp"
#include "dynarmic/frontend/A32/translate/impl/misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/multiply.cpp"
#include "dynarmic/frontend/A32/translate/impl/packing.cpp"
#include "dynarmic/frontend/A32/translate/impl/parallel.cpp"
#include "dynarmic/frontend/A32/translate/impl/reversal.cpp"
#include "dynarmic/frontend/A32/translate/impl/saturated.cpp"
#include "dynarmic/frontend/A32/translate/impl/status_register_access.cpp"
#include "dynarmic/frontend/A32/translate/impl/synchronization.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb16.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_control.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_long_multiply.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_misc.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp"
#include "dynarmic/frontend/A32/translate/impl/thumb32_store_single_data_item.cpp"
#include "dynarmic/frontend/A32/translate/impl/vfp.cpp"

View file

@ -11,6 +11,10 @@
namespace Dynarmic::A32 {
bool TranslatorVisitor::arm_NOP() {
return true;
}
bool TranslatorVisitor::ArmConditionPassed(Cond cond) {
return IsConditionPassed(*this, cond);
}

View file

@ -258,7 +258,7 @@ struct TranslatorVisitor final {
bool arm_CLZ(Cond cond, Reg d, Reg m);
bool arm_MOVT(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12);
bool arm_MOVW(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12);
bool arm_NOP() { return true; }
bool arm_NOP();
bool arm_RBIT(Cond cond, Reg d, Reg m);
bool arm_SBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n);
bool arm_SEL(Cond cond, Reg n, Reg d, Reg m);

View file

@ -6,6 +6,7 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
namespace {
@ -17,11 +18,6 @@ enum class Comparison {
AbsoluteGT,
};
enum class AccumulateBehavior {
None,
Accumulate,
};
enum class WidenBehaviour {
Second,
Both,

View file

@ -8,10 +8,11 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
namespace {
enum class Comparison {
enum class ComparisonATRM {
EQ,
GE,
GT,
@ -19,7 +20,7 @@ enum class Comparison {
LT,
};
bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, Comparison type) {
bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, ComparisonATRM type) {
if (sz == 0b11 || (F && sz != 0b10)) {
return v.UndefinedInstruction();
}
@ -36,15 +37,15 @@ bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F,
if (F) {
switch (type) {
case Comparison::EQ:
case ComparisonATRM::EQ:
return v.ir.FPVectorEqual(32, reg_m, zero, false);
case Comparison::GE:
case ComparisonATRM::GE:
return v.ir.FPVectorGreaterEqual(32, reg_m, zero, false);
case Comparison::GT:
case ComparisonATRM::GT:
return v.ir.FPVectorGreater(32, reg_m, zero, false);
case Comparison::LE:
case ComparisonATRM::LE:
return v.ir.FPVectorGreaterEqual(32, zero, reg_m, false);
case Comparison::LT:
case ComparisonATRM::LT:
return v.ir.FPVectorGreater(32, zero, reg_m, false);
}
@ -67,11 +68,6 @@ bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F,
return true;
}
enum class AccumulateBehavior {
None,
Accumulate,
};
bool PairedAddOperation(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool op, bool Q, bool M, size_t Vm, AccumulateBehavior accumulate) {
if (sz == 0b11) {
return v.UndefinedInstruction();
@ -385,23 +381,23 @@ bool TranslatorVisitor::asimd_VQNEG(bool D, size_t sz, size_t Vd, bool Q, bool M
}
bool TranslatorVisitor::asimd_VCGT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GT);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::GT);
}
bool TranslatorVisitor::asimd_VCGE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GE);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::GE);
}
bool TranslatorVisitor::asimd_VCEQ_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::EQ);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::EQ);
}
bool TranslatorVisitor::asimd_VCLE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LE);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::LE);
}
bool TranslatorVisitor::asimd_VCLT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LT);
return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::LT);
}
bool TranslatorVisitor::asimd_VABS(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {

View file

@ -16,7 +16,7 @@ enum class Accumulating {
Accumulate
};
enum class Rounding {
enum class RoundingATRS {
None,
Round,
};
@ -32,7 +32,7 @@ enum class Signedness {
Unsigned
};
IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) {
IR::U128 PerformRoundingATRSCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) {
const auto round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value));
const auto round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(original, round_const), round_const);
return v.ir.VectorSub(esize, shifted, round_correction);
@ -58,7 +58,7 @@ std::pair<size_t, size_t> ElementSizeAndShiftAmount(bool right_shift, bool L, si
}
}
bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, Accumulating accumulate, Rounding rounding) {
bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, Accumulating accumulate, RoundingATRS RoundingATRS) {
if (!L && mcl::bit::get_bits<3, 5>(imm6) == 0) {
return v.DecodeError();
}
@ -75,9 +75,9 @@ bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bo
auto result = U ? v.ir.VectorLogicalShiftRight(esize, reg_m, static_cast<u8>(shift_amount))
: v.ir.VectorArithmeticShiftRight(esize, reg_m, static_cast<u8>(shift_amount));
if (rounding == Rounding::Round) {
if (RoundingATRS == RoundingATRS::Round) {
const u64 round_value = 1ULL << (shift_amount - 1);
result = PerformRoundingCorrection(v, esize, round_value, reg_m, result);
result = PerformRoundingATRSCorrection(v, esize, round_value, reg_m, result);
}
if (accumulate == Accumulating::Accumulate) {
@ -89,7 +89,7 @@ bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bo
return true;
}
bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, bool M, size_t Vm, Rounding rounding, Narrowing narrowing, Signedness signedness) {
bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, bool M, size_t Vm, RoundingATRS RoundingATRS, Narrowing narrowing, Signedness signedness) {
if (mcl::bit::get_bits<3, 5>(imm6) == 0) {
return v.DecodeError();
}
@ -113,9 +113,9 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, b
return v.ir.VectorLogicalShiftRight(source_esize, reg_m, shift_amount);
}();
if (rounding == Rounding::Round) {
if (RoundingATRS == RoundingATRS::Round) {
const u64 round_value = 1ULL << (shift_amount - 1);
wide_result = PerformRoundingCorrection(v, source_esize, round_value, reg_m, wide_result);
wide_result = PerformRoundingATRSCorrection(v, source_esize, round_value, reg_m, wide_result);
}
const auto result = [&] {
@ -141,22 +141,22 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, b
bool TranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::None, Rounding::None);
Accumulating::None, RoundingATRS::None);
}
bool TranslatorVisitor::asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::Accumulate, Rounding::None);
Accumulating::Accumulate, RoundingATRS::None);
}
bool TranslatorVisitor::asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::None, Rounding::Round);
Accumulating::None, RoundingATRS::Round);
}
bool TranslatorVisitor::asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm,
Accumulating::Accumulate, Rounding::Round);
Accumulating::Accumulate, RoundingATRS::Round);
}
bool TranslatorVisitor::asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) {
@ -271,32 +271,32 @@ bool TranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool
bool TranslatorVisitor::asimd_VSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::None, Narrowing::Truncation, Signedness::Unsigned);
RoundingATRS::None, Narrowing::Truncation, Signedness::Unsigned);
}
bool TranslatorVisitor::asimd_VRSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::Round, Narrowing::Truncation, Signedness::Unsigned);
RoundingATRS::Round, Narrowing::Truncation, Signedness::Unsigned);
}
bool TranslatorVisitor::asimd_VQRSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Signed);
RoundingATRS::Round, Narrowing::SaturateToUnsigned, Signedness::Signed);
}
bool TranslatorVisitor::asimd_VQSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Signed);
RoundingATRS::None, Narrowing::SaturateToUnsigned, Signedness::Signed);
}
bool TranslatorVisitor::asimd_VQSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::None, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
RoundingATRS::None, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
}
bool TranslatorVisitor::asimd_VQRSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {
return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm,
Rounding::Round, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
RoundingATRS::Round, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed);
}
bool TranslatorVisitor::asimd_VSHLL(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) {

View file

@ -0,0 +1,31 @@
#pragma once
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
namespace Dynarmic::A32 {
static inline IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) noexcept {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static inline IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) noexcept {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
static inline IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) noexcept {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
static inline bool ITBlockCheck(const A32::IREmitter& ir) noexcept {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
using ExtensionFunctionU16 = IR::U32 (IREmitter::*)(const IR::U16&);
enum class AccumulateBehavior {
None,
Accumulate,
};
}

View file

@ -4,14 +4,10 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
// SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
bool TranslatorVisitor::arm_SXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
if (d == Reg::PC || m == Reg::PC) {

View file

@ -4,17 +4,10 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
// Saturation instructions
// SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}

View file

@ -7,15 +7,9 @@
#include <mcl/bitsizeof.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
using SaturationFunction = IR::ResultAndOverflow<IR::U32> (IREmitter::*)(const IR::U32&, size_t);

View file

@ -4,13 +4,10 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
namespace {
IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
using ShiftFunction = IR::ResultAndCarry<IR::U32> (IREmitter::*)(const IR::U32&, const IR::U8&, const IR::U1&);

View file

@ -25,9 +25,9 @@ static bool PLIHandler(TranslatorVisitor& v) {
return v.RaiseException(Exception::PreloadInstruction);
}
using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U8&);
using ExtensionFunctionU8 = IR::U32 (IREmitter::*)(const IR::U8&);
static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunctionU8 ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const u32 base = v.ir.AlignPC(4);
const u32 address = U ? (base + imm32) : (base - imm32);
@ -37,7 +37,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
return true;
}
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunctionU8 ext_fn) {
if (m == Reg::PC) {
return v.UnpredictableInstruction();
}
@ -52,7 +52,7 @@ static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
return true;
}
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunctionU8 ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const IR::U32 reg_n = v.ir.GetRegister(n);
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))

View file

@ -4,12 +4,11 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U16&);
static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunctionU16 ext_fn) {
const auto imm32 = imm12.ZeroExtend();
const auto base = v.ir.AlignPC(4);
const auto address = U ? (base + imm32) : (base - imm32);
@ -19,7 +18,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
return true;
}
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) {
static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunctionU16 ext_fn) {
if (m == Reg::PC) {
return v.UnpredictableInstruction();
}
@ -34,7 +33,7 @@ static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re
return true;
}
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) {
static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunctionU16 ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const IR::U32 reg_n = v.ir.GetRegister(n);
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))

View file

@ -6,11 +6,9 @@
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) {
if (m == Reg::PC) {

View file

@ -6,11 +6,9 @@
#include <mcl/bit/bit_count.hpp>
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) {
auto address = start_address;

View file

@ -4,11 +4,9 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static bool ITBlockCheck(const A32::IREmitter& ir) {
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
}
bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) {
if (t == Reg::PC && ITBlockCheck(ir)) {

View file

@ -4,15 +4,9 @@
*/
#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h"
#include "dynarmic/frontend/A32/translate/impl/common.h"
namespace Dynarmic::A32 {
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
}
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
}
bool TranslatorVisitor::thumb32_SADD8(Reg n, Reg d, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {

View file

@ -5,261 +5,7 @@
#include "dynarmic/frontend/A64/a64_ir_emitter.h"
#include <mcl/assert.hpp>
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::A64 {
using Opcode = IR::Opcode;
u64 IREmitter::PC() const {
return current_location->PC();
}
u64 IREmitter::AlignPC(size_t alignment) const {
const u64 pc = PC();
return static_cast<u64>(pc - pc % alignment);
}
void IREmitter::SetCheckBit(const IR::U1& value) {
Inst(Opcode::A64SetCheckBit, value);
}
IR::U1 IREmitter::GetCFlag() {
return Inst<IR::U1>(Opcode::A64GetCFlag);
}
IR::U32 IREmitter::GetNZCVRaw() {
return Inst<IR::U32>(Opcode::A64GetNZCVRaw);
}
void IREmitter::SetNZCVRaw(IR::U32 value) {
Inst(Opcode::A64SetNZCVRaw, value);
}
void IREmitter::SetNZCV(const IR::NZCV& nzcv) {
Inst(Opcode::A64SetNZCV, nzcv);
}
void IREmitter::CallSupervisor(u32 imm) {
Inst(Opcode::A64CallSupervisor, Imm32(imm));
}
void IREmitter::ExceptionRaised(Exception exception) {
Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast<u64>(exception)));
}
void IREmitter::DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) {
Inst(Opcode::A64DataCacheOperationRaised, ImmCurrentLocationDescriptor(), Imm64(static_cast<u64>(op)), value);
}
void IREmitter::InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) {
Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast<u64>(op)), value);
}
void IREmitter::DataSynchronizationBarrier() {
Inst(Opcode::A64DataSynchronizationBarrier);
}
void IREmitter::DataMemoryBarrier() {
Inst(Opcode::A64DataMemoryBarrier);
}
void IREmitter::InstructionSynchronizationBarrier() {
Inst(Opcode::A64InstructionSynchronizationBarrier);
}
IR::U32 IREmitter::GetCNTFRQ() {
return Inst<IR::U32>(Opcode::A64GetCNTFRQ);
}
IR::U64 IREmitter::GetCNTPCT() {
return Inst<IR::U64>(Opcode::A64GetCNTPCT);
}
IR::U32 IREmitter::GetCTR() {
return Inst<IR::U32>(Opcode::A64GetCTR);
}
IR::U32 IREmitter::GetDCZID() {
return Inst<IR::U32>(Opcode::A64GetDCZID);
}
IR::U64 IREmitter::GetTPIDR() {
return Inst<IR::U64>(Opcode::A64GetTPIDR);
}
void IREmitter::SetTPIDR(const IR::U64& value) {
Inst(Opcode::A64SetTPIDR, value);
}
IR::U64 IREmitter::GetTPIDRRO() {
return Inst<IR::U64>(Opcode::A64GetTPIDRRO);
}
void IREmitter::ClearExclusive() {
Inst(Opcode::A64ClearExclusive);
}
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A64ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U16>(Opcode::A64ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U64>(Opcode::A64ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U128>(Opcode::A64ReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) {
return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) {
Inst(Opcode::A64WriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 IREmitter::GetW(Reg reg) {
if (reg == Reg::ZR)
return Imm32(0);
return Inst<IR::U32>(Opcode::A64GetW, IR::Value(reg));
}
IR::U64 IREmitter::GetX(Reg reg) {
if (reg == Reg::ZR)
return Imm64(0);
return Inst<IR::U64>(Opcode::A64GetX, IR::Value(reg));
}
IR::U128 IREmitter::GetS(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetS, IR::Value(vec));
}
IR::U128 IREmitter::GetD(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetD, IR::Value(vec));
}
IR::U128 IREmitter::GetQ(Vec vec) {
return Inst<IR::U128>(Opcode::A64GetQ, IR::Value(vec));
}
IR::U64 IREmitter::GetSP() {
return Inst<IR::U64>(Opcode::A64GetSP);
}
IR::U32 IREmitter::GetFPCR() {
return Inst<IR::U32>(Opcode::A64GetFPCR);
}
IR::U32 IREmitter::GetFPSR() {
return Inst<IR::U32>(Opcode::A64GetFPSR);
}
void IREmitter::SetW(const Reg reg, const IR::U32& value) {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetW, IR::Value(reg), value);
}
void IREmitter::SetX(const Reg reg, const IR::U64& value) {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetX, IR::Value(reg), value);
}
void IREmitter::SetS(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetS, IR::Value(vec), value);
}
void IREmitter::SetD(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetD, IR::Value(vec), value);
}
void IREmitter::SetQ(const Vec vec, const IR::U128& value) {
Inst(Opcode::A64SetQ, IR::Value(vec), value);
}
void IREmitter::SetSP(const IR::U64& value) {
Inst(Opcode::A64SetSP, value);
}
void IREmitter::SetFPCR(const IR::U32& value) {
Inst(Opcode::A64SetFPCR, value);
}
void IREmitter::SetFPSR(const IR::U32& value) {
Inst(Opcode::A64SetFPSR, value);
}
void IREmitter::SetPC(const IR::U64& value) {
Inst(Opcode::A64SetPC, value);
}
IR::U64 IREmitter::ImmCurrentLocationDescriptor() {
return Imm64(IR::LocationDescriptor{*current_location}.Value());
}
} // namespace Dynarmic::A64

View file

@ -8,12 +8,14 @@
#include <optional>
#include <mcl/stdint.hpp>
#include <mcl/assert.hpp>
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/ir_emitter.h"
#include "dynarmic/ir/value.h"
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::A64 {
@ -24,79 +26,262 @@ namespace Dynarmic::A64 {
*/
class IREmitter : public IR::IREmitter {
public:
explicit IREmitter(IR::Block& block)
: IR::IREmitter(block) {}
explicit IREmitter(IR::Block& block, LocationDescriptor descriptor)
: IR::IREmitter(block), current_location(descriptor) {}
explicit IREmitter(IR::Block& block) : IR::IREmitter(block) {}
explicit IREmitter(IR::Block& block, LocationDescriptor descriptor) : IR::IREmitter(block), current_location(descriptor) {}
std::optional<LocationDescriptor> current_location;
u64 PC() const;
u64 AlignPC(size_t alignment) const;
using Opcode = IR::Opcode;
void SetCheckBit(const IR::U1& value);
IR::U1 GetCFlag();
IR::U32 GetNZCVRaw();
void SetNZCVRaw(IR::U32 value);
void SetNZCV(const IR::NZCV& nzcv);
u64 PC() const noexcept {
return current_location->PC();
}
void CallSupervisor(u32 imm);
void ExceptionRaised(Exception exception);
void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value);
void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value);
void DataSynchronizationBarrier();
void DataMemoryBarrier();
void InstructionSynchronizationBarrier();
IR::U32 GetCNTFRQ();
IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this.
IR::U32 GetCTR();
IR::U32 GetDCZID();
IR::U64 GetTPIDR();
IR::U64 GetTPIDRRO();
void SetTPIDR(const IR::U64& value);
u64 AlignPC(size_t alignment) const noexcept {
const u64 pc = PC();
return static_cast<u64>(pc - pc % alignment);
}
void ClearExclusive();
IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type);
IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type);
IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type);
IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type);
IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type);
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type);
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type);
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type);
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type);
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type);
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type);
void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type);
void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type);
void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type);
void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type);
IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type);
void SetCheckBit(const IR::U1& value) noexcept {
Inst(Opcode::A64SetCheckBit, value);
}
IR::U32 GetW(Reg source_reg);
IR::U64 GetX(Reg source_reg);
IR::U128 GetS(Vec source_vec);
IR::U128 GetD(Vec source_vec);
IR::U128 GetQ(Vec source_vec);
IR::U64 GetSP();
IR::U32 GetFPCR();
IR::U32 GetFPSR();
void SetW(Reg dest_reg, const IR::U32& value);
void SetX(Reg dest_reg, const IR::U64& value);
void SetS(Vec dest_vec, const IR::U128& value);
void SetD(Vec dest_vec, const IR::U128& value);
void SetQ(Vec dest_vec, const IR::U128& value);
void SetSP(const IR::U64& value);
void SetFPCR(const IR::U32& value);
void SetFPSR(const IR::U32& value);
void SetPC(const IR::U64& value);
IR::U1 GetCFlag() noexcept {
return Inst<IR::U1>(Opcode::A64GetCFlag);
}
IR::U32 GetNZCVRaw() noexcept {
return Inst<IR::U32>(Opcode::A64GetNZCVRaw);
}
void SetNZCVRaw(IR::U32 value) noexcept {
Inst(Opcode::A64SetNZCVRaw, value);
}
void SetNZCV(const IR::NZCV& nzcv) noexcept {
Inst(Opcode::A64SetNZCV, nzcv);
}
void CallSupervisor(u32 imm) noexcept {
Inst(Opcode::A64CallSupervisor, Imm32(imm));
}
void ExceptionRaised(Exception exception) noexcept {
Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast<u64>(exception)));
}
void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) noexcept {
Inst(Opcode::A64DataCacheOperationRaised, ImmCurrentLocationDescriptor(), Imm64(static_cast<u64>(op)), value);
}
void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) noexcept {
Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast<u64>(op)), value);
}
void DataSynchronizationBarrier() noexcept {
Inst(Opcode::A64DataSynchronizationBarrier);
}
void DataMemoryBarrier() noexcept {
Inst(Opcode::A64DataMemoryBarrier);
}
void InstructionSynchronizationBarrier() noexcept {
Inst(Opcode::A64InstructionSynchronizationBarrier);
}
IR::U32 GetCNTFRQ() noexcept {
return Inst<IR::U32>(Opcode::A64GetCNTFRQ);
}
IR::U64 GetCNTPCT() noexcept {
return Inst<IR::U64>(Opcode::A64GetCNTPCT);
}
IR::U32 GetCTR() noexcept {
return Inst<IR::U32>(Opcode::A64GetCTR);
}
IR::U32 GetDCZID() noexcept {
return Inst<IR::U32>(Opcode::A64GetDCZID);
}
IR::U64 GetTPIDR() noexcept {
return Inst<IR::U64>(Opcode::A64GetTPIDR);
}
void SetTPIDR(const IR::U64& value) noexcept {
Inst(Opcode::A64SetTPIDR, value);
}
IR::U64 GetTPIDRRO() noexcept {
return Inst<IR::U64>(Opcode::A64GetTPIDRRO);
}
void ClearExclusive() noexcept {
Inst(Opcode::A64ClearExclusive);
}
IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U8>(Opcode::A64ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U16>(Opcode::A64ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U64>(Opcode::A64ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U128>(Opcode::A64ReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U8>(Opcode::A64ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U16>(Opcode::A64ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U64>(Opcode::A64ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) noexcept {
return Inst<IR::U128>(Opcode::A64ExclusiveReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type});
}
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) noexcept {
Inst(Opcode::A64WriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) noexcept {
return Inst<IR::U32>(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type});
}
IR::U32 GetW(Reg reg) noexcept {
if (reg == Reg::ZR)
return Imm32(0);
return Inst<IR::U32>(Opcode::A64GetW, IR::Value(reg));
}
IR::U64 GetX(Reg reg) noexcept {
if (reg == Reg::ZR)
return Imm64(0);
return Inst<IR::U64>(Opcode::A64GetX, IR::Value(reg));
}
IR::U128 GetS(Vec vec) noexcept {
return Inst<IR::U128>(Opcode::A64GetS, IR::Value(vec));
}
IR::U128 GetD(Vec vec) noexcept {
return Inst<IR::U128>(Opcode::A64GetD, IR::Value(vec));
}
IR::U128 GetQ(Vec vec) noexcept {
return Inst<IR::U128>(Opcode::A64GetQ, IR::Value(vec));
}
IR::U64 GetSP() noexcept {
return Inst<IR::U64>(Opcode::A64GetSP);
}
IR::U32 GetFPCR() noexcept {
return Inst<IR::U32>(Opcode::A64GetFPCR);
}
IR::U32 GetFPSR() noexcept {
return Inst<IR::U32>(Opcode::A64GetFPSR);
}
void SetW(const Reg reg, const IR::U32& value) noexcept {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetW, IR::Value(reg), value);
}
void SetX(const Reg reg, const IR::U64& value) noexcept {
if (reg == Reg::ZR)
return;
Inst(Opcode::A64SetX, IR::Value(reg), value);
}
void SetS(const Vec vec, const IR::U128& value) noexcept {
Inst(Opcode::A64SetS, IR::Value(vec), value);
}
void SetD(const Vec vec, const IR::U128& value) noexcept {
Inst(Opcode::A64SetD, IR::Value(vec), value);
}
void SetQ(const Vec vec, const IR::U128& value) noexcept {
Inst(Opcode::A64SetQ, IR::Value(vec), value);
}
void SetSP(const IR::U64& value) noexcept {
Inst(Opcode::A64SetSP, value);
}
void SetFPCR(const IR::U32& value) noexcept {
Inst(Opcode::A64SetFPCR, value);
}
void SetFPSR(const IR::U32& value) noexcept {
Inst(Opcode::A64SetFPSR, value);
}
void SetPC(const IR::U64& value) noexcept {
Inst(Opcode::A64SetPC, value);
}
private:
IR::U64 ImmCurrentLocationDescriptor();
IR::U64 ImmCurrentLocationDescriptor() noexcept {
return Imm64(IR::LocationDescriptor{*current_location}.Value());
}
};
} // namespace Dynarmic::A64

View file

@ -33,27 +33,26 @@ inline size_t ToFastLookupIndex(u32 instruction) {
} // namespace detail
template<typename V>
DecodeTable<V> GetDecodeTable() {
constexpr DecodeTable<V> GetDecodeTable() {
std::vector<Matcher<V>> list = {
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
#include "./a64.inc"
#undef INST
};
// If a matcher has more bits in its mask it is more specific, so it should come first.
std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) {
// If a matcher has more bits in its mask it is more specific, so it should come first.
return mcl::bit::count_ones(matcher1.GetMask()) > mcl::bit::count_ones(matcher2.GetMask());
});
// Exceptions to the above rule of thumb.
const std::set<std::string> comes_first{
std::stable_partition(list.begin(), list.end(), [&](const auto& matcher) {
return std::set<std::string>{
"MOVI, MVNI, ORR, BIC (vector, immediate)",
"FMOV (vector, immediate)",
"Unallocated SIMD modified immediate",
};
std::stable_partition(list.begin(), list.end(), [&](const auto& matcher) {
return comes_first.count(matcher.GetName()) > 0;
}.count(matcher.GetName()) > 0;
});
DecodeTable<V> table{};
@ -75,7 +74,6 @@ std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction)
const auto matches_instruction = [instruction](const auto& matcher) {
return matcher.Matches(instruction);
};
const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction);
return iter != subtable.end() ? std::optional<std::reference_wrapper<const Matcher<V>>>(*iter) : std::nullopt;

View file

@ -67,3 +67,64 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
}
} // namespace Dynarmic::A64
// ls -l | awk '{print "#include \"dynarmic/frontend/A64/translate/impl/" $9 "\""}'
#include "dynarmic/frontend/A64/translate/impl/a64_branch.cpp"
#include "dynarmic/frontend/A64/translate/impl/a64_exception_generating.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_addsub.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_bitfield.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_conditional_compare.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_conditional_select.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_crc32.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_logical.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_multiply.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_pcrel.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/data_processing_shift.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_compare.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conditional_compare.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conditional_select.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_conversion_integer.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_three_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/impl.cpp"
#include "dynarmic/frontend/A64/translate/impl/impl.h"
#include "dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_load_literal.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_multiple_structures.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_no_allocate_pair.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_pair.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_register_offset.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_register_unprivileged.cpp"
#include "dynarmic/frontend/A64/translate/impl/load_store_single_structure.cpp"
#include "dynarmic/frontend/A64/translate/impl/move_wide.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_across_lanes.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_aes.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_copy.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_crypto_four_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_crypto_three_register.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_extract.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_permute.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_sha512.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_sha.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_table_lookup.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_three_different.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_three_same.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_three_same_extra.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp"
#include "dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp"
#include "dynarmic/frontend/A64/translate/impl/sys_dc.cpp"
#include "dynarmic/frontend/A64/translate/impl/sys_ic.cpp"
#include "dynarmic/frontend/A64/translate/impl/system.cpp"
#include "dynarmic/frontend/A64/translate/impl/system_flag_format.cpp"
#include "dynarmic/frontend/A64/translate/impl/system_flag_manipulation.cpp"

View file

@ -7,14 +7,14 @@
namespace Dynarmic::A64 {
namespace {
enum class MinMaxOperation {
enum class MinMaxOperationSSPW {
Max,
MaxNumeric,
Min,
MinNumeric,
};
bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOperation operation) {
bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOperationSSPW operation) {
const size_t esize = sz ? 64 : 32;
const IR::U128 operand = v.V(128, Vn);
@ -22,13 +22,13 @@ bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOpera
const IR::U32U64 element2 = v.ir.VectorGetElement(esize, operand, 1);
const IR::U32U64 result = [&] {
switch (operation) {
case MinMaxOperation::Max:
case MinMaxOperationSSPW::Max:
return v.ir.FPMax(element1, element2);
case MinMaxOperation::MaxNumeric:
case MinMaxOperationSSPW::MaxNumeric:
return v.ir.FPMaxNumeric(element1, element2);
case MinMaxOperation::Min:
case MinMaxOperationSSPW::Min:
return v.ir.FPMin(element1, element2);
case MinMaxOperation::MinNumeric:
case MinMaxOperationSSPW::MinNumeric:
return v.ir.FPMinNumeric(element1, element2);
default:
UNREACHABLE();
@ -63,18 +63,18 @@ bool TranslatorVisitor::FADDP_pair_2(bool size, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FMAXNMP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::MaxNumeric);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::MaxNumeric);
}
bool TranslatorVisitor::FMAXP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::Max);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::Max);
}
bool TranslatorVisitor::FMINNMP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::MinNumeric);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::MinNumeric);
}
bool TranslatorVisitor::FMINP_pair_2(bool sz, Vec Vn, Vec Vd) {
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::Min);
return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::Min);
}
} // namespace Dynarmic::A64

View file

@ -27,7 +27,7 @@ enum class ShiftExtraBehavior {
Accumulate,
};
enum class Signedness {
enum class SignednessSSSBI {
Signed,
Unsigned,
};
@ -63,7 +63,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
return true;
}
bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, Signedness signedness) {
bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, SignednessSSSBI SignednessSSSBI) {
if (!immh.Bit<3>()) {
return v.ReservedValue();
}
@ -73,7 +73,7 @@ bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd,
const IR::U64 operand = v.V_scalar(esize, Vn);
IR::U64 result = [&]() -> IR::U64 {
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.ArithmeticShiftRight(operand, v.ir.Imm8(shift_amount));
}
return v.ir.LogicalShiftRight(operand, v.ir.Imm8(shift_amount));
@ -88,7 +88,7 @@ bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd,
return true;
}
bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, Signedness signedness) {
bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, SignednessSSSBI SignednessSSSBI) {
if (!immh.Bit<3>()) {
return v.ReservedValue();
}
@ -100,7 +100,7 @@ bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
const IR::U64 round_bit = v.ir.LogicalShiftRight(v.ir.LogicalShiftLeft(operand, v.ir.Imm8(64 - shift_amount)), v.ir.Imm8(63));
const IR::U64 result = [&] {
const IR::U64 shifted = [&]() -> IR::U64 {
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.ArithmeticShiftRight(operand, v.ir.Imm8(shift_amount));
}
return v.ir.LogicalShiftRight(operand, v.ir.Imm8(shift_amount));
@ -163,7 +163,7 @@ bool ShiftAndInsert(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec
return true;
}
bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Narrowing narrowing, Signedness signedness) {
bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Narrowing narrowing, SignednessSSSBI SignednessSSSBI) {
if (immh == 0b0000) {
return v.ReservedValue();
}
@ -179,7 +179,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
const IR::U128 operand = v.ir.ZeroExtendToQuad(v.ir.VectorGetElement(source_esize, v.V(128, Vn), 0));
IR::U128 wide_result = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.VectorArithmeticShiftRight(source_esize, operand, shift_amount);
}
return v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount);
@ -190,12 +190,12 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
case Narrowing::Truncation:
return v.ir.VectorNarrow(source_esize, wide_result);
case Narrowing::SaturateToUnsigned:
if (signedness == Signedness::Signed) {
if (SignednessSSSBI == SignednessSSSBI::Signed) {
return v.ir.VectorSignedSaturatedNarrowToUnsigned(source_esize, wide_result);
}
return v.ir.VectorUnsignedSaturatedNarrow(source_esize, wide_result);
case Narrowing::SaturateToSigned:
ASSERT(signedness == Signedness::Signed);
ASSERT(SignednessSSSBI == SignednessSSSBI::Signed);
return v.ir.VectorSignedSaturatedNarrowToSigned(source_esize, wide_result);
}
UNREACHABLE();
@ -206,7 +206,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn,
return true;
}
bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness sign, FloatConversionDirection direction, FP::RoundingMode rounding_mode) {
bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSSBI sign, FloatConversionDirection direction, FP::RoundingMode rounding_mode) {
const u32 immh_value = immh.ZeroExtend();
if ((immh_value & 0b1110) == 0b0000) {
@ -227,23 +227,23 @@ bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Ve
switch (direction) {
case FloatConversionDirection::FloatToFixed:
if (esize == 64) {
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPToFixedS64(operand, fbits, rounding_mode)
: v.ir.FPToFixedU64(operand, fbits, rounding_mode);
}
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPToFixedS32(operand, fbits, rounding_mode)
: v.ir.FPToFixedU32(operand, fbits, rounding_mode);
case FloatConversionDirection::FixedToFloat:
if (esize == 64) {
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPSignedFixedToDouble(operand, fbits, rounding_mode)
: v.ir.FPUnsignedFixedToDouble(operand, fbits, rounding_mode);
}
return sign == Signedness::Signed
return sign == SignednessSSSBI::Signed
? v.ir.FPSignedFixedToSingle(operand, fbits, rounding_mode)
: v.ir.FPUnsignedFixedToSingle(operand, fbits, rounding_mode);
}
@ -257,19 +257,19 @@ bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Ve
} // Anonymous namespace
bool TranslatorVisitor::FCVTZS_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FCVTZU_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::SCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::UCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::SLI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -289,27 +289,27 @@ bool TranslatorVisitor::SQSHLU_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToSigned, Signedness::Signed);
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToSigned, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SQSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, Signedness::Signed);
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SRSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SRSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Signed);
}
bool TranslatorVisitor::SHL_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -332,23 +332,23 @@ bool TranslatorVisitor::UQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, Signedness::Unsigned);
return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::URSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::URSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned);
return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::USHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Unsigned);
}
bool TranslatorVisitor::USRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned);
return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Unsigned);
}
} // namespace Dynarmic::A64

View file

@ -26,12 +26,12 @@ enum class ComparisonVariant {
Zero,
};
enum class Signedness {
enum class SignednessSSTS {
Signed,
Unsigned,
};
bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSSTS sign) {
if (size != 0b11) {
return v.ReservedValue();
}
@ -39,7 +39,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd
const IR::U128 operand1 = v.V(64, Vn);
const IR::U128 operand2 = v.V(64, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSSTS::Signed) {
return v.ir.VectorRoundingShiftLeftSigned(64, operand1, operand2);
}
@ -369,7 +369,7 @@ bool TranslatorVisitor::SQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, Signedness::Signed);
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, SignednessSSTS::Signed);
}
bool TranslatorVisitor::SSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -411,7 +411,7 @@ bool TranslatorVisitor::UQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::URSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, Signedness::Unsigned);
return RoundingShiftLeft(*this, size, Vm, Vn, Vd, SignednessSSTS::Unsigned);
}
bool TranslatorVisitor::USHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {

View file

@ -7,7 +7,7 @@
namespace Dynarmic::A64 {
namespace {
enum class ComparisonType {
enum class ComparisonTypeSSTRM {
EQ,
GE,
GT,
@ -15,12 +15,12 @@ enum class ComparisonType {
LT
};
enum class Signedness {
enum class SignednessSSTRM {
Signed,
Unsigned
};
bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, ComparisonType type) {
bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, ComparisonTypeSSTRM type) {
const size_t esize = sz ? 64 : 32;
const size_t datasize = esize;
@ -28,15 +28,15 @@ bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, C
const IR::U128 zero = v.ir.ZeroVector();
const IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSSTRM::EQ:
return v.ir.FPVectorEqual(esize, operand, zero);
case ComparisonType::GE:
case ComparisonTypeSSTRM::GE:
return v.ir.FPVectorGreaterEqual(esize, operand, zero);
case ComparisonType::GT:
case ComparisonTypeSSTRM::GT:
return v.ir.FPVectorGreater(esize, operand, zero);
case ComparisonType::LE:
case ComparisonTypeSSTRM::LE:
return v.ir.FPVectorGreaterEqual(esize, zero, operand);
case ComparisonType::LT:
case ComparisonTypeSSTRM::LT:
return v.ir.FPVectorGreater(esize, zero, operand);
}
@ -47,18 +47,18 @@ bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, C
return true;
}
bool ScalarFPConvertWithRound(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, FP::RoundingMode rmode, Signedness sign) {
bool ScalarFPConvertWithRound(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, FP::RoundingMode rmode, SignednessSSTRM sign) {
const size_t esize = sz ? 64 : 32;
const IR::U32U64 operand = v.V_scalar(esize, Vn);
const IR::U32U64 result = [&]() -> IR::U32U64 {
if (sz) {
return sign == Signedness::Signed
return sign == SignednessSSTRM::Signed
? v.ir.FPToFixedS64(operand, 0, rmode)
: v.ir.FPToFixedU64(operand, 0, rmode);
}
return sign == Signedness::Signed
return sign == SignednessSSTRM::Signed
? v.ir.FPToFixedS32(operand, 0, rmode)
: v.ir.FPToFixedU32(operand, 0, rmode);
}();
@ -107,55 +107,55 @@ bool TranslatorVisitor::FCMEQ_zero_1(Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCMEQ_zero_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::EQ);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::EQ);
}
bool TranslatorVisitor::FCMGE_zero_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::GE);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::GE);
}
bool TranslatorVisitor::FCMGT_zero_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::GT);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::GT);
}
bool TranslatorVisitor::FCMLE_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::LE);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::LE);
}
bool TranslatorVisitor::FCMLT_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::LT);
return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::LT);
}
bool TranslatorVisitor::FCVTAS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTAU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTMS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTMU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTNS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTNU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTPS_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTPU_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FCVTXN_1(bool sz, Vec Vn, Vec Vd) {
@ -171,11 +171,11 @@ bool TranslatorVisitor::FCVTXN_1(bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCVTZS_int_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, Signedness::Signed);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, SignednessSSTRM::Signed);
}
bool TranslatorVisitor::FCVTZU_int_2(bool sz, Vec Vn, Vec Vd) {
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, Signedness::Unsigned);
return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, SignednessSSTRM::Unsigned);
}
bool TranslatorVisitor::FRECPE_1(Vec Vn, Vec Vd) {

View file

@ -9,7 +9,7 @@
namespace Dynarmic::A64 {
namespace {
std::pair<size_t, Vec> Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
std::pair<size_t, Vec> CombineScalar(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
if (size == 0b01) {
return {concatenate(H, L, M).ZeroExtend(), Vmlo.ZeroExtend<Vec>()};
}
@ -122,7 +122,7 @@ bool TranslatorVisitor::SQDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm
}
const size_t esize = 8 << size.ZeroExtend();
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo);
const IR::UAny operand1 = V_scalar(esize, Vn);
const IR::UAny operand2 = ir.VectorGetElement(esize, V(128, Vm), index);
@ -137,7 +137,7 @@ bool TranslatorVisitor::SQRDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> V
}
const size_t esize = 8 << size.ZeroExtend();
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo);
const IR::U128 operand1 = ir.ZeroExtendToQuad(ir.VectorGetElement(esize, V(128, Vn), 0));
const IR::U128 operand2 = V(128, Vm);
@ -154,7 +154,7 @@ bool TranslatorVisitor::SQDMULL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm
}
const size_t esize = 8 << size.ZeroExtend();
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo);
const IR::U128 operand1 = ir.ZeroExtendToQuad(ir.VectorGetElement(esize, V(128, Vn), 0));
const IR::U128 operand2 = V(128, Vm);

View file

@ -20,24 +20,24 @@ enum class Accumulating {
Accumulate
};
enum class Signedness {
enum class SignednessSSBI {
Signed,
Unsigned
};
enum class Narrowing {
enum class NarrowingSSBI {
Truncation,
SaturateToUnsigned,
SaturateToSigned,
};
enum class SaturatingShiftLeftType {
enum class SaturatingShiftLeftTypeSSBI {
Signed,
Unsigned,
SignedWithUnsignedSaturation,
};
enum class FloatConversionDirection {
enum class FloatConversionDirectionSSBI {
FixedToFloat,
FloatToFixed,
};
@ -48,7 +48,7 @@ IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round
return v.ir.VectorSub(esize, shifted, round_correction);
}
bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Accumulating accumulating, Signedness signedness) {
bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Accumulating accumulating, SignednessSSBI SignednessSSBI) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -65,7 +65,7 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn,
const IR::U128 operand = v.V(datasize, Vn);
IR::U128 result = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorArithmeticShiftRight(esize, operand, shift_amount);
}
return v.ir.VectorLogicalShiftRight(esize, operand, shift_amount);
@ -85,7 +85,7 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn,
return true;
}
bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Narrowing narrowing, Signedness signedness) {
bool ShiftRightNarrowingSSBI(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, NarrowingSSBI NarrowingSSBI, SignednessSSBI SignednessSSBI) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -103,7 +103,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
const IR::U128 operand = v.V(128, Vn);
IR::U128 wide_result = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorArithmeticShiftRight(source_esize, operand, shift_amount);
}
return v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount);
@ -115,16 +115,16 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
}
const IR::U128 result = [&] {
switch (narrowing) {
case Narrowing::Truncation:
switch (NarrowingSSBI) {
case NarrowingSSBI::Truncation:
return v.ir.VectorNarrow(source_esize, wide_result);
case Narrowing::SaturateToUnsigned:
if (signedness == Signedness::Signed) {
case NarrowingSSBI::SaturateToUnsigned:
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorSignedSaturatedNarrowToUnsigned(source_esize, wide_result);
}
return v.ir.VectorUnsignedSaturatedNarrow(source_esize, wide_result);
case Narrowing::SaturateToSigned:
ASSERT(signedness == Signedness::Signed);
case NarrowingSSBI::SaturateToSigned:
ASSERT(SignednessSSBI == SignednessSSBI::Signed);
return v.ir.VectorSignedSaturatedNarrowToSigned(source_esize, wide_result);
}
UNREACHABLE();
@ -134,7 +134,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
return true;
}
bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness) {
bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSBI SignednessSSBI) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -151,7 +151,7 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V
const IR::U128 operand = v.Vpart(datasize, Vn, part);
const IR::U128 expanded_operand = [&] {
if (signedness == Signedness::Signed) {
if (SignednessSSBI == SignednessSSBI::Signed) {
return v.ir.VectorSignExtend(esize, operand);
}
return v.ir.VectorZeroExtend(esize, operand);
@ -162,7 +162,7 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V
return true;
}
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SaturatingShiftLeftType type) {
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SaturatingShiftLeftTypeSSBI type) {
if (!Q && immh.Bit<3>()) {
return v.ReservedValue();
}
@ -174,11 +174,11 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 shift_vec = v.ir.VectorBroadcast(esize, v.I(esize, shift));
const IR::U128 result = [&] {
if (type == SaturatingShiftLeftType::Signed) {
if (type == SaturatingShiftLeftTypeSSBI::Signed) {
return v.ir.VectorSignedSaturatedShiftLeft(esize, operand, shift_vec);
}
if (type == SaturatingShiftLeftType::Unsigned) {
if (type == SaturatingShiftLeftTypeSSBI::Unsigned) {
return v.ir.VectorUnsignedSaturatedShiftLeft(esize, operand, shift_vec);
}
@ -189,7 +189,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb,
return true;
}
bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness, FloatConversionDirection direction, FP::RoundingMode rounding_mode) {
bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSBI SignednessSSBI, FloatConversionDirectionSSBI direction, FP::RoundingMode rounding_mode) {
if (immh == 0b0000) {
return v.DecodeError();
}
@ -210,12 +210,12 @@ bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 result = [&] {
switch (direction) {
case FloatConversionDirection::FixedToFloat:
return signedness == Signedness::Signed
case FloatConversionDirectionSSBI::FixedToFloat:
return SignednessSSBI == SignednessSSBI::Signed
? v.ir.FPVectorFromSignedFixed(esize, operand, fbits, rounding_mode)
: v.ir.FPVectorFromUnsignedFixed(esize, operand, fbits, rounding_mode);
case FloatConversionDirection::FloatToFixed:
return signedness == Signedness::Signed
case FloatConversionDirectionSSBI::FloatToFixed:
return SignednessSSBI == SignednessSSBI::Signed
? v.ir.FPVectorToSignedFixed(esize, operand, fbits, rounding_mode)
: v.ir.FPVectorToUnsignedFixed(esize, operand, fbits, rounding_mode);
}
@ -229,19 +229,19 @@ bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn
} // Anonymous namespace
bool TranslatorVisitor::SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SRSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SRSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Signed);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -264,71 +264,71 @@ bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd)
}
bool TranslatorVisitor::SHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::Truncation, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::Truncation, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::RSHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::Truncation, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::Truncation, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::SQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::Signed);
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::Signed);
}
bool TranslatorVisitor::SQSHLU_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::SignedWithUnsignedSaturation);
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::SignedWithUnsignedSaturation);
}
bool TranslatorVisitor::SQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToSigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToSigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToSigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToSigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SQSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::SQRSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Signed);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Signed);
}
bool TranslatorVisitor::UQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::Unsigned);
return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::Unsigned);
}
bool TranslatorVisitor::UQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::UQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Unsigned);
return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, Signedness::Signed);
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed);
}
bool TranslatorVisitor::URSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::URSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::USHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::USRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Unsigned);
return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::USHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned);
return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned);
}
bool TranslatorVisitor::SRI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
@ -384,19 +384,19 @@ bool TranslatorVisitor::SLI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd)
}
bool TranslatorVisitor::SCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed, FloatConversionDirectionSSBI::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::UCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode());
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned, FloatConversionDirectionSSBI::FixedToFloat, ir.current_location->FPCR().RMode());
}
bool TranslatorVisitor::FCVTZS_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed, FloatConversionDirectionSSBI::FloatToFixed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FCVTZU_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero);
return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned, FloatConversionDirectionSSBI::FloatToFixed, FP::RoundingMode::TowardsZero);
}
} // namespace Dynarmic::A64

View file

@ -12,12 +12,12 @@ enum class AbsoluteDifferenceBehavior {
Accumulate
};
enum class Signedness {
enum class SignednessSTD {
Signed,
Unsigned
};
bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsoluteDifferenceBehavior behavior, Signedness sign) {
bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsoluteDifferenceBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -27,7 +27,7 @@ bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
const IR::U128 operand1 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vn, Q));
const IR::U128 operand2 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vm, Q));
IR::U128 result = sign == Signedness::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2)
IR::U128 result = sign == SignednessSTD::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2)
: v.ir.VectorUnsignedAbsoluteDifference(esize, operand1, operand2);
if (behavior == AbsoluteDifferenceBehavior::Accumulate) {
@ -45,7 +45,7 @@ enum class MultiplyLongBehavior {
Subtract
};
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MultiplyLongBehavior behavior, Signedness sign) {
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MultiplyLongBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -59,7 +59,7 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec
const auto reg_n = v.Vpart(datasize, Vn, Q);
const auto reg_m = v.Vpart(datasize, Vm, Q);
return sign == Signedness::Signed
return sign == SignednessSTD::Signed
? v.ir.VectorMultiplySignedWiden(esize, reg_n, reg_m)
: v.ir.VectorMultiplyUnsignedWiden(esize, reg_n, reg_m);
}();
@ -81,7 +81,7 @@ enum class LongOperationBehavior {
Subtraction
};
bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, LongOperationBehavior behavior, Signedness sign) {
bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, LongOperationBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -92,7 +92,7 @@ bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Ve
const auto get_operand = [&](Vec vec) {
const IR::U128 tmp = v.Vpart(64, vec, part);
if (sign == Signedness::Signed) {
if (sign == SignednessSTD::Signed) {
return v.ir.VectorSignExtend(esize, tmp);
}
@ -118,7 +118,7 @@ enum class WideOperationBehavior {
Subtraction
};
bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, WideOperationBehavior behavior, Signedness sign) {
bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, WideOperationBehavior behavior, SignednessSTD sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -130,7 +130,7 @@ bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Ve
const IR::U128 operand2 = [&] {
const IR::U128 tmp = v.Vpart(64, Vm, part);
if (sign == Signedness::Signed) {
if (sign == SignednessSTD::Signed) {
return v.ir.VectorSignExtend(esize, tmp);
}
@ -166,75 +166,75 @@ bool TranslatorVisitor::PMULL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Signed);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, SignednessSTD::Signed);
}
bool TranslatorVisitor::SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Signed);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, SignednessSTD::Signed);
}
bool TranslatorVisitor::SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Signed);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, SignednessSTD::Signed);
}
bool TranslatorVisitor::SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Signed);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, SignednessSTD::Signed);
}
bool TranslatorVisitor::SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Signed);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, SignednessSTD::Signed);
}
bool TranslatorVisitor::SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Signed);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, SignednessSTD::Signed);
}
bool TranslatorVisitor::SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Signed);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, SignednessSTD::Signed);
}
bool TranslatorVisitor::SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Signed);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, SignednessSTD::Signed);
}
bool TranslatorVisitor::SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Signed);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, SignednessSTD::Signed);
}
bool TranslatorVisitor::UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Unsigned);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Unsigned);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Unsigned);
return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Unsigned);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Unsigned);
return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Unsigned);
return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, SignednessSTD::Unsigned);
}
bool TranslatorVisitor::SQDMULL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {

View file

@ -12,12 +12,12 @@ enum class Operation {
Subtract,
};
enum class ExtraBehavior {
enum class ExtraBehaviorSTS {
None,
Round
};
bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, ExtraBehavior behavior) {
bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, ExtraBehaviorSTS behavior) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -35,7 +35,7 @@ bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
return v.ir.VectorSub(doubled_esize, operand1, operand2);
}();
if (behavior == ExtraBehavior::Round) {
if (behavior == ExtraBehaviorSTS::Round) {
const u64 round_const = 1ULL << (esize - 1);
const IR::U128 round_operand = v.ir.VectorBroadcast(doubled_esize, v.I(doubled_esize, round_const));
wide = v.ir.VectorAdd(doubled_esize, wide, round_operand);
@ -48,12 +48,12 @@ bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V
return true;
}
enum class AbsDiffExtraBehavior {
enum class AbsDiffExtraBehaviorSTS {
None,
Accumulate
};
bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehavior behavior) {
bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehaviorSTS behavior) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -66,7 +66,7 @@ bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm,
const IR::U128 result = [&] {
const IR::U128 tmp = v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2);
if (behavior == AbsDiffExtraBehavior::Accumulate) {
if (behavior == AbsDiffExtraBehaviorSTS::Accumulate) {
const IR::U128 d = v.V(datasize, Vd);
return v.ir.VectorAdd(esize, d, tmp);
}
@ -78,12 +78,12 @@ bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm,
return true;
}
enum class Signedness {
enum class SignednessSTS {
Signed,
Unsigned
};
bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -93,14 +93,14 @@ bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec V
const IR::U128 operand1 = v.V(datasize, Vm);
const IR::U128 operand2 = v.V(datasize, Vn);
const IR::U128 result = sign == Signedness::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2)
const IR::U128 result = sign == SignednessSTS::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2)
: v.ir.VectorRoundingHalvingAddUnsigned(esize, operand1, operand2);
v.V(datasize, Vd, result);
return true;
}
bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -111,7 +111,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTS::Signed) {
return v.ir.VectorRoundingShiftLeftSigned(esize, operand1, operand2);
}
@ -122,7 +122,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn
return true;
}
enum class ComparisonType {
enum class ComparisonTypeSTS {
EQ,
GE,
AbsoluteGE,
@ -130,7 +130,7 @@ enum class ComparisonType {
AbsoluteGT
};
bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonType type) {
bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonTypeSTS type) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -142,17 +142,17 @@ bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSTS::EQ:
return v.ir.FPVectorEqual(esize, operand1, operand2);
case ComparisonType::GE:
case ComparisonTypeSTS::GE:
return v.ir.FPVectorGreaterEqual(esize, operand1, operand2);
case ComparisonType::AbsoluteGE:
case ComparisonTypeSTS::AbsoluteGE:
return v.ir.FPVectorGreaterEqual(esize,
v.ir.FPVectorAbs(esize, operand1),
v.ir.FPVectorAbs(esize, operand2));
case ComparisonType::GT:
case ComparisonTypeSTS::GT:
return v.ir.FPVectorGreater(esize, operand1, operand2);
case ComparisonType::AbsoluteGT:
case ComparisonTypeSTS::AbsoluteGT:
return v.ir.FPVectorGreater(esize,
v.ir.FPVectorAbs(esize, operand1),
v.ir.FPVectorAbs(esize, operand2));
@ -165,12 +165,12 @@ bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
return true;
}
enum class MinMaxOperation {
enum class MinMaxOperationSTS {
Min,
Max,
};
bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation, Signedness sign) {
bool VectorMinMaxOperationSTS(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation, SignednessSTS sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -182,14 +182,14 @@ bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
switch (operation) {
case MinMaxOperation::Max:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Max:
if (sign == SignednessSTS::Signed) {
return v.ir.VectorMaxSigned(esize, operand1, operand2);
}
return v.ir.VectorMaxUnsigned(esize, operand1, operand2);
case MinMaxOperation::Min:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Min:
if (sign == SignednessSTS::Signed) {
return v.ir.VectorMinSigned(esize, operand1, operand2);
}
return v.ir.VectorMinUnsigned(esize, operand1, operand2);
@ -203,7 +203,7 @@ bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve
return true;
}
bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) {
bool FPMinMaxOperationSTS(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -214,7 +214,7 @@ bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (operation == MinMaxOperation::Min) {
if (operation == MinMaxOperationSTS::Min) {
return v.ir.FPVectorMin(esize, operand1, operand2);
}
@ -225,7 +225,7 @@ bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve
return true;
}
bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) {
bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -236,7 +236,7 @@ bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (operation == MinMaxOperation::Min) {
if (operation == MinMaxOperationSTS::Min) {
return v.ir.FPVectorMinNumeric(esize, operand1, operand2);
}
@ -247,7 +247,7 @@ bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec
return true;
}
bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation, Signedness sign) {
bool PairedMinMaxOperationSTS(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation, SignednessSTS sign) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -259,14 +259,14 @@ bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
IR::U128 result = [&] {
switch (operation) {
case MinMaxOperation::Max:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Max:
if (sign == SignednessSTS::Signed) {
return Q ? v.ir.VectorPairedMaxSigned(esize, operand1, operand2) : v.ir.VectorPairedMaxSignedLower(esize, operand1, operand2);
}
return Q ? v.ir.VectorPairedMaxUnsigned(esize, operand1, operand2) : v.ir.VectorPairedMaxUnsignedLower(esize, operand1, operand2);
case MinMaxOperation::Min:
if (sign == Signedness::Signed) {
case MinMaxOperationSTS::Min:
if (sign == SignednessSTS::Signed) {
return Q ? v.ir.VectorPairedMinSigned(esize, operand1, operand2) : v.ir.VectorPairedMinSignedLower(esize, operand1, operand2);
}
return Q ? v.ir.VectorPairedMinUnsigned(esize, operand1, operand2) : v.ir.VectorPairedMinUnsignedLower(esize, operand1, operand2);
@ -311,7 +311,7 @@ bool FPPairedMinMax(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec V
return true;
}
bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, Signedness sign) {
bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, SignednessSTS sign) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -323,7 +323,7 @@ bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Ve
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTS::Signed) {
if (op == Operation::Add) {
return v.ir.VectorSignedSaturatedAdd(esize, operand1, operand2);
}
@ -342,7 +342,7 @@ bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Ve
return true;
}
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) {
bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -353,7 +353,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec
const IR::U128 operand1 = v.V(datasize, Vn);
const IR::U128 operand2 = v.V(datasize, Vm);
const IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTS::Signed) {
return v.ir.VectorSignedSaturatedShiftLeft(esize, operand1, operand2);
}
@ -401,27 +401,27 @@ bool TranslatorVisitor::CMGE_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd)
}
bool TranslatorVisitor::SABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::Accumulate);
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehaviorSTS::Accumulate);
}
bool TranslatorVisitor::SABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::None);
return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehaviorSTS::None);
}
bool TranslatorVisitor::SMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Signed);
}
bool TranslatorVisitor::SMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Signed);
}
bool TranslatorVisitor::SMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Signed);
}
bool TranslatorVisitor::SMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Signed);
}
bool TranslatorVisitor::SQDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -506,19 +506,19 @@ bool TranslatorVisitor::MUL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::ADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::None);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehaviorSTS::None);
}
bool TranslatorVisitor::RADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::Round);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehaviorSTS::Round);
}
bool TranslatorVisitor::SUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::None);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehaviorSTS::None);
}
bool TranslatorVisitor::RSUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::Round);
return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehaviorSTS::Round);
}
bool TranslatorVisitor::SHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -554,15 +554,15 @@ bool TranslatorVisitor::SHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Signed);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, SignednessSTS::Signed);
}
bool TranslatorVisitor::SQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Signed);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, SignednessSTS::Signed);
}
bool TranslatorVisitor::SRHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed);
}
bool TranslatorVisitor::UHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -598,15 +598,15 @@ bool TranslatorVisitor::UHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Unsigned);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Unsigned);
return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::URHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::ADDP_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -642,11 +642,11 @@ bool TranslatorVisitor::FABD_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FACGE_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGE);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::AbsoluteGE);
}
bool TranslatorVisitor::FACGT_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGT);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::AbsoluteGT);
}
bool TranslatorVisitor::FADD_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
@ -737,15 +737,15 @@ bool TranslatorVisitor::FCMEQ_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCMEQ_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::EQ);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::EQ);
}
bool TranslatorVisitor::FCMGE_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GE);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::GE);
}
bool TranslatorVisitor::FCMGT_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GT);
return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::GT);
}
bool TranslatorVisitor::AND_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
@ -827,11 +827,11 @@ bool TranslatorVisitor::CMTST_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed);
}
bool TranslatorVisitor::SRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed);
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed);
}
bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -851,11 +851,11 @@ bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::URSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned);
return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -875,11 +875,11 @@ bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
@ -918,11 +918,11 @@ bool TranslatorVisitor::UABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::UMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned);
return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::UMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned);
return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Unsigned);
}
bool TranslatorVisitor::FSUB_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
@ -1104,11 +1104,11 @@ bool TranslatorVisitor::EOR_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FMAX_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max);
return FPMinMaxOperationSTS(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Max);
}
bool TranslatorVisitor::FMAXNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max);
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Max);
}
bool TranslatorVisitor::FMAXNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
@ -1120,11 +1120,11 @@ bool TranslatorVisitor::FMAXP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FMIN_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min);
return FPMinMaxOperationSTS(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Min);
}
bool TranslatorVisitor::FMINNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min);
return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Min);
}
bool TranslatorVisitor::FMINNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {

View file

@ -8,7 +8,7 @@
namespace Dynarmic::A64 {
namespace {
enum class ComparisonType {
enum class ComparisonTypeSTRM {
EQ,
GE,
GT,
@ -16,7 +16,7 @@ enum class ComparisonType {
LT,
};
bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, ComparisonType type) {
bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, ComparisonTypeSTRM type) {
if (size == 0b11 && !Q) {
return v.ReservedValue();
}
@ -28,15 +28,15 @@ bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec V
const IR::U128 zero = v.ir.ZeroVector();
IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSTRM::EQ:
return v.ir.VectorEqual(esize, operand, zero);
case ComparisonType::GE:
case ComparisonTypeSTRM::GE:
return v.ir.VectorGreaterEqualSigned(esize, operand, zero);
case ComparisonType::GT:
case ComparisonTypeSTRM::GT:
return v.ir.VectorGreaterSigned(esize, operand, zero);
case ComparisonType::LE:
case ComparisonTypeSTRM::LE:
return v.ir.VectorLessEqualSigned(esize, operand, zero);
case ComparisonType::LT:
case ComparisonTypeSTRM::LT:
default:
return v.ir.VectorLessSigned(esize, operand, zero);
}
@ -50,7 +50,7 @@ bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec V
return true;
}
bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, ComparisonType type) {
bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, ComparisonTypeSTRM type) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -62,15 +62,15 @@ bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd,
const IR::U128 zero = v.ir.ZeroVector();
const IR::U128 result = [&] {
switch (type) {
case ComparisonType::EQ:
case ComparisonTypeSTRM::EQ:
return v.ir.FPVectorEqual(esize, operand, zero);
case ComparisonType::GE:
case ComparisonTypeSTRM::GE:
return v.ir.FPVectorGreaterEqual(esize, operand, zero);
case ComparisonType::GT:
case ComparisonTypeSTRM::GT:
return v.ir.FPVectorGreater(esize, operand, zero);
case ComparisonType::LE:
case ComparisonTypeSTRM::LE:
return v.ir.FPVectorGreaterEqual(esize, zero, operand);
case ComparisonType::LT:
case ComparisonTypeSTRM::LT:
return v.ir.FPVectorGreater(esize, zero, operand);
}
@ -81,12 +81,12 @@ bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd,
return true;
}
enum class Signedness {
enum class SignednessSTRM {
Signed,
Unsigned
};
bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, Signedness signedness) {
bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, SignednessSTRM SignednessSTRM) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -96,7 +96,7 @@ bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd
const FP::RoundingMode rounding_mode = v.ir.current_location->FPCR().RMode();
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 result = signedness == Signedness::Signed
const IR::U128 result = SignednessSTRM == SignednessSTRM::Signed
? v.ir.FPVectorFromSignedFixed(esize, operand, 0, rounding_mode)
: v.ir.FPVectorFromUnsignedFixed(esize, operand, 0, rounding_mode);
@ -104,7 +104,7 @@ bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd
return true;
}
bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, Signedness signedness, FP::RoundingMode rounding_mode) {
bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, SignednessSTRM SignednessSTRM, FP::RoundingMode rounding_mode) {
if (sz && !Q) {
return v.ReservedValue();
}
@ -113,7 +113,7 @@ bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd
const size_t esize = sz ? 64 : 32;
const IR::U128 operand = v.V(datasize, Vn);
const IR::U128 result = signedness == Signedness::Signed
const IR::U128 result = SignednessSTRM == SignednessSTRM::Signed
? v.ir.FPVectorToSignedFixed(esize, operand, 0, rounding_mode)
: v.ir.FPVectorToUnsignedFixed(esize, operand, 0, rounding_mode);
@ -168,7 +168,7 @@ enum class PairedAddLongExtraBehavior {
Accumulate,
};
bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Signedness sign, PairedAddLongExtraBehavior behavior) {
bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, SignednessSTRM sign, PairedAddLongExtraBehavior behavior) {
if (size == 0b11) {
return v.ReservedValue();
}
@ -178,7 +178,7 @@ bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Si
const IR::U128 operand = v.V(datasize, Vn);
IR::U128 result = [&] {
if (sign == Signedness::Signed) {
if (sign == SignednessSTRM::Signed) {
return v.ir.VectorPairedAddSignedWiden(esize, operand);
}
@ -254,23 +254,23 @@ bool TranslatorVisitor::CNT(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::CMGE_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::GE);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::GE);
}
bool TranslatorVisitor::CMGT_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::GT);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::GT);
}
bool TranslatorVisitor::CMEQ_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::EQ);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::EQ);
}
bool TranslatorVisitor::CMLE_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::LE);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::LE);
}
bool TranslatorVisitor::CMLT_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::LT);
return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::LT);
}
bool TranslatorVisitor::ABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
@ -341,23 +341,23 @@ bool TranslatorVisitor::FCMEQ_zero_3(bool Q, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCMEQ_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::EQ);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::EQ);
}
bool TranslatorVisitor::FCMGE_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::GE);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::GE);
}
bool TranslatorVisitor::FCMGT_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::GT);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::GT);
}
bool TranslatorVisitor::FCMLE_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::LE);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::LE);
}
bool TranslatorVisitor::FCMLT_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::LT);
return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::LT);
}
bool TranslatorVisitor::FCVTL(bool Q, bool sz, Vec Vn, Vec Vd) {
@ -411,19 +411,19 @@ bool TranslatorVisitor::FCVTN(bool Q, bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCVTNS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::ToNearest_TieEven);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::ToNearest_TieEven);
}
bool TranslatorVisitor::FCVTMS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsMinusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsMinusInfinity);
}
bool TranslatorVisitor::FCVTAS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::ToNearest_TieAwayFromZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::ToNearest_TieAwayFromZero);
}
bool TranslatorVisitor::FCVTPS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsPlusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsPlusInfinity);
}
bool TranslatorVisitor::FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) {
@ -447,27 +447,27 @@ bool TranslatorVisitor::FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::FCVTZS_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FCVTNU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::ToNearest_TieEven);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::ToNearest_TieEven);
}
bool TranslatorVisitor::FCVTMU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsMinusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsMinusInfinity);
}
bool TranslatorVisitor::FCVTAU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::ToNearest_TieAwayFromZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::ToNearest_TieAwayFromZero);
}
bool TranslatorVisitor::FCVTPU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsPlusInfinity);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsPlusInfinity);
}
bool TranslatorVisitor::FCVTZU_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsZero);
return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsZero);
}
bool TranslatorVisitor::FRINTN_1(bool Q, Vec Vn, Vec Vd) {
@ -780,19 +780,19 @@ bool TranslatorVisitor::USQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Signed, PairedAddLongExtraBehavior::Accumulate);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Signed, PairedAddLongExtraBehavior::Accumulate);
}
bool TranslatorVisitor::SADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Signed, PairedAddLongExtraBehavior::None);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Signed, PairedAddLongExtraBehavior::None);
}
bool TranslatorVisitor::UADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Unsigned, PairedAddLongExtraBehavior::Accumulate);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Unsigned, PairedAddLongExtraBehavior::Accumulate);
}
bool TranslatorVisitor::UADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Unsigned, PairedAddLongExtraBehavior::None);
return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Unsigned, PairedAddLongExtraBehavior::None);
}
bool TranslatorVisitor::URECPE(bool Q, bool sz, Vec Vn, Vec Vd) {
@ -824,11 +824,11 @@ bool TranslatorVisitor::URSQRTE(bool Q, bool sz, Vec Vn, Vec Vd) {
}
bool TranslatorVisitor::SCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, Signedness::Signed);
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed);
}
bool TranslatorVisitor::UCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, Signedness::Unsigned);
return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned);
}
bool TranslatorVisitor::SHLL(bool Q, Imm<2> size, Vec Vn, Vec Vd) {

View file

@ -11,7 +11,7 @@
namespace Dynarmic::A64 {
namespace {
std::pair<size_t, Vec> Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
std::pair<size_t, Vec> CombineVector(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) {
if (size == 0b01) {
return {concatenate(H, L, M).ZeroExtend(), Vmlo.ZeroExtend<Vec>()};
}
@ -19,19 +19,19 @@ std::pair<size_t, Vec> Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4>
return {concatenate(H, L).ZeroExtend(), concatenate(M, Vmlo).ZeroExtend<Vec>()};
}
enum class ExtraBehavior {
enum class ExtraBehaviorSVXIE {
None,
Extended,
Accumulate,
Subtract,
};
bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) {
bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) {
if (size != 0b01 && size != 0b10) {
return v.ReservedValue();
}
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const size_t idxdsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = Q ? 128 : 64;
@ -41,9 +41,9 @@ bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<
const IR::U128 operand3 = v.V(datasize, Vd);
IR::U128 result = v.ir.VectorMultiply(esize, operand1, operand2);
if (extra_behavior == ExtraBehavior::Accumulate) {
if (extra_behavior == ExtraBehaviorSVXIE::Accumulate) {
result = v.ir.VectorAdd(esize, operand3, result);
} else if (extra_behavior == ExtraBehavior::Subtract) {
} else if (extra_behavior == ExtraBehaviorSVXIE::Subtract) {
result = v.ir.VectorSub(esize, operand3, result);
}
@ -51,7 +51,7 @@ bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<
return true;
}
bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) {
bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) {
if (sz && L == 1) {
return v.ReservedValue();
}
@ -71,13 +71,13 @@ bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1>
const IR::U128 result = [&] {
switch (extra_behavior) {
case ExtraBehavior::None:
case ExtraBehaviorSVXIE::None:
return v.ir.FPVectorMul(esize, operand1, operand2);
case ExtraBehavior::Extended:
case ExtraBehaviorSVXIE::Extended:
return v.ir.FPVectorMulX(esize, operand1, operand2);
case ExtraBehavior::Accumulate:
case ExtraBehaviorSVXIE::Accumulate:
return v.ir.FPVectorMulAdd(esize, operand3, operand1, operand2);
case ExtraBehavior::Subtract:
case ExtraBehaviorSVXIE::Subtract:
return v.ir.FPVectorMulAdd(esize, operand3, v.ir.FPVectorNeg(esize, operand1), operand2);
}
UNREACHABLE();
@ -86,7 +86,7 @@ bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1>
return true;
}
bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) {
bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) {
const size_t idxdsize = H == 1 ? 128 : 64;
const size_t index = concatenate(H, L, M).ZeroExtend();
const Vec Vm = Vmlo.ZeroExtend<Vec>();
@ -101,13 +101,13 @@ bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Im
// regular multiplies and extended multiplies.
const IR::U128 result = [&] {
switch (extra_behavior) {
case ExtraBehavior::None:
case ExtraBehaviorSVXIE::None:
break;
case ExtraBehavior::Extended:
case ExtraBehaviorSVXIE::Extended:
break;
case ExtraBehavior::Accumulate:
case ExtraBehaviorSVXIE::Accumulate:
return v.ir.FPVectorMulAdd(esize, operand3, operand1, operand2);
case ExtraBehavior::Subtract:
case ExtraBehaviorSVXIE::Subtract:
return v.ir.FPVectorMulAdd(esize, operand3, v.ir.FPVectorNeg(esize, operand1), operand2);
}
UNREACHABLE();
@ -151,12 +151,12 @@ bool DotProduct(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I
return true;
}
enum class Signedness {
enum class SignednessSVXIE {
Signed,
Unsigned
};
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior, Signedness sign) {
bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior, SignednessSVXIE sign) {
if (size == 0b00 || size == 0b11) {
return v.ReservedValue();
}
@ -164,23 +164,23 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M,
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = v.Vpart(datasize, Vn, Q);
const IR::U128 operand2 = v.V(idxsize, Vm);
const IR::U128 index_vector = v.ir.VectorBroadcastElement(esize, operand2, index);
const IR::U128 result = [&] {
const IR::U128 product = sign == Signedness::Signed
const IR::U128 product = sign == SignednessSVXIE::Signed
? v.ir.VectorMultiplySignedWiden(esize, operand1, index_vector)
: v.ir.VectorMultiplyUnsignedWiden(esize, operand1, index_vector);
if (extra_behavior == ExtraBehavior::None) {
if (extra_behavior == ExtraBehaviorSVXIE::None) {
return product;
}
const IR::U128 operand3 = v.V(2 * datasize, Vd);
if (extra_behavior == ExtraBehavior::Accumulate) {
if (extra_behavior == ExtraBehaviorSVXIE::Accumulate) {
return v.ir.VectorAdd(2 * esize, operand3, product);
}
@ -193,15 +193,15 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M,
} // Anonymous namespace
bool TranslatorVisitor::MLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate);
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate);
}
bool TranslatorVisitor::MLS_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract);
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract);
}
bool TranslatorVisitor::MUL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None);
return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None);
}
bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<2> rot, Imm<1> H, Vec Vn, Vec Vd) {
@ -292,39 +292,39 @@ bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4
}
bool TranslatorVisitor::FMLA_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate);
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate);
}
bool TranslatorVisitor::FMLA_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate);
}
bool TranslatorVisitor::FMLS_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract);
return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract);
}
bool TranslatorVisitor::FMLS_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract);
}
bool TranslatorVisitor::FMUL_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None);
}
bool TranslatorVisitor::FMULX_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Extended);
return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Extended);
}
bool TranslatorVisitor::SMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate, Signedness::Signed);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate, SignednessSVXIE::Signed);
}
bool TranslatorVisitor::SMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract, Signedness::Signed);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract, SignednessSVXIE::Signed);
}
bool TranslatorVisitor::SMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None, Signedness::Signed);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None, SignednessSVXIE::Signed);
}
bool TranslatorVisitor::SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
@ -336,7 +336,7 @@ bool TranslatorVisitor::SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = Vpart(datasize, Vn, part);
const IR::U128 operand2 = V(idxsize, Vm);
@ -355,7 +355,7 @@ bool TranslatorVisitor::SQDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = Q ? 128 : 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = V(datasize, Vn);
const IR::U128 operand2 = V(idxsize, Vm);
@ -374,7 +374,7 @@ bool TranslatorVisitor::SQRDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M,
const size_t idxsize = H == 1 ? 128 : 64;
const size_t esize = 8 << size.ZeroExtend();
const size_t datasize = Q ? 128 : 64;
const auto [index, Vm] = Combine(size, H, L, M, Vmlo);
const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo);
const IR::U128 operand1 = V(datasize, Vn);
const IR::U128 operand2 = V(idxsize, Vm);
@ -394,15 +394,15 @@ bool TranslatorVisitor::UDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4>
}
bool TranslatorVisitor::UMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate, SignednessSVXIE::Unsigned);
}
bool TranslatorVisitor::UMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract, SignednessSVXIE::Unsigned);
}
bool TranslatorVisitor::UMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None, Signedness::Unsigned);
return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None, SignednessSVXIE::Unsigned);
}
} // namespace Dynarmic::A64

View file

@ -5,10 +5,12 @@
#pragma once
#include <stdint.h>
namespace Dynarmic {
namespace A32 {
enum class ArchVersion {
enum class ArchVersion : std::uint8_t {
v3,
v4,
v4T,

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@ -120,14 +123,32 @@ struct UserCallbacks : public TranslateCallbacks {
};
struct UserConfig {
bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
UserCallbacks* callbacks;
size_t processor_id = 0;
ExclusiveMonitor* global_monitor = nullptr;
/// Select the architecture version to use.
/// There are minor behavioural differences between versions.
ArchVersion arch_version = ArchVersion::v8;
// Page Table
// The page table is used for faster memory access. If an entry in the table is nullptr,
// the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>* page_table = nullptr;
/// Coprocessors
std::array<std::shared_ptr<Coprocessor>, 16> coprocessors{};
/// Fastmem Pointer
/// This should point to the beginning of a 4GB address space which is in arranged just like
/// what you wish for emulated memory to be. If the host page faults on an address, the JIT
/// will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
std::optional<uintptr_t> fastmem_pointer = std::nullopt;
/// This selects other optimizations than can't otherwise be disabled by setting other
/// configuration options. This includes:
@ -137,12 +158,29 @@ struct UserConfig {
/// This is intended to be used for debugging.
OptimizationFlag optimizations = all_safe_optimizations;
bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
/// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
/// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
std::uint32_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
std::int32_t page_table_pointer_mask_bits = 0;
/// Select the architecture version to use.
/// There are minor behavioural differences between versions.
ArchVersion arch_version = ArchVersion::v8;
/// Processor ID
std::uint8_t processor_id = 0;
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// This enables unsafe optimizations that reduce emulation accuracy in favour of speed.
/// For safety, in order to enable unsafe optimizations you have to set BOTH this flag
@ -150,12 +188,6 @@ struct UserConfig {
/// The prefered and tested mode for this library is with unsafe optimizations disabled.
bool unsafe_optimizations = false;
// Page Table
// The page table is used for faster memory access. If an entry in the table is nullptr,
// the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>* page_table = nullptr;
/// Determines if the pointer in the page_table shall be offseted locally or globally.
/// 'false' will access page_table[addr >> bits][addr & mask]
/// 'true' will access page_table[addr >> bits][addr]
@ -163,26 +195,11 @@ struct UserConfig {
/// So there might be wrongly faulted pages which maps to nullptr.
/// This can be avoided by carefully allocating the memory region.
bool absolute_offset_page_table = false;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
int page_table_pointer_mask_bits = 0;
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// Determines if the above option only triggers when the misalignment straddles a
/// page boundary.
bool only_detect_misalignment_via_page_table_on_page_boundary = false;
// Fastmem Pointer
// This should point to the beginning of a 4GB address space which is in arranged just like
// what you wish for emulated memory to be. If the host page faults on an address, the JIT
// will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
std::optional<uintptr_t> fastmem_pointer = std::nullopt;
/// Determines if instructions that pagefault should cause recompilation of that block
/// with fastmem disabled.
/// Recompiled code will use the page_table if this is available, otherwise memory
@ -198,9 +215,6 @@ struct UserConfig {
/// callbacks.
bool recompile_on_exclusive_fastmem_failure = true;
// Coprocessors
std::array<std::shared_ptr<Coprocessor>, 16> coprocessors{};
/// When set to true, UserCallbacks::InstructionSynchronizationBarrierRaised will be
/// called when an ISB instruction is executed.
/// When set to false, ISB will be treated as a NOP instruction.
@ -234,10 +248,6 @@ struct UserConfig {
/// in unusual behavior.
bool always_little_endian = false;
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
size_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Internal use only
bool very_verbose_debugging_output = false;
};

View file

@ -136,11 +136,30 @@ struct UserCallbacks {
};
struct UserConfig {
/// Fastmem Pointer
/// This should point to the beginning of a 2^page_table_address_space_bits bytes
/// address space which is in arranged just like what you wish for emulated memory to
/// be. If the host page faults on an address, the JIT will fallback to calling the
/// MemoryRead*/MemoryWrite* callbacks.
std::optional<std::uintptr_t> fastmem_pointer = std::nullopt;
UserCallbacks* callbacks;
size_t processor_id = 0;
ExclusiveMonitor* global_monitor = nullptr;
/// Pointer to where TPIDRRO_EL0 is stored. This pointer will be inserted into
/// emitted code.
const std::uint64_t* tpidrro_el0 = nullptr;
/// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into
/// emitted code.
std::uint64_t* tpidr_el0 = nullptr;
/// Pointer to the page table which we can use for direct page table access.
/// If an entry in page_table is null, the relevant memory callback will be called.
/// If page_table is nullptr, all memory accesses hit the memory callbacks.
void** page_table = nullptr;
/// This selects other optimizations than can't otherwise be disabled by setting other
/// configuration options. This includes:
/// - IR optimizations
@ -149,12 +168,50 @@ struct UserConfig {
/// This is intended to be used for debugging.
OptimizationFlag optimizations = all_safe_optimizations;
bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of page_table. Valid values are between 12 and 64 inclusive.
/// This is only used if page_table is not nullptr.
std::uint32_t page_table_address_space_bits = 36;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
std::int32_t page_table_pointer_mask_bits = 0;
/// Counter-timer frequency register. The value of the register is not interpreted by
/// dynarmic.
std::uint32_t cntfrq_el0 = 600000000;
/// CTR_EL0<27:24> is log2 of the cache writeback granule in words.
/// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words.
/// CTR_EL0<19:16> is log2 of the smallest data/unified cacheline in words.
/// CTR_EL0<15:14> is the level 1 instruction cache policy.
/// CTR_EL0<3:0> is log2 of the smallest instruction cacheline in words.
std::uint32_t ctr_el0 = 0x8444c004;
/// DCZID_EL0<3:0> is log2 of the block size in words
/// DCZID_EL0<4> is 0 if the DC ZVA instruction is permitted.
std::uint32_t dczid_el0 = 4;
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of fastmem arena. Valid values are between 12 and 64 inclusive.
/// This is only used if fastmem_pointer is set.
std::uint32_t fastmem_address_space_bits = 36;
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
std::uint32_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64 | 128.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// Processor ID
std::uint8_t processor_id = 0;
/// This enables unsafe optimizations that reduce emulation accuracy in favour of speed.
/// For safety, in order to enable unsafe optimizations you have to set BOTH this flag
@ -177,48 +234,13 @@ struct UserConfig {
/// instruction is executed.
bool hook_hint_instructions = false;
/// Counter-timer frequency register. The value of the register is not interpreted by
/// dynarmic.
std::uint32_t cntfrq_el0 = 600000000;
/// CTR_EL0<27:24> is log2 of the cache writeback granule in words.
/// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words.
/// CTR_EL0<19:16> is log2 of the smallest data/unified cacheline in words.
/// CTR_EL0<15:14> is the level 1 instruction cache policy.
/// CTR_EL0<3:0> is log2 of the smallest instruction cacheline in words.
std::uint32_t ctr_el0 = 0x8444c004;
/// DCZID_EL0<3:0> is log2 of the block size in words
/// DCZID_EL0<4> is 0 if the DC ZVA instruction is permitted.
std::uint32_t dczid_el0 = 4;
/// Pointer to where TPIDRRO_EL0 is stored. This pointer will be inserted into
/// emitted code.
const std::uint64_t* tpidrro_el0 = nullptr;
/// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into
/// emitted code.
std::uint64_t* tpidr_el0 = nullptr;
/// Pointer to the page table which we can use for direct page table access.
/// If an entry in page_table is null, the relevant memory callback will be called.
/// If page_table is nullptr, all memory accesses hit the memory callbacks.
void** page_table = nullptr;
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of page_table. Valid values are between 12 and 64 inclusive.
/// This is only used if page_table is not nullptr.
size_t page_table_address_space_bits = 36;
/// Masks out the first N bits in host pointers from the page table.
/// The intention behind this is to allow users of Dynarmic to pack attributes in the
/// same integer and update the pointer attribute pair atomically.
/// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
int page_table_pointer_mask_bits = 0;
/// Determines what happens if the guest accesses an entry that is off the end of the
/// page table. If true, Dynarmic will silently mirror page_table's address space. If
/// false, accessing memory outside of page_table bounds will result in a call to the
/// relevant memory callback.
/// This is only used if page_table is not nullptr.
bool silently_mirror_page_table = true;
/// Determines if the pointer in the page_table shall be offseted locally or globally.
/// 'false' will access page_table[addr >> bits][addr & mask]
/// 'true' will access page_table[addr >> bits][addr]
@ -226,31 +248,17 @@ struct UserConfig {
/// So there might be wrongly faulted pages which maps to nullptr.
/// This can be avoided by carefully allocating the memory region.
bool absolute_offset_page_table = false;
/// Determines if we should detect memory accesses via page_table that straddle are
/// misaligned. Accesses that straddle page boundaries will fallback to the relevant
/// memory callback.
/// This value should be the required access sizes this applies to ORed together.
/// To detect any access, use: 8 | 16 | 32 | 64 | 128.
std::uint8_t detect_misaligned_access_via_page_table = 0;
/// Determines if the above option only triggers when the misalignment straddles a
/// page boundary.
bool only_detect_misalignment_via_page_table_on_page_boundary = false;
/// Fastmem Pointer
/// This should point to the beginning of a 2^page_table_address_space_bits bytes
/// address space which is in arranged just like what you wish for emulated memory to
/// be. If the host page faults on an address, the JIT will fallback to calling the
/// MemoryRead*/MemoryWrite* callbacks.
std::optional<uintptr_t> fastmem_pointer = std::nullopt;
/// Determines if instructions that pagefault should cause recompilation of that block
/// with fastmem disabled.
/// Recompiled code will use the page_table if this is available, otherwise memory
/// accesses will hit the memory callbacks.
bool recompile_on_fastmem_failure = true;
/// Declares how many valid address bits are there in virtual addresses.
/// Determines the size of fastmem arena. Valid values are between 12 and 64 inclusive.
/// This is only used if fastmem_pointer is set.
size_t fastmem_address_space_bits = 36;
/// Determines what happens if the guest accesses an entry that is off the end of the
/// fastmem arena. If true, Dynarmic will silently mirror fastmem's address space. If
/// false, accessing memory outside of fastmem bounds will result in a call to the
@ -285,12 +293,15 @@ struct UserConfig {
/// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
bool enable_cycle_counting = true;
// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
// Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
size_t code_cache_size = 128 * 1024 * 1024; // bytes
/// Internal use only
bool very_verbose_debugging_output = false;
inline bool HasOptimization(OptimizationFlag f) const {
if (!unsafe_optimizations) {
f &= all_safe_optimizations;
}
return (f & optimizations) != no_optimizations;
}
};
} // namespace A64

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -24,8 +24,8 @@ if (NOT EXISTS "${TZ_DIR}" OR NOT EXISTS "${TZIF_LIST_FILE}")
# separate directory before building.
execute_process(
COMMAND
${GIT_PROGRAM} clone --depth 1 "file://${TZ_SOURCE_DIR}" "${TZ_TMP_SOURCE_DIR}"
COMMAND_ERROR_IS_FATAL ANY
${GIT_PROGRAM} clone --depth=1 "file://${TZ_SOURCE_DIR}" "${TZ_TMP_SOURCE_DIR}"
# No need to be fatal, on SunOS this works fine - COMMAND_ERROR_IS_FATAL ANY
)
if (APPLE)

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "tzif.h"
#include <array>
#include <cerrno>
@ -7,7 +10,7 @@
#include <getopt.h>
#include <poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cstdint>
#include <unistd.h>
constexpr std::size_t ten_megabytes{(1 << 20) * 10};
@ -92,7 +95,7 @@ int main(int argc, char *argv[]) {
}
}
u_int8_t *buf = new u_int8_t[filesize];
std::uint8_t *buf = new std::uint8_t[filesize];
filesize = read(f, buf, filesize);
if (filesize == static_cast<std::size_t>(-1)) {
@ -124,7 +127,7 @@ int main(int argc, char *argv[]) {
delete[] buf;
std::vector<u_int8_t> output_buffer;
std::vector<std::uint8_t> output_buffer;
tzif_data->ReformatNintendo(output_buffer);
filename = "(stdout)";

View file

@ -1,14 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "tzif.h"
#include <cstdint>
#include <cstring>
#include <memory>
#include <sys/types.h>
#include <cstdint>
namespace Tzif {
static std::size_t SkipToVersion2(const u_int8_t *data, std::size_t size) {
static std::size_t SkipToVersion2(const std::uint8_t *data, std::size_t size) {
char magic[5];
const u_int8_t *p{data};
const std::uint8_t *p{data};
std::memcpy(magic, data, 4);
magic[4] = '\0';
@ -28,15 +31,15 @@ static std::size_t SkipToVersion2(const u_int8_t *data, std::size_t size) {
}
template <typename Type> constexpr static void SwapEndianess(Type *value) {
u_int8_t *data = reinterpret_cast<u_int8_t *>(value);
std::uint8_t *data = reinterpret_cast<std::uint8_t *>(value);
union {
u_int8_t data[sizeof(Type)];
std::uint8_t data[sizeof(Type)];
Type value;
} temp;
for (u_int32_t i = 0; i < sizeof(Type); i++) {
u_int32_t alt_index = sizeof(Type) - i - 1;
for (std::uint32_t i = 0; i < sizeof(Type); i++) {
std::uint32_t alt_index = sizeof(Type) - i - 1;
temp.data[alt_index] = data[i];
}
@ -52,13 +55,13 @@ static void FlipHeader(Header &header) {
SwapEndianess(&header.charcnt);
}
std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size) {
std::unique_ptr<DataImpl> ReadData(const std::uint8_t *data, std::size_t size) {
const std::size_t v2_offset = SkipToVersion2(data, size);
if (v2_offset == static_cast<std::size_t>(-1)) {
return nullptr;
}
const u_int8_t *p = data + v2_offset;
const std::uint8_t *p = data + v2_offset;
Header header;
std::memcpy(&header, p, sizeof(header));
@ -67,10 +70,10 @@ std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size) {
FlipHeader(header);
const std::size_t data_block_length =
header.timecnt * sizeof(int64_t) + header.timecnt * sizeof(u_int8_t) +
header.timecnt * sizeof(int64_t) + header.timecnt * sizeof(std::uint8_t) +
header.typecnt * sizeof(TimeTypeRecord) +
header.charcnt * sizeof(int8_t) + header.isstdcnt * sizeof(u_int8_t) +
header.isutcnt * sizeof(u_int8_t);
header.charcnt * sizeof(int8_t) + header.isstdcnt * sizeof(std::uint8_t) +
header.isutcnt * sizeof(std::uint8_t);
if (v2_offset + data_block_length + sizeof(Header) > size) {
return nullptr;
@ -81,7 +84,7 @@ std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size) {
const auto copy =
[]<typename Type>(std::unique_ptr<Type[]> &array, int length,
const u_int8_t *const &ptr) -> const u_int8_t * {
const std::uint8_t *const &ptr) -> const std::uint8_t * {
const std::size_t region_length = length * sizeof(Type);
array = std::make_unique<Type[]>(length);
std::memcpy(array.get(), ptr, region_length);
@ -110,16 +113,16 @@ std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size) {
return impl;
}
static void PushToBuffer(std::vector<u_int8_t> &buffer, const void *data,
static void PushToBuffer(std::vector<std::uint8_t> &buffer, const void *data,
std::size_t size) {
const u_int8_t *p{reinterpret_cast<const u_int8_t *>(data)};
const std::uint8_t *p{reinterpret_cast<const std::uint8_t *>(data)};
for (std::size_t i = 0; i < size; i++) {
buffer.push_back(*p);
p++;
}
}
void DataImpl::ReformatNintendo(std::vector<u_int8_t> &buffer) const {
void DataImpl::ReformatNintendo(std::vector<std::uint8_t> &buffer) const {
buffer.clear();
Header header_copy{header};
@ -131,7 +134,7 @@ void DataImpl::ReformatNintendo(std::vector<u_int8_t> &buffer) const {
PushToBuffer(buffer, transition_times.get(),
header.timecnt * sizeof(int64_t));
PushToBuffer(buffer, transition_types.get(),
header.timecnt * sizeof(u_int8_t));
header.timecnt * sizeof(std::uint8_t));
PushToBuffer(buffer, local_time_type_records.get(),
header.typecnt * sizeof(TimeTypeRecord));
PushToBuffer(buffer, time_zone_designations.get(),

View file

@ -1,22 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <memory>
#include <sys/types.h>
#include <cstdint>
#include <vector>
namespace Tzif {
typedef struct {
char magic[4];
u_int8_t version;
u_int8_t reserved[15];
u_int32_t isutcnt;
u_int32_t isstdcnt;
u_int32_t leapcnt;
u_int32_t timecnt;
u_int32_t typecnt;
u_int32_t charcnt;
std::uint8_t version;
std::uint8_t reserved[15];
std::uint32_t isutcnt;
std::uint32_t isstdcnt;
std::uint32_t leapcnt;
std::uint32_t timecnt;
std::uint32_t typecnt;
std::uint32_t charcnt;
} Header;
static_assert(sizeof(Header) == 0x2c);
@ -34,9 +37,9 @@ public:
#pragma pack(push, 1)
typedef struct {
u_int32_t utoff;
u_int8_t dst;
u_int8_t idx;
std::uint32_t utoff;
std::uint8_t dst;
std::uint8_t idx;
} TimeTypeRecord;
#pragma pack(pop)
static_assert(sizeof(TimeTypeRecord) == 0x6);
@ -46,7 +49,7 @@ public:
explicit Data() = default;
virtual ~Data() = default;
virtual void ReformatNintendo(std::vector<u_int8_t> &buffer) const = 0;
virtual void ReformatNintendo(std::vector<std::uint8_t> &buffer) const = 0;
};
class DataImpl : public Data {
@ -54,19 +57,19 @@ public:
explicit DataImpl() = default;
~DataImpl() override = default;
void ReformatNintendo(std::vector<u_int8_t> &buffer) const override;
void ReformatNintendo(std::vector<std::uint8_t> &buffer) const override;
Header header;
Footer footer;
std::unique_ptr<int64_t[]> transition_times;
std::unique_ptr<u_int8_t[]> transition_types;
std::unique_ptr<std::uint8_t[]> transition_types;
std::unique_ptr<TimeTypeRecord[]> local_time_type_records;
std::unique_ptr<int8_t[]> time_zone_designations;
std::unique_ptr<u_int8_t[]> standard_indicators;
std::unique_ptr<u_int8_t[]> ut_indicators;
std::unique_ptr<std::uint8_t[]> standard_indicators;
std::unique_ptr<std::uint8_t[]> ut_indicators;
};
std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size);
std::unique_ptr<DataImpl> ReadData(const std::uint8_t *data, std::size_t size);
} // namespace Tzif

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Baldur Karlsson
// SPDX-License-Identifier: MIT
@ -38,14 +41,8 @@
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define RENDERDOC_CC __cdecl
#elif defined(__linux__)
#define RENDERDOC_CC
#elif defined(__APPLE__)
#define RENDERDOC_CC
#elif defined(__FreeBSD__)
#define RENDERDOC_CC
#else
#error "Unknown platform"
#define RENDERDOC_CC
#endif
#ifdef __cplusplus

View file

@ -1,6 +1,6 @@
# This file has been adapted from dynarmic
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.12)
project(sirit CXX)
# Determine if we're built as a subproject (using add_subdirectory)

View file

@ -15,6 +15,7 @@ import android.view.Surface
import android.view.View
import android.widget.TextView
import androidx.annotation.Keep
import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import net.swiftzer.semver.SemVer
import java.lang.ref.WeakReference
@ -27,6 +28,7 @@ import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.network.NetPlayManager
import java.io.File
/**
* Class which contains methods that interact
@ -102,6 +104,21 @@ object NativeLibrary {
FileUtil.getFilename(Uri.parse(path))
}
@Keep
@JvmStatic
fun copyFileToStorage(source: String, destdir: String): Boolean {
return FileUtil.copyUriToInternalStorage(
source.toUri(),
destdir
) != null
}
@Keep
@JvmStatic
fun getFileExtension(source: String): String {
return FileUtil.getExtension(source.toUri())
}
external fun setAppDirectory(directory: String)
/**
@ -415,18 +432,29 @@ object NativeLibrary {
*/
external fun firmwareVersion(): String
fun isFirmwareSupported(): Boolean {
var version: SemVer
/**
* Verifies installed firmware.
*
* @return The result code.
*/
external fun verifyFirmware(): Int
try {
version = SemVer.parse(firmwareVersion())
} catch (_: Exception) {
return false
}
val max = SemVer(19, 0, 1)
/**
* Check if a game requires firmware to be playable.
*
* @param programId The game's Program ID.
* @return Whether or not the game requires firmware to be playable.
*/
external fun gameRequiresFirmware(programId: String): Boolean
return version <= max
}
/**
* Installs keys from the specified path.
*
* @param path The path to install keys from.
* @param ext What extension the keys should have.
* @return The result code.
*/
external fun installKeys(path: String, ext: String): Int
/**
* Checks the PatchManager for any addons that are available

View file

@ -3,11 +3,16 @@
package org.yuzu.yuzu_emu.adapters
import android.content.DialogInterface
import android.net.Uri
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.pm.ShortcutInfoCompat
@ -33,6 +38,10 @@ import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
import androidx.recyclerview.widget.RecyclerView
import androidx.core.net.toUri
import androidx.core.content.edit
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
class GameAdapter(private val activity: AppCompatActivity) :
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>(exact = false) {
@ -171,8 +180,9 @@ class GameAdapter(private val activity: AppCompatActivity) :
fun onClick(game: Game) {
val gameExists = DocumentFile.fromSingleUri(
YuzuApplication.appContext,
Uri.parse(game.path)
game.path.toUri()
)?.exists() == true
if (!gameExists) {
Toast.makeText(
YuzuApplication.appContext,
@ -184,14 +194,15 @@ class GameAdapter(private val activity: AppCompatActivity) :
return
}
val launch: () -> Unit = {
val preferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
preferences.edit()
.putLong(
preferences.edit {
putLong(
game.keyLastPlayedTime,
System.currentTimeMillis()
)
.apply()
}
activity.lifecycleScope.launch {
withContext(Dispatchers.IO) {
@ -209,6 +220,25 @@ class GameAdapter(private val activity: AppCompatActivity) :
binding.root.findNavController().navigate(action)
}
if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.loader_requires_firmware)
.setMessage(
Html.fromHtml(
activity.getString(R.string.loader_requires_firmware_description),
Html.FROM_HTML_MODE_LEGACY
)
)
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
launch()
}
.setNegativeButton(android.R.string.cancel) { _,_ -> }
.show()
} else {
launch()
}
}
fun onLongClick(game: Game): Boolean {
val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game)
binding.root.findNavController().navigate(action)

View file

@ -34,6 +34,7 @@ import org.yuzu.yuzu_emu.databinding.ItemBanListBinding
import org.yuzu.yuzu_emu.databinding.ItemButtonNetplayBinding
import org.yuzu.yuzu_emu.databinding.ItemTextNetplayBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.network.NetDataValidators
import org.yuzu.yuzu_emu.network.NetPlayManager
import org.yuzu.yuzu_emu.utils.CompatUtils
import org.yuzu.yuzu_emu.utils.GameHelper
@ -102,6 +103,13 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
dismiss()
}
btnLobbyBrowser.setOnClickListener {
if (!NetDataValidators.username()) {
Toast.makeText(
context,
R.string.multiplayer_nickname_invalid,
Toast.LENGTH_LONG
).show()
} else {
LobbyBrowser(context).show()
dismiss()
}
@ -109,6 +117,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
}
}
}
}
data class NetPlayItems(
val option: Int,
@ -368,7 +377,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
)
) {
override fun validate(s: String): Boolean {
return s.length in 3..20
return NetDataValidators.roomName(s)
}
}
@ -378,7 +387,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_required)
) {
override fun validate(s: String): Boolean {
return s.isNotEmpty()
return NetDataValidators.notEmpty(s)
}
}
@ -388,12 +397,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_token_required)
) {
override fun validate(s: String): Boolean {
if (s != context.getString(R.string.multiplayer_public_visibility)) {
return true;
}
val token = StringSetting.WEB_TOKEN.getString()
return token.matches(Regex("[a-z]{48}"))
return NetDataValidators.roomVisibility(s, context)
}
}
@ -403,12 +407,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_ip_error)
) {
override fun validate(s: String): Boolean {
return try {
InetAddress.getByName(s)
s.length >= 7
} catch (_: Exception) {
false
}
return NetDataValidators.ipAddress(s)
}
}
@ -418,7 +417,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_username_error)
) {
override fun validate(s: String): Boolean {
return s.length in 4..20
return NetDataValidators.username(s)
}
}
@ -428,7 +427,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
context.getString(R.string.multiplayer_port_error)
) {
override fun validate(s: String): Boolean {
return s.toIntOrNull() in 1..65535
return NetDataValidators.port(s)
}
}

View file

@ -20,6 +20,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.network.NetDataValidators
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
@ -300,9 +301,7 @@ abstract class SettingsItem(
val chars = "abcdefghijklmnopqrstuvwxyz"
(1..48).map { chars.random() }.joinToString("")
},
validator = { s ->
s?.matches(Regex("[a-z]{48}")) == true
},
validator = NetDataValidators::token,
errorId = R.string.multiplayer_token_error
)
)
@ -312,9 +311,7 @@ abstract class SettingsItem(
StringSetting.WEB_USERNAME,
titleId = R.string.web_username,
descriptionId = R.string.web_username_description,
validator = { s ->
s?.length in 4..20
},
validator = NetDataValidators::username,
errorId = R.string.multiplayer_username_error
)
)

View file

@ -154,8 +154,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
stringInputBinding.generate.setOnClickListener {
stringInputBinding.editText.setText(onGenerate())
}
} else {
stringInputBinding.generate.isVisible = false
}
val validator = item.validator
@ -179,8 +177,9 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
}
override fun afterTextChanged(s: Editable?) {
stringInputBinding.editText.error =
if (validator(s.toString())) null else requireContext().getString(item.errorId)
val isValid = validator(s.toString())
stringInputBinding.editTextLayout.isErrorEnabled = !isValid
stringInputBinding.editTextLayout.error = if (isValid) null else requireContext().getString(item.errorId)
}
}

View file

@ -264,8 +264,6 @@ class DriverFetcherFragment : Fragment() {
}
releases.add(release)
println(release.publishTime)
}
}

View file

@ -137,7 +137,7 @@ class HomeSettingsFragment : Fragment() {
binding.root.findNavController()
.navigate(R.id.action_homeSettingsFragment_to_appletLauncherFragment)
},
{ NativeLibrary.isFirmwareAvailable() && NativeLibrary.isFirmwareSupported() },
{ NativeLibrary.isFirmwareAvailable() },
R.string.applets_error_firmware,
R.string.applets_error_description
)

View file

@ -352,7 +352,7 @@ class SetupFragment : Fragment() {
val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
mainActivity.processKey(result)
mainActivity.processKey(result, "keys")
if (NativeLibrary.areKeysPresent()) {
keyCallback.onStepCompleted()
}

View file

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.network
import android.content.Context
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import java.net.InetAddress
object NetDataValidators {
fun roomName(s: String): Boolean {
return s.length in 3..20
}
fun notEmpty(s: String): Boolean {
return s.isNotEmpty()
}
fun token(s: String?): Boolean {
return s?.matches(Regex("[a-z]{48}")) == true
}
fun token(): Boolean {
return token(StringSetting.WEB_TOKEN.getString())
}
fun roomVisibility(s: String, context: Context): Boolean {
if (s != context.getString(R.string.multiplayer_public_visibility)) {
return true;
}
return token()
}
fun ipAddress(s: String): Boolean {
return try {
InetAddress.getByName(s)
s.length >= 7
} catch (_: Exception) {
false
}
}
fun username(s: String?): Boolean {
return s?.matches(Regex("^[ a-zA-Z0-9._-]{4,20}$")) == true
}
fun username(): Boolean {
return username(StringSetting.WEB_USERNAME.getString())
}
fun port(s: String): Boolean {
return s.toIntOrNull() in 1..65535
}
}

View file

@ -47,9 +47,6 @@ import info.debatty.java.stringsimilarity.Jaccard
import info.debatty.java.stringsimilarity.JaroWinkler
import java.util.Locale
import androidx.core.content.edit
import androidx.core.view.updateLayoutParams
import org.yuzu.yuzu_emu.features.settings.model.Settings
import android.view.ViewParent
import androidx.core.view.doOnNextLayout
class GamesFragment : Fragment() {
@ -151,7 +148,7 @@ class GamesFragment : Fragment() {
)
}
gamesViewModel.games.collect(viewLifecycleOwner) {
if (it.size > 0) {
if (it.isNotEmpty()) {
setAdapter(it)
}
}
@ -361,7 +358,7 @@ class GamesFragment : Fragment() {
popup.setOnMenuItemClickListener { item ->
currentFilter = item.itemId
preferences.edit().putInt(PREF_SORT_TYPE, currentFilter).apply()
preferences.edit { putInt(PREF_SORT_TYPE, currentFilter) }
filterAndSearch()
true
}

View file

@ -6,6 +6,8 @@ package org.yuzu.yuzu_emu.ui.main
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.ParcelFileDescriptor
import android.provider.OpenableColumns
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.view.WindowManager
@ -47,6 +49,7 @@ import java.io.BufferedOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import androidx.core.content.edit
import androidx.core.net.toFile
class MainActivity : AppCompatActivity(), ThemeProvider {
private lateinit var binding: ActivityMainBinding
@ -70,10 +73,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val granted = permissions.entries.all { it.value }
if (granted) {
// Permissions were granted.
Toast.makeText(this, R.string.bluetooth_permissions_granted, Toast.LENGTH_SHORT).show()
Toast.makeText(this, R.string.bluetooth_permissions_granted, Toast.LENGTH_SHORT)
.show()
} else {
// Permissions were denied.
Toast.makeText(this, R.string.bluetooth_permissions_denied, Toast.LENGTH_LONG).show()
Toast.makeText(this, R.string.bluetooth_permissions_denied, Toast.LENGTH_LONG)
.show()
}
}
@ -146,22 +151,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
binding.statusBarShade.setBackgroundColor(
ThemeHelper.getColorWithOpacity(
MaterialColors.getColor(
binding.root,
com.google.android.material.R.attr.colorSurface
),
ThemeHelper.SYSTEM_BAR_ALPHA
binding.root, com.google.android.material.R.attr.colorSurface
), ThemeHelper.SYSTEM_BAR_ALPHA
)
)
if (InsetsHelper.getSystemGestureType(applicationContext) !=
InsetsHelper.GESTURE_NAVIGATION
) {
if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) {
binding.navigationBarShade.setBackgroundColor(
ThemeHelper.getColorWithOpacity(
MaterialColors.getColor(
binding.root,
com.google.android.material.R.attr.colorSurface
),
ThemeHelper.SYSTEM_BAR_ALPHA
binding.root, com.google.android.material.R.attr.colorSurface
), ThemeHelper.SYSTEM_BAR_ALPHA
)
)
}
@ -172,9 +171,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) }
homeViewModel.contentToInstall.collect(
this,
resetState = { homeViewModel.setContentToInstall(null) }
) {
this, resetState = { homeViewModel.setContentToInstall(null) }) {
if (it != null) {
installContent(it)
}
@ -183,7 +180,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
if (it) checkKeys()
}
homeViewModel.checkFirmware.collect(this, resetState = { homeViewModel.setCheckFirmware(false) }) {
homeViewModel.checkFirmware.collect(
this, resetState = { homeViewModel.setCheckFirmware(false) }) {
if (it) checkFirmware()
}
@ -203,12 +201,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
negativeButtonTitleId = R.string.close,
showNegativeButton = true,
positiveAction = {
PreferenceManager.getDefaultSharedPreferences(applicationContext)
.edit() {
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit() {
putBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_WARNING, false)
}
}
).show(supportFragmentManager, MessageDialogFragment.TAG)
}).show(supportFragmentManager, MessageDialogFragment.TAG)
}
}
@ -228,15 +224,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
private fun checkFirmware() {
if (!NativeLibrary.isFirmwareAvailable() || !NativeLibrary.isFirmwareSupported()) {
val resultCode: Int = NativeLibrary.verifyFirmware()
if (resultCode == 0) return;
val resultString: String =
resources.getStringArray(R.array.verifyFirmwareResults)[resultCode]
MessageDialogFragment.newInstance(
titleId = R.string.firmware_missing,
descriptionId = R.string.firmware_missing_description,
titleId = R.string.firmware_invalid,
descriptionString = resultString,
helpLinkId = R.string.firmware_missing_help
).show(supportFragmentManager, MessageDialogFragment.TAG)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
@ -283,8 +282,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
super.onResume()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener(
binding.root
) { _: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
@ -315,17 +313,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
fun processGamesDir(result: Uri, calledFromGameFragment: Boolean = false) {
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
result, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
val uriString = result.toString()
val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString }
if (folder != null) {
Toast.makeText(
applicationContext,
R.string.folder_already_added,
Toast.LENGTH_SHORT
applicationContext, R.string.folder_already_added, Toast.LENGTH_SHORT
).show()
return
}
@ -334,72 +329,52 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
.show(supportFragmentManager, AddGameFolderDialogFragment.TAG)
}
val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
val getProdKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
processKey(result)
processKey(result, "keys")
}
}
fun processKey(result: Uri): Boolean {
if (FileUtil.getExtension(result) != "keys") {
MessageDialogFragment.newInstance(
this,
titleId = R.string.reading_keys_failure,
descriptionId = R.string.install_prod_keys_failure_extension_description
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
val getAmiiboKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
processKey(result, "bin")
}
}
fun processKey(result: Uri, extension: String = "keys") {
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
result, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
result,
dstPath,
"prod.keys"
) != null
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
applicationContext,
R.string.install_keys_success,
Toast.LENGTH_SHORT
).show()
homeViewModel.setCheckKeys(true)
val resultCode: Int = NativeLibrary.installKeys(result.toString(), extension);
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
if (!firstTimeSetup) {
homeViewModel.setCheckFirmware(true)
}
if (resultCode == 0) {
// TODO(crueter): It may be worth it to switch some of these Toasts to snackbars,
// since most of it is foreground-only anyways.
Toast.makeText(
applicationContext, R.string.keys_install_success, Toast.LENGTH_SHORT
).show()
gamesViewModel.reloadGames(true)
return true
} else {
return
}
val resultString: String =
resources.getStringArray(R.array.installKeysResults)[resultCode]
MessageDialogFragment.newInstance(
this,
titleId = R.string.invalid_keys_error,
descriptionId = R.string.install_keys_failure_description,
helpLinkId = R.string.dumping_keys_quickstart_link
titleId = R.string.keys_failed,
descriptionString = resultString,
helpLinkId = R.string.keys_missing_help
).show(supportFragmentManager, MessageDialogFragment.TAG)
return false
}
}
return false
}
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
val getFirmware = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
processFirmware(result)
}
}
fun processFirmware(result: Uri, onComplete: (() -> Unit)? = null) {
val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
@ -409,15 +384,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
ProgressDialogFragment.newInstance(
this,
R.string.firmware_installing
this, R.string.firmware_installing
) { progressCallback, _ ->
var messageToShow: Any
try {
FileUtil.unzipToInternalStorage(
result.toString(),
cacheFirmwareDir,
progressCallback
result.toString(), cacheFirmwareDir, progressCallback
)
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
@ -448,10 +420,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
fun uninstallFirmware() {
val firmwarePath = File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
val firmwarePath =
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
ProgressDialogFragment.newInstance(
this,
R.string.firmware_uninstalling
this, R.string.firmware_uninstalling
) { progressCallback, _ ->
var messageToShow: Any
try {
@ -473,49 +445,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
messageToShow
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
val getAmiiboKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
if (FileUtil.getExtension(result) != "bin") {
MessageDialogFragment.newInstance(
this,
titleId = R.string.reading_keys_failure,
descriptionId = R.string.install_amiibo_keys_failure_extension_description
).show(supportFragmentManager, MessageDialogFragment.TAG)
return@registerForActivityResult
}
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
result,
dstPath,
"key_retail.bin"
) != null
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
applicationContext,
R.string.install_keys_success,
Toast.LENGTH_SHORT
).show()
} else {
MessageDialogFragment.newInstance(
this,
titleId = R.string.invalid_keys_error,
descriptionId = R.string.install_keys_failure_description,
helpLinkId = R.string.dumping_keys_quickstart_link
).show(supportFragmentManager, MessageDialogFragment.TAG)
}
}
}
val installGameUpdate = registerForActivityResult(
ActivityResultContracts.OpenMultipleDocuments()
@ -530,15 +459,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
ProgressDialogFragment.newInstance(
this@MainActivity,
R.string.verifying_content,
false
this@MainActivity, R.string.verifying_content, false
) { _, _ ->
var updatesMatchProgram = true
for (document in documents) {
val valid = NativeLibrary.doesUpdateMatchProgram(
addonViewModel.game!!.programId,
document.toString()
addonViewModel.game!!.programId, document.toString()
)
if (!valid) {
updatesMatchProgram = false
@ -554,16 +480,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
titleId = R.string.content_install_notice,
descriptionId = R.string.content_install_notice_description,
positiveAction = { homeViewModel.setContentToInstall(documents) },
negativeAction = {}
)
negativeAction = {})
}
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
private fun installContent(documents: List<Uri>) {
ProgressDialogFragment.newInstance(
this@MainActivity,
R.string.installing_game_content
this@MainActivity, R.string.installing_game_content
) { progressCallback, messageCallback ->
var installSuccess = 0
var installOverwrite = 0
@ -571,14 +495,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
var error = 0
documents.forEach {
messageCallback.invoke(FileUtil.getFilename(it))
when (
InstallResult.from(
when (InstallResult.from(
NativeLibrary.installFileToNand(
it.toString(),
progressCallback
it.toString(), progressCallback
)
)
) {
)) {
InstallResult.Success -> {
installSuccess += 1
}
@ -599,13 +520,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
addonViewModel.refreshAddons()
val separator = System.getProperty("line.separator") ?: "\n"
val separator = System.lineSeparator() ?: "\n"
val installResult = StringBuilder()
if (installSuccess > 0) {
installResult.append(
getString(
R.string.install_game_content_success_install,
installSuccess
R.string.install_game_content_success_install, installSuccess
)
)
installResult.append(separator)
@ -613,8 +533,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
if (installOverwrite > 0) {
installResult.append(
getString(
R.string.install_game_content_success_overwrite,
installOverwrite
R.string.install_game_content_success_overwrite, installOverwrite
)
)
installResult.append(separator)
@ -624,8 +543,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
installResult.append(separator)
installResult.append(
getString(
R.string.install_game_content_failed_count,
errorTotal
R.string.install_game_content_failed_count, errorTotal
)
)
installResult.append(separator)
@ -666,9 +584,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
ProgressDialogFragment.newInstance(
this,
R.string.exporting_user_data,
true
this, R.string.exporting_user_data, true
) { progressCallback, _ ->
val zipResult = FileUtil.zipFromInternalStorage(
File(DirectoryInitialization.userDirectory!!),
@ -692,8 +608,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
ProgressDialogFragment.newInstance(
this,
R.string.importing_user_data
this, R.string.importing_user_data
) { progressCallback, _ ->
val checkStream =
ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result)))

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -177,6 +180,10 @@ object GpuDriverHelper {
* @return A non-null [GpuDriverMetadata] instance that may have null members
*/
fun getMetadataFromZip(driver: File): GpuDriverMetadata {
if (!driver.exists()) {
return GpuDriverMetadata()
}
try {
ZipFile(driver).use { zf ->
val entries = zf.entries()

View file

@ -60,6 +60,7 @@
#include "core/hle/service/set/system_settings_server.h"
#include "core/loader/loader.h"
#include "frontend_common/config.h"
#include "frontend_common/firmware_manager.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
@ -283,6 +284,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
: Service::AM::LaunchType::ApplicationInitiated,
.program_index = static_cast<s32>(program_index),
};
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
if (m_load_result != Core::SystemResultStatus::Success) {
return m_load_result;
@ -764,35 +766,19 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass cl
}
bool isFirmwarePresent() {
auto bis_system =
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
return false;
}
// Query an applet to see if it's available
auto applet_nca =
bis_system->GetEntry(0x010000000000100Dull, FileSys::ContentRecordType::Program);
if (!applet_nca) {
return false;
}
return true;
return FirmwareManager::CheckFirmwarePresence(EmulationSession::GetInstance().System());
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env, jclass clazz) {
return isFirmwarePresent();
}
// TODO(crueter): This check is nonfunctional...
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclass clazz) {
Service::Set::FirmwareVersionFormat firmware_data{};
const auto result = Service::Set::GetFirmwareVersionImpl(
firmware_data, EmulationSession::GetInstance().System(),
Service::Set::GetFirmwareVersionType::Version2);
const auto pair = FirmwareManager::GetFirmwareVersion(EmulationSession::GetInstance().System());
const auto firmware_data = pair.first;
const auto result = pair.second;
if (result.IsError() || !isFirmwarePresent()) {
LOG_INFO(Frontend, "Installed firmware: No firmware available");
return Common::Android::ToJString(env, "N/A");
}
@ -804,6 +790,23 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclas
return Common::Android::ToJString(env, display_version);
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyFirmware(JNIEnv* env, jclass clazz) {
return static_cast<int>(FirmwareManager::VerifyFirmware(EmulationSession::GetInstance().System()));
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_gameRequiresFirmware(JNIEnv* env, jclass clazz, jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
return FirmwareManager::GameRequiresFirmware(program_id);
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_installKeys(JNIEnv* env, jclass clazz, jstring jpath, jstring jext) {
const auto path = Common::Android::GetJString(env, jpath);
const auto ext = Common::Android::GetJString(env, jext);
return static_cast<int>(FirmwareManager::InstallKeys(path, ext));
}
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj,
jstring jpath,
jstring jprogramId) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -1,952 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="687.3875"
android:viewportHeight="687.3875"
android:width="2598dp"
android:height="2598dp">
<path
android:pathData="M-12.54741 -9.487146H695.7068V701.107H-12.54741V-9.487146Z"
android:fillColor="#1C1C1C"
android:strokeColor="#1C1C1C"
android:strokeWidth="11.589"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M494.45889 345.0122l-20.55738 30.02458 -8.65574 -119.82784 67.35244 34.35247 -20.82787 30.56554 70.59835 147.959 -17.04096 22.7213z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M532.19248 289.56141l26.91392 -4.32787 -65.99997 -34.89344 -26.77869 3.92213z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M558.56543 285.63928l-19.7459 30.56557 -26.77869 3.9221 20.42213 -30.7008z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M582.63918 468.22118l27.86066 -4.05736 -71.54506 -148.36471 -26.77869 4.4631z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M610.22935 464.70479l-17.04099 24.74999 -26.91392 2.84017 17.31148 -24.209z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M474.98348 375.98351l26.91392 -3.11065 3.51639 -5.40983 -10.41392 -22.04509z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="2.320764"
android:scaleX="0.7541365"
android:scaleY="0.7541365"
android:translateX="-141.3355"
android:translateY="27.85998">
<path
android:pathData="M393.01518 281.73251l-20.55738 30.02458 -8.65574 -119.82784 67.35244 34.35247 -20.82787 30.56554 70.59835 147.959 -17.04096 22.7213z"
android:strokeColor="#232323"
android:strokeWidth="3.87681"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M430.74877 226.28172l26.91392 -4.32787 -65.99997 -34.89344 -26.77869 3.92213z"
android:strokeColor="#232323"
android:strokeWidth="3.87681"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M457.12172 222.35959l-19.7459 30.56557 -26.77869 3.9221 20.42213 -30.7008z"
android:strokeColor="#232323"
android:strokeWidth="3.87681"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M481.19547 404.94149l27.86066 -4.05736 -71.54506 -148.36471 -26.77869 4.4631z"
android:strokeColor="#232323"
android:strokeWidth="3.87681"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M508.78564 401.4251l-17.04099 24.74999 -26.91392 2.84017 17.31148 -24.209z"
android:strokeColor="#232323"
android:strokeWidth="3.87681"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M373.53977 312.70382l26.91392 -3.11065 3.51639 -5.40983 -10.41392 -22.04509z"
android:strokeColor="#232323"
android:strokeWidth="3.87681"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<path
android:pathData="M331.56055 45.999602l27.82927 8.893895 62.44852 -56.4236293 -37.39261 -1.8170322z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M359.61877 54.909822l11.09014 24.614746 91.29096 -82.0942394 -38.68031 -1.6229503z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M369.89743 79.524568L341.69867 71.00408 330.67615 46.051217 359.61877 54.63933Z"
android:strokeColor="#232323"
android:strokeWidth="2.64583"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M635.3851 77.63113A53.01638 53.01638 0 0 1 529.3523 77.63113A53.01638 53.01638 0 0 1 635.3851 77.63113Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M370.3487 589.3373A26.71373 26.71373 0 0 1 316.9212 589.3373A26.71373 26.71373 0 0 1 370.3487 589.3373Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M221.1756 598.8859A62.61387 62.61387 0 0 1 95.94788 598.8859A62.61387 62.61387 0 0 1 221.1756 598.8859Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M439.18345 506.27236l6.64477 47.48313 43.42712 -20.89004 -6.87718 -47.72509z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M250.6585 331.34613l-31.74822 105.78124 89.83779 84.43087 121.44738 -20.93441 32.30276 -105.6426 -90.11504 -85.12406z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M196.88499 433.42193l28.85734 38.86296 -28.78561 38.82713 -28.59435 -38.30115z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M507.61256 173.83179l8.65666 25.9651 -22.30747 15.78891 -8.61435 -25.6169z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M238.54168 139.98243l48.2679 -0.54605 14.49415 45.96882 -47.66037 0.6626z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="-6.069791"
android:scaleX="0.7527306"
android:scaleY="0.7038611"
android:translateX="450.7954"
android:translateY="136.4846">
<group
android:rotation="8.307879">
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-2.088203"
android:translateY="46.2009">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-0.4652534"
android:translateY="1.29927">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-1.006237"
android:translateY="24.02058">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
<group
android:rotation="42.78186"
android:scaleX="1.070914"
android:scaleY="1.042189"
android:translateX="661.8707"
android:translateY="250.1218">
<group
android:rotation="17.87905">
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-2.088203"
android:translateY="46.2009">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-0.4652534"
android:translateY="1.29927">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-1.006237"
android:translateY="24.02058">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
<group
android:rotation="92.90104"
android:scaleX="0.686048"
android:scaleY="0.6572564"
android:translateX="164.3531"
android:translateY="238.4857">
<group
android:rotation="-0.00002171183">
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-2.088203"
android:translateY="46.2009">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-0.4652534"
android:translateY="1.29927">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-1.006237"
android:translateY="24.02058">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
<group
android:rotation="3.075623"
android:scaleX="1.039543"
android:scaleY="0.9959163"
android:translateX="-242.0844"
android:translateY="-115.0889">
<group
android:rotation="-0.000003860364">
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-2.088203"
android:translateY="46.2009">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-0.4652534"
android:translateY="1.29927">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-1.006237"
android:translateY="24.02058">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-2.088203"
android:translateY="46.2009">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-0.4652534"
android:translateY="1.29927">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="1.004303"
android:scaleY="0.9859607"
android:translateX="-1.006237"
android:translateY="24.02058">
<path
android:pathData="M189.07372 56.803262c-24.61475 22.721306 43.27868 105.491778 54.90982 115.229478 11.63114 9.7377 66.54097 64.37703 104.4098 48.68851 37.86886 -15.68852 -54.36883 -119.28685 -47.06557 -111.44259 7.3033 7.84426 -74.38521 -76.008178 -112.25405 -52.475398z"
android:strokeColor="#232323"
android:strokeWidth="4.48315"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<path
android:pathData="M114.027 0.004829188H120.3289V687.4189H114.027V0.004829188Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M222.8384 0.03916146H229.1403V687.4533H222.8384V0.03916146Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M41.36438 -242.1991H46.69247V-99.86517H41.36438V-242.1991Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M127.124 -242.8359H132.452V-100.502H127.124V-242.8359Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M212.4888 -242.8362H217.8169V-100.5023H212.4888V-242.8362Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M298.6423 -242.8366H303.9704V-100.5027H298.6423V-242.8366Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M384.3656 -242.8369H389.6937V-100.5031H384.3656V-242.8369Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M470.2463 -242.8373H475.5743V-100.5034H470.2463V-242.8373Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M556.1945 -242.8377H561.5226V-100.5038H556.1945V-242.8377Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M642.1034 -242.838H647.4315V-100.5042H642.1034V-242.838Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<path
android:pathData="M286.371 -0.4009084H292.6729V687.0132H286.371V-0.4009084Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M395.1824 -0.3665761H401.4843V687.0475H395.1824V-0.3665761Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M40.94651 -414.5431H46.2746V-272.2092H40.94651V-414.5431Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M126.7061 -415.1799H132.0342V-272.846H126.7061V-415.1799Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M212.0709 -415.1802H217.399V-272.8464H212.0709V-415.1802Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M298.2244 -415.1806H303.5525V-272.8467H298.2244V-415.1806Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M383.9477 -415.181H389.2758V-272.8471H383.9477V-415.181Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M469.8284 -415.1813H475.1565V-272.8475H469.8284V-415.1813Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M555.7766 -415.1817H561.1047V-272.8478H555.7766V-415.1817Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M641.6855 -415.182H647.0136V-272.8482H641.6855V-415.182Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:translateX="172.7436"
android:translateY="-1.445976">
<path
android:pathData="M286.371 0.004829188H292.6729V687.4189H286.371V0.004829188Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M395.1824 0.03916146H401.4843V687.4533H395.1824V0.03916146Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M41.35225 -414.5431H46.68034V-272.2092H41.35225V-414.5431Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M127.1118 -415.1799H132.4399V-272.846H127.1118V-415.1799Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M212.4766 -415.1802H217.8047V-272.8464H212.4766V-415.1802Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M298.6302 -415.1806H303.9583V-272.8467H298.6302V-415.1806Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M384.3535 -415.181H389.6815V-272.8471H384.3535V-415.181Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M470.2341 -415.1813H475.5622V-272.8475H470.2341V-415.1813Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M556.1824 -415.1817H561.5105V-272.8478H556.1824V-415.1817Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M642.0913 -415.182H647.4193V-272.8482H642.0913V-415.182Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
<group
android:translateX="345.2804"
android:translateY="-1.445976">
<path
android:pathData="M286.371 0.004829188H292.6729V687.4189H286.371V0.004829188Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M395.1824 0.03916146H401.4843V687.4533H395.1824V0.03916146Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M41.35225 -414.5431H46.68034V-272.2092H41.35225V-414.5431Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M127.1118 -415.1799H132.4399V-272.846H127.1118V-415.1799Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M212.4766 -415.1802H217.8047V-272.8464H212.4766V-415.1802Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M298.6302 -415.1806H303.9583V-272.8467H298.6302V-415.1806Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M384.3535 -415.181H389.6815V-272.8471H384.3535V-415.181Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M470.2341 -415.1813H475.5622V-272.8475H470.2341V-415.1813Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M556.1824 -415.1817H561.5105V-272.8478H556.1824V-415.1817Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M642.0913 -415.182H647.4193V-272.8482H642.0913V-415.182Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
<group
android:translateX="-343.8918"
android:translateY="0.07904825">
<path
android:pathData="M286.371 0.004829188H292.6729V687.4189H286.371V0.004829188Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:pathData="M395.1824 0.03916146H401.4843V687.4533H395.1824V0.03916146Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M41.35225 -414.5431H46.68034V-272.2092H41.35225V-414.5431Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M127.1118 -415.1799H132.4399V-272.846H127.1118V-415.1799Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M212.4766 -415.1802H217.8047V-272.8464H212.4766V-415.1802Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M298.6302 -415.1806H303.9583V-272.8467H298.6302V-415.1806Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M384.3535 -415.181H389.6815V-272.8471H384.3535V-415.181Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M470.2341 -415.1813H475.5622V-272.8475H470.2341V-415.1813Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M556.1824 -415.1817H561.5105V-272.8478H556.1824V-415.1817Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
<group
android:rotation="45.00107"
android:scaleX="1.000033"
android:scaleY="0.9999669">
<group
android:rotation="45.00107">
<path
android:pathData="M642.0913 -415.182H647.4193V-272.8482H642.0913V-415.182Z"
android:fillColor="#232323"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View file

@ -27,6 +27,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/generate"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/edit_text_layout"
app:layout_constraintTop_toBottomOf="@+id/edit_text_layout" />

Some files were not shown because too many files have changed in this diff Show more