mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-30 12:16:18 +00:00
Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e34fa1e868 | |||
| f85dc57d8d | |||
| 722bd07dbf | |||
| 56caa156b6 | |||
| ffc06b999b | |||
| 51833f6b82 | |||
| 643d78b0e3 | |||
| 38fd46eba4 | |||
| 33a0446b53 | |||
| c186cb9fc3 | |||
| 9c6c03acd1 | |||
| f4a0227426 | |||
| e631bae857 | |||
| 6cfa4ddc12 | |||
| d34a536690 | |||
| 8b4d074049 | |||
| bf7046d522 | |||
| 5ea19d0cdb | |||
| b243e2cb75 | |||
| 22f77b1024 | |||
| f8cfa2e4b1 | |||
| 84a21089e5 | |||
| 411ded7dcb | |||
| cda51e6be1 | |||
| c9ed08854a | |||
| 7d5461d73c | |||
| 3c31ce4d2e | |||
| 4ddbfed915 | |||
| 3ce6bc710b | |||
| 7fa966acde | |||
| fcbebef9f7 | |||
| 80b9b30f46 | |||
| 4c2f42f3a0 | |||
| a03160e381 | |||
| 627691d7a2 | |||
| 91c376a45f | |||
| f929f71b3c | |||
| b23fe40585 | |||
| 9627b84d33 | |||
| 12d4276fff | |||
| 30c81da18d | |||
| 076c7dd844 | |||
| 18dc426a8c | |||
| f820bd6ff0 | |||
| 0f030ae48f | |||
| ad8cea3da9 | |||
| ac4e7380b6 | |||
| 3ca742e6b1 | |||
| 088f3339de | |||
| bf2eed5fe2 | |||
| 4946e09eed | |||
| 71ca489704 | |||
| d224edfd16 | |||
| 5202095e1d | |||
| bb84074ecf | |||
| 692ce90e70 | |||
| 9ce4b67ab3 | |||
| e91b7b9ac5 | |||
| 86b1ed4ebd | |||
| bf98f8a96b | |||
| 25ff105c05 | |||
| 93f5af68c9 | |||
| e64b9da3a4 | |||
| ef3faf230f | |||
| f693011515 | |||
| 53583b4cc9 | |||
| 411f97c733 | |||
| b131f7f760 | |||
| 527fa0a083 | |||
| 725be65530 | |||
| 92f1e551b3 | |||
| 8096fd960f | |||
| f785cf3615 | |||
| 861cdbf912 | |||
| 32b066fb76 | |||
| 6957b45a44 | |||
| 9ce7e97db9 | |||
| b8e2616da7 | |||
| e769501611 | |||
| 7a388127bb | |||
| d97157e46b | |||
| ff3cbb7b05 | |||
| 2676a946a4 | |||
| 9e45bc4fb5 | |||
| fb81acab22 | |||
| 8f40bdb99a | |||
| 1de83fad38 | |||
| 47d59cf994 | |||
| a291a95645 | |||
| 99e3c4d2fa | |||
| cbeae28bd1 | |||
| 1019bed75b | |||
| 35b653e5fb | |||
| 0f86d527de | |||
| 4d948ce757 | |||
| 35c47438fb | |||
| e0748f02cd | |||
| cce9c1af6b | |||
| e9efa2c954 | |||
| 96b7e498f5 | |||
| c3707ba54c | |||
| 5eb11d3c7b | |||
| da45ac4f22 | |||
| 2a82754448 | |||
| 5262e18252 | |||
| 938666b672 | |||
| 781d1872f7 | |||
| 8f15dea93e | |||
| d0bfb8ed12 | |||
| 6f160733f5 | |||
| 97657104f7 | |||
| 60488f486e | |||
| 43c7f1c872 | |||
| 44848ea04c | |||
| ca086e59df | |||
| f24c00f3c0 | |||
| 939e79a71c | |||
| 076f42c8a9 | |||
| 264cff37a1 | |||
| 372c96a908 | |||
| 0228ef19df | |||
| c66efe83be |
Executable
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/local/bin/bash -ex
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
[ -z ${OO_PS4_TOOLCHAIN+x} ] && exit
|
||||||
|
|
||||||
|
# cmake
|
||||||
|
[ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake"
|
||||||
|
set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN")
|
||||||
|
set(CMAKE_STAGING_PREFIX "$OO_PS4_TOOLCHAIN")
|
||||||
|
set(CMAKE_SYSTEM_NAME "OpenOrbis")
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "-D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=btver2 -march=btver2 -fPIC -funwind-tables -femulated-tls")
|
||||||
|
set(CMAKE_CXX_FLAGS "-D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=btver2 -march=btver2 -fPIC -funwind-tables -femulated-tls")
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||||
|
set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||||
|
set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER clang)
|
||||||
|
set(CMAKE_CXX_COMPILER clang++)
|
||||||
|
set(CMAKE_LINKER ld.lld)
|
||||||
|
set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
|
||||||
|
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
|
|
||||||
|
# TODO: Why does cmake not set this?
|
||||||
|
set(CMAKE_SIZEOF_VOID_P 8)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
[ -z ${NPROC+x} ] && NPROC=$(nproc || 1)
|
||||||
|
|
||||||
|
# Normally a platform has a package manager
|
||||||
|
# PS4 does not, atleast not in the normal sense
|
||||||
|
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
|
||||||
|
[ -f "build/Makefile" ] || cmake -S . -B build -G "Unix Makefiles" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \
|
||||||
|
-DENABLE_QT_TRANSLATION=OFF \
|
||||||
|
-DENABLE_CUBEB=OFF \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
|
||||||
|
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
||||||
|
-DENABLE_SDL2=ON \
|
||||||
|
-DENABLE_LIBUSB=OFF \
|
||||||
|
-DENABLE_UPDATE_CHECKER=OFF \
|
||||||
|
-DENABLE_QT=OFF \
|
||||||
|
-DENABLE_OPENGL=ON \
|
||||||
|
-DENABLE_WEB_SERVICE=OFF \
|
||||||
|
-DUSE_DISCORD_PRESENCE=OFF \
|
||||||
|
-DCPMUTIL_FORCE_BUNDLED=ON \
|
||||||
|
-DYUZU_USE_EXTERNAL_FFMPEG=ON \
|
||||||
|
-DYUZU_USE_CPM=ON \
|
||||||
|
-DDYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=OFF \
|
||||||
|
-DDYNARMIC_TESTS=ON \
|
||||||
|
-DYUZU_TESTS=ON \
|
||||||
|
-DYUZU_USE_EXTERNAL_SDL2=ON \
|
||||||
|
"${EXTRA_CMAKE_FLAGS[@]}" || exit
|
||||||
|
|
||||||
|
cmake --build build -t yuzu-cmd_pkg -- -j$NPROC
|
||||||
|
#cmake --build build -t dynarmic_tests_pkg -- -j$NPROC
|
||||||
|
#cmake --build build -t testps4_pkg -- -j$NPROC
|
||||||
+2
-3
@@ -19,7 +19,6 @@ log.txt
|
|||||||
# Generated source files
|
# Generated source files
|
||||||
src/common/scm_rev.cpp
|
src/common/scm_rev.cpp
|
||||||
dist/english_plurals/generated_en.ts
|
dist/english_plurals/generated_en.ts
|
||||||
*-toolchain.cmake
|
|
||||||
|
|
||||||
# Project/editor files
|
# Project/editor files
|
||||||
*.swp
|
*.swp
|
||||||
@@ -65,5 +64,5 @@ artifacts
|
|||||||
vulkansdk*.exe
|
vulkansdk*.exe
|
||||||
*.tar.zst
|
*.tar.zst
|
||||||
|
|
||||||
# Build-time generated external sources
|
# PS4 toolchain stuff
|
||||||
externals/generated
|
ps4-toolchain.cmake
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||||
|
index 0129511c..10fc9b04 100644
|
||||||
|
--- a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||||
|
+++ b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||||
|
@@ -15,6 +15,12 @@
|
||||||
|
# pragma once
|
||||||
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||||
|
|
||||||
|
+// hacky fix for ps4
|
||||||
|
+#if defined(__OPENORBIS__)
|
||||||
|
+# define FIONBIO 0
|
||||||
|
+# define FIONREAD 1
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#include <boost/asio/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/unix.c b/unix.c
|
||||||
|
index 6669216..86a2faa 100644
|
||||||
|
--- a/unix.c
|
||||||
|
+++ b/unix.c
|
||||||
|
@@ -53,7 +53,7 @@
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
|
||||||
|
+#if !defined(__OPENORBIS__) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
|
||||||
|
typedef int socklen_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
diff --git a/libavutil/cpu.c b/libavutil/cpu.c
|
||||||
|
index 03e2720..874258f 100644
|
||||||
|
--- a/libavutil/cpu.c
|
||||||
|
+++ b/libavutil/cpu.c
|
||||||
|
@@ -43,8 +43,10 @@
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/types.h>
|
||||||
|
+#ifndef __OPENORBIS__
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
diff --git a/cmake/ConfigureOpenSSL.cmake b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
index 3012e05..2ae23ff 100644
|
||||||
|
--- a/cmake/ConfigureOpenSSL.cmake
|
||||||
|
+++ b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
@@ -108,7 +108,8 @@ function(configure_openssl)
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT "${CONFIGURE_OPTIONS_OLD}" STREQUAL "")
|
||||||
|
- if(CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD)
|
||||||
|
+ # TODO(lizzie): Emscripten has issues with rebuilding due to the wrapper it uses
|
||||||
|
+ if(CMAKE_SYSTEM_NAME MATCHES "Emscripten" OR CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD)
|
||||||
|
message(STATUS "Found previous configure results. Don't perform configuration")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
@@ -134,10 +135,24 @@ function(configure_openssl)
|
||||||
|
set(VERBOSE_OPTION OUTPUT_QUIET)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
+ if (CMAKE_SYSTEM_NAME MATCHES "Emscripten")
|
||||||
|
+ set(EMSCRIPTEN_CMAKE_WRAPPER "emcmake")
|
||||||
|
+ find_program(EMCC emcc REQUIRED)
|
||||||
|
+ set(EMSCRIPTEN_LINKER ${EMCC})
|
||||||
|
+ list(APPEND CONFIGURE_COMMAND wasm64)
|
||||||
|
+ else()
|
||||||
|
+ set(EMSCRIPTEN_CMAKE_WRAPPER "")
|
||||||
|
+ set(EMSCRIPTEN_LINKER ${CMAKE_LINKER})
|
||||||
|
+ endif ()
|
||||||
|
+
|
||||||
|
execute_process(
|
||||||
|
- COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
+ COMMAND ${EMSCRIPTEN_CMAKE_WRAPPER} ${CMAKE_COMMAND} -E env
|
||||||
|
"CFLAGS=${CMAKE_C_FLAGS}"
|
||||||
|
"CXXFLAGS=${CMAKE_CXX_FLAGS}"
|
||||||
|
+ "LDFLAGS=${CMAKE_CXX_LINK_FLAGS}"
|
||||||
|
+ "CC=${CMAKE_C_COMPILER}"
|
||||||
|
+ "CXX=${CMAKE_CXX_COMPILER}"
|
||||||
|
+ "LD=${EMSCRIPTEN_LINKER}"
|
||||||
|
${CONFIGURE_COMMAND}
|
||||||
|
WORKING_DIRECTORY ${CONFIGURE_BUILD_DIR}
|
||||||
|
${VERBOSE_OPTION}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 1ca57e1..593fd62 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -148,6 +148,16 @@ if(NOT BUILD_SHARED_LIBS)
|
||||||
|
list(APPEND OPENSSL_CONFIGURE_OPTIONS no-shared)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
+list(APPEND OPENSSL_CONFIGURE_OPTIONS
|
||||||
|
+ no-threads no-thread-pool no-shared no-afalgeng no-async no-capieng no-cmp no-cms no-comp no-ct
|
||||||
|
+ no-docs no-dgram no-dso no-dynamic-engine no-engine no-filenames no-gost
|
||||||
|
+ no-http no-legacy no-module no-nextprotoneg no-ocsp no-padlockeng no-quic
|
||||||
|
+ no-srp no-srtp no-ssl-trace no-static-engine no-tests no-thread-pool no-ts
|
||||||
|
+ no-ui-console no-uplink no-ssl3-method no-tls1-method no-tls1_1-method
|
||||||
|
+ no-dtls1-method no-dtls1_2-method no-argon2 no-bf no-blake2 no-cast
|
||||||
|
+ no-dsa no-idea no-md4 no-mdc2 no-ocb no-rc2 no-rc4 no-rmd160 no-scrypt
|
||||||
|
+ no-siphash no-siv no-sm2 no-sm3 no-sm4 no-whirlpool no-apps)
|
||||||
|
+
|
||||||
|
list(SORT OPENSSL_CONFIGURE_OPTIONS)
|
||||||
|
list(REMOVE_DUPLICATES OPENSSL_CONFIGURE_OPTIONS)
|
||||||
|
list(PREPEND OPENSSL_CONFIGURE_OPTIONS ${OPENSSL_TARGET_PLATFORM})
|
||||||
|
diff --git a/cmake/ConfigureOpenSSL.cmake b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
index 2ae23ff..22a4a27 100644
|
||||||
|
--- a/cmake/ConfigureOpenSSL.cmake
|
||||||
|
+++ b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
@@ -154,6 +154,7 @@ function(configure_openssl)
|
||||||
|
"CXX=${CMAKE_CXX_COMPILER}"
|
||||||
|
"LD=${EMSCRIPTEN_LINKER}"
|
||||||
|
${CONFIGURE_COMMAND}
|
||||||
|
+ "--prefix=${CMAKE_SYSROOT}"
|
||||||
|
WORKING_DIRECTORY ${CONFIGURE_BUILD_DIR}
|
||||||
|
${VERBOSE_OPTION}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/crypto/o_str.c b/crypto/o_str.c
|
||||||
|
index 8aadff5..ba427c9 100644
|
||||||
|
--- a/crypto/o_str.c
|
||||||
|
+++ b/crypto/o_str.c
|
||||||
|
@@ -385,7 +385,7 @@ int openssl_strerror_r(int errnum, char *buf, size_t buflen)
|
||||||
|
* It can return a pointer to some (immutable) static string in which case
|
||||||
|
* buf is left unused.
|
||||||
|
*/
|
||||||
|
- err = strerror_r(errnum, buf, buflen);
|
||||||
|
+ err = (char *)strerror_r(errnum, buf, buflen);
|
||||||
|
if (err == NULL || buflen == 0)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 8872895..b0eeca8 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -1770,7 +1770,6 @@ elseif(EMSCRIPTEN)
|
||||||
|
|
||||||
|
CheckPTHREAD()
|
||||||
|
CheckLibUnwind()
|
||||||
|
-
|
||||||
|
elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
||||||
|
|
||||||
|
set(SDL_DISABLE_DLOPEN_NOTES TRUE)
|
||||||
|
@@ -3647,10 +3646,30 @@ if(NOT HAVE_CAMERA)
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
+# Always on?
|
||||||
|
+if (OPENORBIS)
|
||||||
|
+ sdl_sources(
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systhread.c"
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysmutex.c" # Can be faked, if necessary
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_syscond.c" # Can be faked, if necessary
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysrwlock.c" # Can be faked, if necessary
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systls.c"
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syssem.c"
|
||||||
|
+ )
|
||||||
|
+ sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c")
|
||||||
|
+ sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c")
|
||||||
|
+ set(HAVE_SDL_THREADS TRUE)
|
||||||
|
+ set(HAVE_SDL_TIMERS TRUE)
|
||||||
|
+ set(HAVE_SDL_TIME TRUE)
|
||||||
|
+ set(SDL_TIME_UNIX 1)
|
||||||
|
+ set(SDL_TIMER_UNIX 1)
|
||||||
|
+ set(SDL_THREAD_PTHREAD 1)
|
||||||
|
+endif ()
|
||||||
|
+
|
||||||
|
# We always need to have threads and timers around
|
||||||
|
if(NOT HAVE_SDL_THREADS)
|
||||||
|
# The Emscripten and N-Gage platform has been carefully vetted to work without threads
|
||||||
|
- if(EMSCRIPTEN OR NGAGE)
|
||||||
|
+ if(EMSCRIPTEN OR NGAGE OR OPENORBIS)
|
||||||
|
set(SDL_THREADS_DISABLED 1)
|
||||||
|
sdl_glob_sources(
|
||||||
|
"${SDL3_SOURCE_DIR}/src/thread/generic/*.c"
|
||||||
|
diff --git a/build-scripts/rename_macros.py b/build-scripts/rename_macros.py
|
||||||
|
index 978120c..b6063dd 100755
|
||||||
|
--- a/build-scripts/rename_macros.py
|
||||||
|
+++ b/build-scripts/rename_macros.py
|
||||||
|
@@ -124,6 +124,7 @@ RENAMED_MACROS = {
|
||||||
|
"__RISCOS__": "SDL_PLATFORM_RISCOS",
|
||||||
|
"__SOLARIS__": "SDL_PLATFORM_SOLARIS",
|
||||||
|
"__PSP__": "SDL_PLATFORM_PSP",
|
||||||
|
+ "__PS4__": "SDL_PLATFORM_PS4",
|
||||||
|
"__PS2__": "SDL_PLATFORM_PS2",
|
||||||
|
"__VITA__": "SDL_PLATFORM_VITA",
|
||||||
|
"__3DS__": "SDL_PLATFORM_3DS",
|
||||||
|
diff --git a/include/SDL3/SDL_platform_defines.h b/include/SDL3/SDL_platform_defines.h
|
||||||
|
index 7963149..6c0dd5d 100644
|
||||||
|
--- a/include/SDL3/SDL_platform_defines.h
|
||||||
|
+++ b/include/SDL3/SDL_platform_defines.h
|
||||||
|
@@ -442,6 +442,16 @@
|
||||||
|
#define SDL_PLATFORM_PSP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#if defined(__PS4__) || defined(__OPENORBIS__)
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * A preprocessor macro that is only defined if compiling for Sony PSP.
|
||||||
|
+ *
|
||||||
|
+ * \since This macro is available since SDL 3.2.0.
|
||||||
|
+ */
|
||||||
|
+#define SDL_PLATFORM_PS4 1
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if defined(__PS2__) || defined(PS2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
diff --git a/src/SDL.c b/src/SDL.c
|
||||||
|
index b1a1a56..0a3fec6 100644
|
||||||
|
--- a/src/SDL.c
|
||||||
|
+++ b/src/SDL.c
|
||||||
|
@@ -714,7 +714,7 @@ void SDL_Quit(void)
|
||||||
|
SDL_DBus_Quit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#if defined(SDL_PLATFORM_UNIX) && !defined(SDL_PLATFORM_ANDROID) && !defined(SDL_PLATFORM_EMSCRIPTEN) && !defined(SDL_PLATFORM_PRIVATE)
|
||||||
|
+#if defined(SDL_PLATFORM_UNIX) && !defined(SDL_PLATFORM_ANDROID) && !defined(SDL_PLATFORM_EMSCRIPTEN) && !defined(SDL_PLATFORM_PRIVATE) && !defined(SDL_PLATFORM_PS4)
|
||||||
|
SDL_Gtk_Quit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -813,6 +813,8 @@ const char *SDL_GetPlatform(void)
|
||||||
|
return "tvOS";
|
||||||
|
#elif defined(SDL_PLATFORM_PS2)
|
||||||
|
return "PlayStation 2";
|
||||||
|
+#elif defined(SDL_PLATFORM_PS4)
|
||||||
|
+ return "PlayStation 4";
|
||||||
|
#elif defined(SDL_PLATFORM_PSP)
|
||||||
|
return "PlayStation Portable";
|
||||||
|
#elif defined(SDL_PLATFORM_VITA)
|
||||||
|
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
|
||||||
|
index c1e4241..65b1e6d 100644
|
||||||
|
--- a/src/audio/SDL_audio.c
|
||||||
|
+++ b/src/audio/SDL_audio.c
|
||||||
|
@@ -80,6 +80,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
|
#ifdef SDL_AUDIO_DRIVER_NGAGE
|
||||||
|
&NGAGEAUDIO_bootstrap,
|
||||||
|
#endif
|
||||||
|
+#ifdef SDL_AUDIO_DRIVER_PS4
|
||||||
|
+ &PS4AUDIO_bootstrap,
|
||||||
|
+#endif
|
||||||
|
#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||||
|
&EMSCRIPTENAUDIO_bootstrap,
|
||||||
|
#endif
|
||||||
|
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
|
||||||
|
index 60c9743..2d12c3a 100644
|
||||||
|
--- a/src/joystick/SDL_joystick.c
|
||||||
|
+++ b/src/joystick/SDL_joystick.c
|
||||||
|
@@ -106,6 +106,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||||
|
#ifdef SDL_JOYSTICK_N3DS
|
||||||
|
&SDL_N3DS_JoystickDriver,
|
||||||
|
#endif
|
||||||
|
+#ifdef SDL_JOYSTICK_PS4
|
||||||
|
+ &SDL_PS4_JoystickDriver,
|
||||||
|
+#endif
|
||||||
|
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
|
||||||
|
&SDL_DUMMY_JoystickDriver
|
||||||
|
#endif
|
||||||
|
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
|
||||||
|
index 47ce42c..42ab9de 100644
|
||||||
|
--- a/src/joystick/SDL_sysjoystick.h
|
||||||
|
+++ b/src/joystick/SDL_sysjoystick.h
|
||||||
|
@@ -253,6 +253,7 @@ extern SDL_JoystickDriver SDL_HAIKU_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
|
||||||
|
+extern SDL_JoystickDriver SDL_PS4_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_WGI_JoystickDriver;
|
||||||
|
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
|
||||||
|
index a1bb44a..51843c4 100644
|
||||||
|
--- a/src/render/SDL_sysrender.h
|
||||||
|
+++ b/src/render/SDL_sysrender.h
|
||||||
|
@@ -381,6 +381,7 @@ extern SDL_RenderDriver NGAGE_RenderDriver;
|
||||||
|
extern SDL_RenderDriver VULKAN_RenderDriver;
|
||||||
|
extern SDL_RenderDriver PS2_RenderDriver;
|
||||||
|
extern SDL_RenderDriver PSP_RenderDriver;
|
||||||
|
+extern SDL_RenderDriver PS4_RenderDriver;
|
||||||
|
extern SDL_RenderDriver SW_RenderDriver;
|
||||||
|
extern SDL_RenderDriver VITA_GXM_RenderDriver;
|
||||||
|
extern SDL_RenderDriver GPU_RenderDriver;
|
||||||
|
diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
|
||||||
|
index 4a870f6..69ca1db 100644
|
||||||
|
--- a/src/stdlib/SDL_string.c
|
||||||
|
+++ b/src/stdlib/SDL_string.c
|
||||||
|
@@ -32,7 +32,9 @@
|
||||||
|
|
||||||
|
#include "SDL_casefolding.h"
|
||||||
|
|
||||||
|
-#if defined(__SIZEOF_WCHAR_T__)
|
||||||
|
+#if defined(SDL_PLATFORM_PS4)
|
||||||
|
+#define SDL_SIZEOF_WCHAR_T 2
|
||||||
|
+#elif defined(__SIZEOF_WCHAR_T__)
|
||||||
|
#define SDL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__
|
||||||
|
#elif defined(SDL_PLATFORM_NGAGE)
|
||||||
|
#define SDL_SIZEOF_WCHAR_T 2
|
||||||
|
@@ -43,7 +45,6 @@
|
||||||
|
#endif
|
||||||
|
SDL_COMPILE_TIME_ASSERT(sizeof_wchar_t, sizeof(wchar_t) == SDL_SIZEOF_WCHAR_T);
|
||||||
|
|
||||||
|
-
|
||||||
|
char *SDL_UCS4ToUTF8(Uint32 codepoint, char *dst)
|
||||||
|
{
|
||||||
|
if (!dst) {
|
||||||
|
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
|
||||||
|
index f650f27..e23424f 100644
|
||||||
|
--- a/src/video/SDL_video.c
|
||||||
|
+++ b/src/video/SDL_video.c
|
||||||
|
@@ -131,6 +131,9 @@ static VideoBootStrap *bootstrap[] = {
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_NGAGE
|
||||||
|
&NGAGE_bootstrap,
|
||||||
|
#endif
|
||||||
|
+#ifdef SDL_VIDEO_DRIVER_PS4
|
||||||
|
+ &PS4_bootstrap,
|
||||||
|
+#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_KMSDRM
|
||||||
|
&KMSDRM_bootstrap,
|
||||||
|
#endif
|
||||||
|
@@ -314,6 +317,7 @@ static bool SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window,
|
||||||
|
SDL_GetWindowSizeInPixels(window, &w, &h);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
+
|
||||||
|
SDL_Renderer *renderer = NULL;
|
||||||
|
const char *render_driver = NULL;
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
diff --git a/source/opt/loop_dependence.cpp b/source/opt/loop_dependence.cpp
|
||||||
|
index e41c044..a51b53b 100644
|
||||||
|
--- a/source/opt/loop_dependence.cpp
|
||||||
|
+++ b/source/opt/loop_dependence.cpp
|
||||||
|
@@ -12,6 +12,12 @@
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
+// PS4: issue?
|
||||||
|
+#ifdef __PS4__
|
||||||
|
+#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||||
|
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#include "source/opt/loop_dependence.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
@@ -19,6 +25,7 @@
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
+#include <cstdlib>
|
||||||
|
|
||||||
|
#include "source/opt/instruction.h"
|
||||||
|
#include "source/opt/scalar_analysis_nodes.h"
|
||||||
@@ -23,6 +23,7 @@ include(UseCcache)
|
|||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(CPMUtil)
|
include(CPMUtil)
|
||||||
|
include(OpenOrbis)
|
||||||
|
|
||||||
if (NOT DEFINED ARCHITECTURE)
|
if (NOT DEFINED ARCHITECTURE)
|
||||||
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
|
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
|
||||||
|
|||||||
@@ -18,10 +18,13 @@ if (DEFINED GIT_RELEASE)
|
|||||||
set(BUILD_VERSION "${GIT_TAG}")
|
set(BUILD_VERSION "${GIT_TAG}")
|
||||||
set(GIT_REFSPEC "${GIT_RELEASE}")
|
set(GIT_REFSPEC "${GIT_RELEASE}")
|
||||||
set(IS_DEV_BUILD false)
|
set(IS_DEV_BUILD false)
|
||||||
else()
|
elseif(DEFINED GIT_COMMIT)
|
||||||
string(SUBSTRING ${GIT_COMMIT} 0 10 BUILD_VERSION)
|
string(SUBSTRING ${GIT_COMMIT} 0 10 BUILD_VERSION)
|
||||||
set(BUILD_VERSION "${BUILD_VERSION}-${GIT_REFSPEC}")
|
set(BUILD_VERSION "${BUILD_VERSION}-${GIT_REFSPEC}")
|
||||||
set(IS_DEV_BUILD true)
|
set(IS_DEV_BUILD true)
|
||||||
|
else()
|
||||||
|
set(BUILD_VERSION "NoGitInfo")
|
||||||
|
set(IS_DEV_BUILD true)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NIGHTLY_BUILD)
|
if (NIGHTLY_BUILD)
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
set(CROSS_TARGET "powerpc64le" CACHE STRING "Cross-compilation target (aarch64, powerpc64le, riscv64, etc)")
|
|
||||||
|
|
||||||
set(CMAKE_SYSROOT /usr/${CROSS_TARGET}-unknown-linux-gnu)
|
|
||||||
|
|
||||||
set(CMAKE_C_COMPILER ${CROSS_TARGET}-unknown-linux-gnu-gcc)
|
|
||||||
set(CMAKE_CXX_COMPILER ${CROSS_TARGET}-unknown-linux-gnu-g++)
|
|
||||||
|
|
||||||
# search programs in the host environment
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
||||||
|
|
||||||
# search headers and libraries in the target environment
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH /usr/${CROSS_TARGET}-unknown-linux-gnu)
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
function(create_ps4_eboot project target content_id)
|
||||||
|
set(sce_sys_dir sce_sys)
|
||||||
|
set(sce_sys_param ${sce_sys_dir}/param.sfo)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${target}.pkg"
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin
|
||||||
|
VERBATIM
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
|
DEPENDS ${project}
|
||||||
|
)
|
||||||
|
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(create_ps4_pkg project target content_id)
|
||||||
|
set(sce_sys_dir sce_sys)
|
||||||
|
set(sce_sys_param ${sce_sys_dir}/param.sfo)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${target}.pkg"
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin
|
||||||
|
COMMAND mkdir -p ${sce_sys_dir}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_new ${sce_sys_param}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_TYPE --type Integer --maxsize 4 --value 1
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_VER --type Utf8 --maxsize 8 --value 1.03
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} ATTRIBUTE --type Integer --maxsize 4 --value 0
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CATEGORY --type Utf8 --maxsize 4 --value gd
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CONTENT_ID --type Utf8 --maxsize 48 --value ${content_id}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} DOWNLOAD_DATA_SIZE --type Integer --maxsize 4 --value 0
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} SYSTEM_VER --type Integer --maxsize 4 --value 0
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE --type Utf8 --maxsize 128 --value ${target}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE_ID --type Utf8 --maxsize 12 --value BREW00090
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} VERSION --type Utf8 --maxsize 8 --value 1.03
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/create-gp4 -out ${target}.gp4 --content-id=${content_id} --files "${target}_eboot.bin ${sce_sys_param} sce_module/libc.prx sce_module/libSceFios2.prx"
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${target}.gp4 .
|
||||||
|
VERBATIM
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
|
DEPENDS ${project}
|
||||||
|
)
|
||||||
|
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
if (NOT DEFINED ENV{OO_PS4_TOOLCHAIN})
|
||||||
|
set(ENV{OO_PS4_TOOLCHAIN} ${CMAKE_SYSROOT})
|
||||||
|
endif ()
|
||||||
+20
-6
@@ -12,7 +12,8 @@
|
|||||||
"min_version": "1.57",
|
"min_version": "1.57",
|
||||||
"package": "Boost",
|
"package": "Boost",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-clang-cl.patch"
|
"0001-clang-cl.patch",
|
||||||
|
"0004-openorbis.patch"
|
||||||
],
|
],
|
||||||
"repo": "boostorg/boost",
|
"repo": "boostorg/boost",
|
||||||
"version": "boost-1.90.0"
|
"version": "boost-1.90.0"
|
||||||
@@ -70,12 +71,18 @@
|
|||||||
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
||||||
"min_version": "1.3",
|
"min_version": "1.3",
|
||||||
"repo": "lsalzman/enet",
|
"repo": "lsalzman/enet",
|
||||||
"version": "v1.3.18"
|
"version": "v1.3.18",
|
||||||
|
"patches": [
|
||||||
|
"0001-openorbis.patch"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
||||||
"repo": "FFmpeg/FFmpeg",
|
"repo": "FFmpeg/FFmpeg",
|
||||||
"version": "c7b5f1537d"
|
"version": "c7b5f1537d",
|
||||||
|
"patches": [
|
||||||
|
"0001-sysctl-openorbis.patch"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"ffmpeg-ci": {
|
"ffmpeg-ci": {
|
||||||
"ci": true,
|
"ci": true,
|
||||||
@@ -183,7 +190,8 @@
|
|||||||
"min_version": "3.0.0",
|
"min_version": "3.0.0",
|
||||||
"package": "OpenSSL",
|
"package": "OpenSSL",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-add-bundled-cert.patch"
|
"0001-add-bundled-cert.patch",
|
||||||
|
"0002-fix-gnu-openorbis.patch"
|
||||||
],
|
],
|
||||||
"repo": "openssl/openssl",
|
"repo": "openssl/openssl",
|
||||||
"version": "openssl-3.6.2"
|
"version": "openssl-3.6.2"
|
||||||
@@ -205,7 +213,9 @@
|
|||||||
"0001-cpmutil-compat.patch",
|
"0001-cpmutil-compat.patch",
|
||||||
"0002-use-ccache.patch",
|
"0002-use-ccache.patch",
|
||||||
"0003-use-cmake-compiler-flags.patch",
|
"0003-use-cmake-compiler-flags.patch",
|
||||||
"0004-use-shell-wrapper.patch"
|
"0004-use-shell-wrapper.patch",
|
||||||
|
"0005-wasm-support.patch",
|
||||||
|
"0006-openorbis-prefix.patch"
|
||||||
],
|
],
|
||||||
"repo": "jimmy-park/openssl-cmake",
|
"repo": "jimmy-park/openssl-cmake",
|
||||||
"version": "3.6.2"
|
"version": "3.6.2"
|
||||||
@@ -243,7 +253,11 @@
|
|||||||
"min_version": "3.2.10",
|
"min_version": "3.2.10",
|
||||||
"package": "SDL3",
|
"package": "SDL3",
|
||||||
"repo": "libsdl-org/SDL",
|
"repo": "libsdl-org/SDL",
|
||||||
"version": "release-3.4.8"
|
"version": "release-3.4.8",
|
||||||
|
"patches": [
|
||||||
|
"0001-ps4.patch",
|
||||||
|
"0002-ps4-drivers.patch"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sdl3-ci": {
|
"sdl3-ci": {
|
||||||
"ci": true,
|
"ci": true,
|
||||||
|
|||||||
Vendored
+223
@@ -0,0 +1,223 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg7"
|
||||||
|
sodipodi:docname="ps4.svg"
|
||||||
|
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||||
|
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs7">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#003e74;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2ea8ff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient1"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#3579ff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0b00ff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch37"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop37" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch28"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#252525;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop28" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch27"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop27" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch15"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop16" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient14"
|
||||||
|
inkscape:swatch="gradient">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop14" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop15" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch9"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch8"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<rect
|
||||||
|
x="22.627417"
|
||||||
|
y="402.76802"
|
||||||
|
width="521.34025"
|
||||||
|
height="248.94868"
|
||||||
|
id="rect24" />
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath18">
|
||||||
|
<circle
|
||||||
|
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
id="circle18"
|
||||||
|
cx="-246.8315"
|
||||||
|
cy="246.8338"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
r="191.89999" />
|
||||||
|
</clipPath>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath22">
|
||||||
|
<circle
|
||||||
|
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
id="circle22"
|
||||||
|
cx="256"
|
||||||
|
cy="256"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
r="191.89999" />
|
||||||
|
</clipPath>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath128">
|
||||||
|
<circle
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#03ffff;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="circle128"
|
||||||
|
cx="256"
|
||||||
|
cy="256"
|
||||||
|
r="192" />
|
||||||
|
</clipPath>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient1"
|
||||||
|
id="linearGradient3"
|
||||||
|
x1="256"
|
||||||
|
y1="64"
|
||||||
|
x2="256"
|
||||||
|
y2="448"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.1874952,0,0,-1.1874952,-47.370662,560.66391)" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5"
|
||||||
|
id="linearGradient4"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(-1.1874952,0,0,1.1874952,560.61528,-47.345282)"
|
||||||
|
x1="256"
|
||||||
|
y1="64"
|
||||||
|
x2="256"
|
||||||
|
y2="448" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="1.4142136"
|
||||||
|
inkscape:cx="262.69017"
|
||||||
|
inkscape:cy="76.367532"
|
||||||
|
inkscape:window-width="1600"
|
||||||
|
inkscape:window-height="849"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg7" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;mix-blend-mode:screen;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:15.907;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path1"
|
||||||
|
cx="256.61652"
|
||||||
|
cy="257.31778"
|
||||||
|
r="227.33479" />
|
||||||
|
<path
|
||||||
|
id="path8-7"
|
||||||
|
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient3);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
d="m 256.62812,484.66422 a 227.99908,228.00372 0 0 1 -94.5288,-20.52182 c 17.54241,-0.96226 34.77843,-4.71825 46.2868,-10.46733 12.69502,-6.3416 25.70492,-17.24174 35.38366,-26.3736 h 36.45053 c 0.93211,0.61234 1.88758,1.23061 2.86668,1.85086 4.89722,14.18571 13.27668,38.80747 17.49933,51.23264 a 227.99908,228.00372 0 0 1 -43.9582,4.27925 z m 55.26491,-6.80041 -16.39068,-41.47736 c 6.99845,3.71973 14.6813,7.07649 22.62503,9.76921 20.75463,7.03513 39.46594,9.14022 49.31353,9.76688 a 227.99908,228.00372 0 0 1 -55.54788,21.94127 z m 58.6952,-23.72487 c -8.69086,-4.31956 -29.66977,-14.9556 -49.97917,-26.83747 h 87.23219 a 227.99908,228.00372 0 0 1 -37.25302,26.83747 z m -241.49988,-8.48659 a 227.99908,228.00372 0 0 1 -23.67337,-18.35088 h 95.80906 c -1.32304,0.72101 -2.11058,1.13186 -2.11058,1.13186 l 9.37935,10.63433 -34.47214,-6.30174 c 0,-2e-5 -10.96427,4.13624 -36.05858,11.02861 -3.09966,0.85131 -6.06162,1.45425 -8.87374,1.85782 z M 96.054184,418.52496 A 227.99908,228.00372 0 0 1 64.743277,379.80069 h 53.833883 c 16.2593,10.82121 36.03109,20.56336 55.93056,22.04797 47.50893,3.54468 62.979,-1.67459 62.979,-1.67459 0,0 -4.13964,4.3321 -13.0323,12.01204 -2.4447,2.11135 -5.46123,4.28998 -8.54904,6.33885 z m 156.603246,0 c 4.10483,-4.24043 6.54978,-7.04162 6.54978,-7.04162 0,0 3.17296,2.8621 8.63949,7.04162 z m 54.10293,0 c -19.35695,-13.88741 -22.86161,-25.14433 -22.86161,-25.14433 0,0 49.2172,17.2685 90.39112,0.28064 10.4477,-4.31055 19.37408,-9.1049 26.88099,-13.86058 h 47.3421 a 227.99908,228.00372 0 0 1 -31.31091,38.72427 z M 59.385631,371.02418 A 227.99908,228.00372 0 0 1 41.543041,332.29992 H 159.20017 c 1.30773,2.3199 2.75142,4.57103 4.34409,6.73083 12.77878,17.32895 25.06121,26.96783 33.0852,31.99343 h -27.15468 c -5.2719,-0.84 -10.81534,-1.78919 -16.40924,-2.84819 -27.04349,-5.11994 -72.845405,-20.48007 -72.845405,-20.48007 0,0 10.296355,11.13669 26.131855,23.32826 z m 238.424449,0 c 30.05703,-10.10404 47.05829,-24.07021 56.34572,-38.72426 h 117.55739 a 227.99908,228.00372 0 0 1 -17.84258,38.72426 h -40.22176 c 13.33114,-10.41219 19.38725,-18.85882 19.38725,-18.85882 0,0 -30.08919,11.11726 -59.29823,18.85882 z m -41.2585,-14.62133 c -0.90134,-0.01 -9.08983,-0.64727 -40.38179,-18.55498 -2.80164,-1.60327 -5.61377,-3.47048 -8.41452,-5.54795 h 37.53597 c 6.43727,15.58979 11.34615,24.10293 11.34615,24.10293 0,0 -0.0258,6.4e-4 -0.0858,0 z m 12.72847,-0.0418 c 0,0 -2.97304,-8.3824 -6.55675,-24.06118 h 46.48163 c -24.16151,23.08045 -39.92488,24.06123 -39.92488,24.06123 z M 38.653164,323.52341 a 227.99908,228.00372 0 0 1 -8.28,-38.72426 H 147.25331 c 0.50409,11.4347 2.40394,25.61361 7.73264,38.72426 z m 158.567726,0 c -12.80955,-11.77756 -24.77977,-26.58932 -33.71374,-38.72426 h 65.85729 c 4.01234,15.08912 8.39298,28.09557 12.44549,38.72426 z m 63.60057,0 c -2.16662,-10.57203 -4.40101,-23.55135 -6.23667,-38.72426 h 95.8253 c -7.46906,9.7857 -18.55287,23.51811 -32.62829,38.72426 z m 97.99155,0 c 5.95644,-13.69644 6.2152,-27.44278 5.00743,-38.72426 h 119.06262 a 227.99908,228.00372 0 0 1 -8.28,38.72426 z M 29.452392,276.02264 A 227.99908,228.00372 0 0 1 28.62903,256.6605 227.99908,228.00372 0 0 1 29.452392,237.29836 H 219.64878 c 2.02639,13.95226 4.61647,26.90106 7.48446,38.72428 H 157.2241 c -5.80191,-8.33616 -9.27267,-13.98815 -9.27267,-13.98815 0,0 -0.7416,5.5263 -0.8396,13.98815 z m 224.144368,0 c -1.22897,-11.76966 -2.19512,-24.70616 -2.7113,-38.72428 h 232.91837 a 227.99908,228.00372 0 0 1 0.82337,19.36214 227.99908,228.00372 0 0 1 -0.82337,19.36214 H 362.56568 c -0.39943,-2.2888 -0.8157,-4.40137 -1.19214,-6.30638 0,0 -1.52342,2.281 -4.43454,6.30638 z M 30.373164,228.52186 a 227.99908,228.00372 0 0 1 8.28,-38.72427 H 218.96921 c -1.16001,13.8461 -1.41371,26.99937 -0.37573,38.72427 z m 220.252536,0 c -0.27246,-12.17105 -0.19776,-25.09608 0.33166,-38.72427 h 223.6457 a 227.99908,228.00372 0 0 1 8.28,38.72427 z M 41.540725,181.02109 a 227.99908,228.00372 0 0 1 17.84259,-38.72427 H 225.63264 c -2.42151,12.98777 -4.45297,26.07281 -5.81919,38.72427 z m 209.892105,0 c 1.03997,-13.90922 3.42234,-26.81596 6.74692,-38.72427 h 195.69317 a 227.99908,228.00372 0 0 1 17.84258,38.72427 z M 64.740961,133.52032 A 227.99908,228.00372 0 0 1 96.051856,94.796041 H 236.06961 c -3.05987,12.287259 -6.07477,25.390049 -8.74155,38.724279 z m 196.112969,0 c 4.80192,-14.52175 10.96848,-27.42708 17.67095,-38.724279 h 138.6795 a 227.99908,228.00372 0 0 1 31.3109,38.724279 z M 105.41267,86.019537 A 227.99908,228.00372 0 0 1 254.61726,28.666053 c -3.30134,10.858112 -9.7429,31.901037 -16.31878,57.353484 z m 178.62756,0 C 299.82749,62.260898 317.24402,46.83239 326.52798,39.636692 a 227.99908,228.00372 0 0 1 81.31559,46.382845 z"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<path
|
||||||
|
id="path8-7-2"
|
||||||
|
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient4);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
d="m 256.61651,28.654412 a 227.99908,228.00372 0 0 1 94.5288,20.521817 C 333.6029,50.138492 316.36688,53.89448 304.85851,59.64356 292.1635,65.985164 279.15359,76.8853 269.47486,86.017162 h -36.45054 c -0.93211,-0.612343 -1.88758,-1.230613 -2.86668,-1.850865 -4.89722,-14.18571 -13.27667,-38.807461 -17.49932,-51.232639 a 227.99908,228.00372 0 0 1 43.95819,-4.279246 z m -55.26491,6.800405 16.39068,41.477366 c -6.99844,-3.719734 -14.6813,-7.076497 -22.62503,-9.769213 -20.75463,-7.035126 -39.46594,-9.140222 -49.31352,-9.766875 A 227.99908,228.00372 0 0 1 201.3516,35.454817 Z m -58.6952,23.724872 c 8.69086,4.319561 29.66977,14.955598 49.97917,26.837473 H 105.40338 A 227.99908,228.00372 0 0 1 142.6564,59.179689 Z m 241.49988,8.486589 a 227.99908,228.00372 0 0 1 23.67337,18.350884 h -95.80906 c 1.32305,-0.721011 2.11058,-1.131861 2.11058,-1.131861 l -9.37935,-10.634328 34.47215,6.30174 c 0,1.2e-5 10.96426,-4.136248 36.05857,-11.028611 3.09966,-0.851315 6.06162,-1.454254 8.87374,-1.857824 z m 33.03417,27.127388 a 227.99908,228.00372 0 0 1 31.31091,38.724274 h -53.83388 c -16.25931,-10.82121 -36.0311,-20.56336 -55.93057,-22.04797 -47.50892,-3.54468 -62.97899,1.67459 -62.97899,1.67459 0,0 4.13963,-4.3321 13.03229,-12.01204 2.4447,-2.111347 5.46123,-4.289985 8.54904,-6.338854 z m -156.60325,0 c -4.10482,4.240439 -6.54978,7.041624 -6.54978,7.041624 0,0 -3.17295,-2.862104 -8.63949,-7.041624 z m -54.10293,0 c 19.35695,13.887414 22.86161,25.144334 22.86161,25.144334 0,0 -49.2172,-17.2685 -90.39112,-0.28064 -10.4477,4.31055 -19.37408,9.1049 -26.88099,13.86058 H 64.73166 A 227.99908,228.00372 0 0 1 96.042582,94.793666 Z m 247.37474,47.500784 a 227.99908,228.00372 0 0 1 17.84257,38.72426 H 354.04446 c -1.30773,-2.3199 -2.75142,-4.57103 -4.34409,-6.73083 -12.77878,-17.32895 -25.06121,-26.96783 -33.0852,-31.99343 h 27.15468 c 5.2719,0.84 10.81534,1.78919 16.40924,2.84819 27.04349,5.11994 72.84541,20.48007 72.84541,20.48007 0,0 -10.29636,-11.13669 -26.13186,-23.32826 z m -238.42446,0 c -30.05702,10.10404 -47.05829,24.07021 -56.34572,38.72426 H 41.531435 a 227.99908,228.00372 0 0 1 17.842579,-38.72426 h 40.221767 c -13.331141,10.41219 -19.387248,18.85882 -19.387248,18.85882 0,0 30.089197,-11.11726 59.298227,-18.85882 z m 41.2585,14.62133 c 0.90134,0.009 9.08984,0.64727 40.38179,18.55498 2.80164,1.60327 5.61377,3.47048 8.41452,5.54795 h -37.53597 c -6.43727,-15.58979 -11.34615,-24.10293 -11.34615,-24.10293 0,0 0.0258,-6.4e-4 0.0859,0 z m -12.72847,0.0418 c 0,0 2.97304,8.3824 6.55675,24.06118 H 204.0397 c 24.16152,-23.08045 39.92488,-24.06123 39.92488,-24.06123 z m 230.62688,32.83764 a 227.99908,228.00372 0 0 1 8.28,38.72426 H 365.99132 c -0.50409,-11.4347 -2.40394,-25.61361 -7.73264,-38.72426 z m -158.56772,0 c 12.80955,11.77756 24.77977,26.58932 33.71374,38.72426 h -65.85729 c -4.01234,-15.08912 -8.39298,-28.09557 -12.44549,-38.72426 z m -63.60057,0 c 2.16662,10.57203 4.40101,23.55135 6.23667,38.72426 h -95.8253 c 7.46906,-9.7857 18.55287,-23.51811 32.62829,-38.72426 z m -97.99154,0 c -5.95644,13.69644 -6.21521,27.44278 -5.00743,38.72426 H 30.361558 a 227.99908,228.00372 0 0 1 8.280001,-38.72426 z m 329.3606,47.50077 a 227.99908,228.00372 0 0 1 0.82336,19.36214 227.99908,228.00372 0 0 1 -0.82336,19.36214 H 293.59585 c -2.02639,-13.95226 -4.61647,-26.90106 -7.48446,-38.72428 h 69.90914 c 5.80191,8.33616 9.27267,13.98815 9.27267,13.98815 0,0 0.74161,-5.5263 0.8396,-13.98815 z m -224.14436,0 c 1.22897,11.76966 2.19512,24.70616 2.7113,38.72428 H 29.440786 a 227.99908,228.00372 0 0 1 -0.823361,-19.36214 227.99908,228.00372 0 0 1 0.823361,-19.36214 H 150.67895 c 0.39943,2.2888 0.8157,4.40137 1.19214,6.30638 0,0 1.52343,-2.281 4.43455,-6.30638 z m 223.22359,47.50078 a 227.99908,228.00372 0 0 1 -8.28,38.72427 H 294.27542 c 1.16002,-13.8461 1.41371,-26.99937 0.37574,-38.72427 z m -220.25252,0 c 0.27245,12.17105 0.19775,25.09608 -0.33167,38.72427 H 38.641559 a 227.99908,228.00372 0 0 1 -8.280001,-38.72427 z m 209.08496,47.50077 a 227.99908,228.00372 0 0 1 -17.84258,38.72427 H 287.61199 c 2.42151,-12.98777 4.45297,-26.07281 5.81919,-38.72427 z m -209.89209,0 c -1.03998,13.90921 -3.42235,26.81596 -6.74692,38.72427 H 59.371698 A 227.99908,228.00372 0 0 1 41.52912,332.29754 Z m 186.69187,47.50077 a 227.99908,228.00372 0 0 1 -31.3109,38.72428 H 277.17503 c 3.05986,-12.28726 6.07476,-25.39005 8.74154,-38.72428 z m -196.11297,0 c -4.80193,14.52175 -10.96849,27.42708 -17.67095,38.72428 H 96.040255 A 227.99908,228.00372 0 0 1 64.729344,379.79831 Z m 155.44125,47.50078 a 227.99908,228.00372 0 0 1 -149.20459,57.35348 c 3.30135,-10.85811 9.7429,-31.90104 16.31879,-57.35348 z m -178.62756,0 c -15.78726,23.75863 -33.20379,39.18714 -42.48775,46.38284 a 227.99908,228.00372 0 0 1 -81.31558,-46.38284 z"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path192"
|
||||||
|
cx="88.20919"
|
||||||
|
cy="216.80666"
|
||||||
|
rx="43.306744"
|
||||||
|
ry="42.75507" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 211.35225,346.71976 151.38374,303.96994 137.1338,384.12586 Z"
|
||||||
|
id="path195" />
|
||||||
|
<path
|
||||||
|
id="path196-7"
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 309.50171,362.30735 86.0678,57.93833 m -75.48269,11.93227 57.93833,-86.0678" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:13.9781;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect197"
|
||||||
|
width="66.112526"
|
||||||
|
height="59.501274"
|
||||||
|
x="93.831078"
|
||||||
|
y="-503.61469"
|
||||||
|
transform="rotate(108)" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 16 KiB |
@@ -12,6 +12,7 @@
|
|||||||
- [NetBSD](#netbsd)
|
- [NetBSD](#netbsd)
|
||||||
- [MSYS2](#msys2)
|
- [MSYS2](#msys2)
|
||||||
- [RedoxOS](#redoxos)
|
- [RedoxOS](#redoxos)
|
||||||
|
- [PlayStation 4](#playstation-4)
|
||||||
<!-- /TOC -->
|
<!-- /TOC -->
|
||||||
|
|
||||||
## Arch Linux
|
## Arch Linux
|
||||||
@@ -242,3 +243,14 @@ find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
|
|||||||
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
||||||
|
|
||||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||||
|
|
||||||
|
## PlayStation 4
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis/PS4Toolchain/prefix"
|
||||||
|
export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp $OO_PS4_TOOLCHAIN/include/endian.h $OO_PS4_TOOLCHAIN/include/sys/endian.h
|
||||||
|
```
|
||||||
|
|||||||
+1
-137
@@ -2,122 +2,7 @@
|
|||||||
|
|
||||||
General guide for cross compiling.
|
General guide for cross compiling.
|
||||||
|
|
||||||
## Gentoo
|
## Debian ARM64
|
||||||
|
|
||||||
Gentoo's cross-compilation setup is relatively easy, provided you're already familiar with portage.
|
|
||||||
|
|
||||||
### Crossdev
|
|
||||||
|
|
||||||
First, emerge crossdev via `sudo emerge -a sys-devel/crossdev`.
|
|
||||||
|
|
||||||
Now, set up the environment depending on the target architecture; e.g.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo crossdev powerpc64le
|
|
||||||
sudo crossdev aarch64
|
|
||||||
```
|
|
||||||
|
|
||||||
### QEMU
|
|
||||||
|
|
||||||
Installing a qemu user setup is recommended for testing. To do so, you will need the relevant USE flags:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
app-emulation/qemu static-user qemu_user_targets_ppc64le qemu_user_targets_aarch64
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that to use cross-emerged libraries, you will need to tell qemu where the sysroot is. You can do this with an alias:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
alias qemu-ppc64le="qemu-ppc64le -L /usr/powerpc64le-unknown-linux-gnu"
|
|
||||||
alias qemu-aarch64="qemu-aarch64 -L /usr/aarch64-unknown-linux-gnu"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
Some packages have broken USE flags on other architectures; you'll also need to set up python targets. In `/usr/<target>-unknown-linux-gnu/etc/portage/package.use`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
>=net-misc/curl-8.16.0-r1 ssl
|
|
||||||
|
|
||||||
*/* PYTHON_TARGETS: python3_13 PYTHON_SINGLE_TARGET: python3_13
|
|
||||||
*/* pam
|
|
||||||
|
|
||||||
sys-apps/util-linux pam su
|
|
||||||
app-shells/bash -readline
|
|
||||||
>=dev-libs/libpcre2-10.47 unicode
|
|
||||||
>=x11-libs/libxkbcommon-1.12.3 X
|
|
||||||
>=sys-libs/zlib-1.3.1-r1 minizip
|
|
||||||
>=app-alternatives/gpg-1-r3 ssl
|
|
||||||
>=app-crypt/gnupg-2.5.13-r2 ssl
|
|
||||||
|
|
||||||
dev-libs/* -introspection
|
|
||||||
media-libs/harfbuzz -introspection
|
|
||||||
dev-libs/quazip -qt5 qt6
|
|
||||||
```
|
|
||||||
|
|
||||||
Dependencies should be about the same [as normal Gentoo](./Deps.md), but removing gamemode and renderdoc is recommended. Keep in mind that when emerging, you want to use `emerge-<target>-unknown-linux-gnu`, e.g. `emerge-powerpc64le-unknown-linux-gnu`.
|
|
||||||
|
|
||||||
Enable GURU in the cross environment (as root):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
mkdir -p /usr/powerpc64le-unknown-linux-gnu/etc/portage/repos.conf
|
|
||||||
cat << EOF > /usr/powerpc64le-unknown-linux-gnu/etc/portage/repos.conf/guru.conf
|
|
||||||
[guru]
|
|
||||||
location = /var/db/repos/guru
|
|
||||||
auto-sync = no
|
|
||||||
priority = 1
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Now emerge your dependencies:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo emerge-powerpc64le-unknown-linux-gnu -aU app-arch/lz4 app-arch/zstd app-arch/unzip \
|
|
||||||
dev-libs/libfmt dev-libs/libusb dev-libs/mcl dev-libs/sirit dev-libs/oaknut \
|
|
||||||
dev-libs/unordered_dense dev-libs/boost dev-libs/openssl dev-libs/discord-rpc \
|
|
||||||
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
|
|
||||||
dev-util/vulkan-utility-libraries dev-util/glslang \
|
|
||||||
media-libs/libva media-libs/opus media-video/ffmpeg \
|
|
||||||
media-libs/VulkanMemoryAllocator media-libs/libsdl2 media-libs/cubeb \
|
|
||||||
net-libs/enet net-libs/mbedtls \
|
|
||||||
sys-libs/zlib \
|
|
||||||
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt dev-cpp/catch \
|
|
||||||
net-wireless/wireless-tools \
|
|
||||||
dev-qt/qtbase:6 dev-libs/quazip \
|
|
||||||
virtual/pkgconfig
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building
|
|
||||||
|
|
||||||
A toolchain is provided in `CMakeModules/GentooCross.cmake`. To use it:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake -S . -B build/ppc64 -DCMAKE_TOOLCHAIN_FILE=CMakeModules/GentooCross.cmake -G Ninja -DCROSS_TARGET=powerpc64le -DENABLE_OPENGL=OFF
|
|
||||||
```
|
|
||||||
|
|
||||||
Now build as normal:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake --build build/ppc64 -j$(nproc)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alternatively
|
|
||||||
|
|
||||||
Only emerge the absolute necessities:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo emerge-powerpc64le-unknown-linux-gnu -aU media-video/ffmpeg media-libs/libsdl2 dev-qt/qtbase:6
|
|
||||||
```
|
|
||||||
|
|
||||||
Then set `YUZU_USE_CPM=ON`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake -S . -B build/ppc64 -DCMAKE_TOOLCHAIN_FILE=CMakeModules/GentooCross.cmake -G Ninja -DCROSS_TARGET=powerpc64le -DENABLE_OPENGL=OFF -DYUZU_USE_CPM=ON
|
|
||||||
```
|
|
||||||
|
|
||||||
## ARM64
|
|
||||||
|
|
||||||
### Debian ARM64
|
|
||||||
|
|
||||||
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
||||||
|
|
||||||
@@ -203,24 +88,3 @@ And finally, run the compiled executable with QEMU!
|
|||||||
```sh
|
```sh
|
||||||
qemu-aarch64 build/aarch64/bin/eden
|
qemu-aarch64 build/aarch64/bin/eden
|
||||||
```
|
```
|
||||||
|
|
||||||
## PowerPC
|
|
||||||
|
|
||||||
This is a guide for FreeBSD users mainly.
|
|
||||||
|
|
||||||
Now you got a PowerPC sysroot - quickly decompress it somewhere, say `/home/user/opt/powerpc64le`. Create a toolchain file, for example `powerpc64le-toolchain.cmake`; always [consult the manual](https://man.freebsd.org/cgi/man.cgi?query=cmake-toolchains&sektion=7&manpath=FreeBSD+13.2-RELEASE+and+Ports).
|
|
||||||
|
|
||||||
There is a script to automatically do all of this under `./tools/setup-cross-sysroot.sh`.
|
|
||||||
|
|
||||||
Remember to add `-mabi=elfv1` to `CFLAGS`/`CXXFLAGS` otherwise the program will crash.
|
|
||||||
|
|
||||||
Specify:
|
|
||||||
|
|
||||||
- `YUZU_USE_CPM`: Set this to `ON` so packages can be found and built if your sysroot doesn't have them.
|
|
||||||
- `YUZU_USE_EXTERNAL_FFMPEG`: Set this to `ON` as well.
|
|
||||||
|
|
||||||
Then run using a program such as QEMU to emulate userland syscalls:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cmake --build build-ppc64-pc-freebsd -t dynarmic_tests -- -j8 && qemu-ppc64-static -L $HOME/opt/ppc64-freebsd/sysroot ./build-ppc64-pc-freebsd/bin/dynarmic_tests
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# PowerPC 64 backend
|
|
||||||
|
|
||||||
The ppc64 backend currently only supports the little endian variant, with big endian support being experimental for the time being. Additionally only A32 is supported (for now).
|
|
||||||
|
|
||||||
- Flag handling: Flags are emulated via software, while there may be some funny tricks with the CTR, I'd rather not bother - plus it's widely known that those instructions are not nice on real metal - so I would rather take the i-cache cost.
|
|
||||||
- 128-bit atomics: No 128-bit atomic support is provided, this may cause wrong or erroneous execution in some contexts.
|
|
||||||
|
|
||||||
To handle endianess differences all 16/32/64-bit loads and stores to the "emulated memory" are byteswapped beforehand.
|
|
||||||
@@ -7,12 +7,11 @@ A dynamic recompiler for ARM.
|
|||||||
|
|
||||||
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
|
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
|
||||||
|
|
||||||
The only supported host architectures are x86-64, PowerPC 64, and AArch64. There are no plans to support any 32-bit architectures.
|
The only supported host architectures are x86-64, and AArch64. There are no plans to support any 32-bit architectures.
|
||||||
|
|
||||||
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
|
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
|
||||||
|
|
||||||
Design documentation can be found at [./Design.md](./Design.md).
|
Design documentation can be found at [./Design.md](./Design.md).
|
||||||
PowerPC design documentation can be found at [./PowerPC](./PowerPC.md).
|
|
||||||
|
|
||||||
Alternatives to Dynarmic
|
Alternatives to Dynarmic
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ Eden will store configuration files in the following directories:
|
|||||||
- **Android**: Data is stored internally.
|
- **Android**: Data is stored internally.
|
||||||
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
|
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
|
||||||
- **HaikuOS**: `/boot/home/config/settings/eden`
|
- **HaikuOS**: `/boot/home/config/settings/eden`
|
||||||
|
- **PlayStation 4**: `/data/eden`
|
||||||
|
|
||||||
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use the `user` directory instead.
|
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use the `user` directory instead.
|
||||||
|
|
||||||
|
|||||||
Vendored
+5
-5
@@ -249,17 +249,17 @@ endif()
|
|||||||
# TZDB (Time Zone Database)
|
# TZDB (Time Zone Database)
|
||||||
add_subdirectory(nx_tzdb)
|
add_subdirectory(nx_tzdb)
|
||||||
|
|
||||||
# PowerPC emitter
|
|
||||||
if (ARCHITECTURE_powerpc64)
|
|
||||||
add_subdirectory(powah)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(tz tz/tz/tz.cpp)
|
add_library(tz tz/tz/tz.cpp)
|
||||||
target_include_directories(tz PUBLIC ./tz)
|
target_include_directories(tz PUBLIC ./tz)
|
||||||
|
|
||||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||||
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
|
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
|
||||||
|
|
||||||
|
if (OPENORBIS)
|
||||||
|
add_library(ps4sup ps4sup/emutls.c ps4sup/stub.cpp)
|
||||||
|
target_include_directories(ps4sup PUBLIC ./ps4sup)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT TARGET RenderDoc::API)
|
if (NOT TARGET RenderDoc::API)
|
||||||
add_library(renderdoc INTERFACE)
|
add_library(renderdoc INTERFACE)
|
||||||
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
||||||
|
|||||||
+2
-2
@@ -166,7 +166,7 @@ detect_architecture_symbols(
|
|||||||
"_M_MRX000")
|
"_M_MRX000")
|
||||||
|
|
||||||
detect_architecture_symbols(
|
detect_architecture_symbols(
|
||||||
ARCH powerpc64
|
ARCH ppc64
|
||||||
SYMBOLS
|
SYMBOLS
|
||||||
"__ppc64__"
|
"__ppc64__"
|
||||||
"__powerpc64__"
|
"__powerpc64__"
|
||||||
@@ -174,7 +174,7 @@ detect_architecture_symbols(
|
|||||||
"_M_PPC64")
|
"_M_PPC64")
|
||||||
|
|
||||||
detect_architecture_symbols(
|
detect_architecture_symbols(
|
||||||
ARCH powerpc
|
ARCH ppc
|
||||||
SYMBOLS
|
SYMBOLS
|
||||||
"__ppc__"
|
"__ppc__"
|
||||||
"__ppc"
|
"__ppc"
|
||||||
|
|||||||
Vendored
-10
@@ -1,10 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
add_library(powah INTERFACE)
|
|
||||||
target_include_directories(powah INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
target_compile_options(powah INTERFACE -Wno-unused-parameter)
|
|
||||||
|
|
||||||
add_executable(powah_tests tests.cpp)
|
|
||||||
create_target_directory_groups(powah_tests)
|
|
||||||
target_link_libraries(powah_tests PRIVATE Catch2::Catch2WithMain)
|
|
||||||
Vendored
-145
@@ -1,145 +0,0 @@
|
|||||||
vabsdub,VX,04,1027
|
|
||||||
vabsduh,VX,04,1091
|
|
||||||
vabsduw,VX,04,1155
|
|
||||||
vaddcuw,VX,04,384
|
|
||||||
vaddfp,VX,04,10
|
|
||||||
vaddsbs,VX,04,768
|
|
||||||
vaddshs,VX,04,832
|
|
||||||
vaddsws,VX,04,896
|
|
||||||
vaddubm,VX,04,0
|
|
||||||
vaddubs,VX,04,512
|
|
||||||
vadduhm,VX,04,64
|
|
||||||
vadduhs,VX,04,576
|
|
||||||
vadduwm,VX,04,128
|
|
||||||
vadduws,VX,04,640
|
|
||||||
vand,VX,04,1028
|
|
||||||
vandc,VX,04,1092
|
|
||||||
vavgsb,VX,04,1282
|
|
||||||
vavgsh,VX,04,1346
|
|
||||||
vavgsw,VX,04,1410
|
|
||||||
vavgub,VX,04,1026
|
|
||||||
vavguh,VX,04,1090
|
|
||||||
vavguw,VX,04,1154
|
|
||||||
vcfsx,VDU,04842
|
|
||||||
vcfux,VDU,04778
|
|
||||||
vcmpbfp,VXR,04,966
|
|
||||||
vcmpeqfp,VXR,04,198
|
|
||||||
vcmpequb,VXR,04,6
|
|
||||||
vcmpequh,VXR,04,70
|
|
||||||
vcmpequw,VXR,04,134
|
|
||||||
vcmpgefp,VXR,04,454
|
|
||||||
vcmpgtfp,VXR,04,710
|
|
||||||
vcmpgtsb,VXR,04,774
|
|
||||||
vcmpgtsh,VXR,04,838
|
|
||||||
vcmpgtsw,VXR,04,902
|
|
||||||
vcmpgtub,VXR,04,518
|
|
||||||
vcmpgtuh,VXR,04,582
|
|
||||||
vcmpgtuw,VXR,04,646
|
|
||||||
vctsxs,VDU,04970
|
|
||||||
vctuxs,VDU,04906
|
|
||||||
vexptefp,VY,04,394
|
|
||||||
vlogefp,VY,04,458
|
|
||||||
vmaddfp,VXC,46
|
|
||||||
vmaxfp,VX,04,1034
|
|
||||||
vmaxsb,VX,04,258
|
|
||||||
vmaxsh,VX,04,322
|
|
||||||
vmaxsw,VX,04,386
|
|
||||||
vmaxub,VX,04,2
|
|
||||||
vmaxuh,VX,04,66
|
|
||||||
vmaxuw,VX,04,130
|
|
||||||
vmhaddshs,VXC,32
|
|
||||||
vmhraddshs,VXC,33
|
|
||||||
vminfp,VX,04,1098
|
|
||||||
vminsb,VX,04,770
|
|
||||||
vminsh,VX,04,834
|
|
||||||
vminsw,VX,04,898
|
|
||||||
vminub,VX,04,514
|
|
||||||
vminuh,VX,04,578
|
|
||||||
vminuw,VX,04,642
|
|
||||||
vmladduhm,VXC,34
|
|
||||||
vmrghb,VX,04,12
|
|
||||||
vmrghh,VX,04,76
|
|
||||||
vmrghw,VX,04,140
|
|
||||||
vmrglb,VX,04,268
|
|
||||||
vmrglh,VX,04,332
|
|
||||||
vmrglw,VX,04,396
|
|
||||||
vmsummbm,VXC,37
|
|
||||||
vmsumshm,VXC,40
|
|
||||||
vmsumshs,VXC,41
|
|
||||||
vmsumubm,VXC,36
|
|
||||||
vmsumuhm,VXC,38
|
|
||||||
vmsumuhs,VXC,39
|
|
||||||
vmulesb,VX,04,776
|
|
||||||
vmulesh,VX,04,840
|
|
||||||
vmuleub,VX,04,520
|
|
||||||
vmuleuh,VX,04,584
|
|
||||||
vmulosb,VX,04,264
|
|
||||||
vmulosh,VX,04,328
|
|
||||||
vmuloub,VX,04,8
|
|
||||||
vmulouh,VX,04,72
|
|
||||||
vnmsubfp,VXC,47
|
|
||||||
vnor,VX,04,1284
|
|
||||||
vor,VX,04,1156
|
|
||||||
vperm,VXC,43
|
|
||||||
vpkpx,VX,04,782
|
|
||||||
vpkshss,VX,04,398
|
|
||||||
vpkshus,VX,04,270
|
|
||||||
vpkswss,VX,04,462
|
|
||||||
vpkswus,VX,04,334
|
|
||||||
vpkuhum,VX,04,14
|
|
||||||
vpkuhus,VX,04,142
|
|
||||||
vpkuwum,VX,04,78
|
|
||||||
vpkuwus,VX,04,206
|
|
||||||
vrefp,VY,04,266
|
|
||||||
vrfim,VY,04,714
|
|
||||||
vrfin,VY,04,522
|
|
||||||
vrfip,VY,04,650
|
|
||||||
vrfiz,VY,04,586
|
|
||||||
vrlb,VX,04,4
|
|
||||||
vrlh,VX,04,68
|
|
||||||
vrlw,VX,04,132
|
|
||||||
vrsqrtefp,VY,04,330
|
|
||||||
vsel,VXC,42
|
|
||||||
vsl,VX,04,452
|
|
||||||
vslb,VX,04,260
|
|
||||||
vsldoi,VX,04,/ SH 44
|
|
||||||
vslh,VX,04,324
|
|
||||||
vslo,VX,04,1036
|
|
||||||
vslw,VX,04,388
|
|
||||||
vspltb,VU,04,524
|
|
||||||
vsplth,VU,04,588
|
|
||||||
vspltisb,VS,04,780
|
|
||||||
vspltish,VS,04,844
|
|
||||||
vspltisw,VS,04,908
|
|
||||||
vspltw,VSU,04,652
|
|
||||||
vsr,VX,04,708
|
|
||||||
vsrab,VX,04,772
|
|
||||||
vsrah,VX,04,836
|
|
||||||
vsraw,VX,04,900
|
|
||||||
vsrb,VX,04,516
|
|
||||||
vsrh,VX,04,580
|
|
||||||
vsro,VX,04,1100
|
|
||||||
vsrw,VX,04,644
|
|
||||||
vsubcuw,VX,04,1408
|
|
||||||
vsubfp,VX,04,74
|
|
||||||
vsubsbs,VX,04,1792
|
|
||||||
vsubshs,VX,04,1856
|
|
||||||
vsubsws,VX,04,1920
|
|
||||||
vsububm,VX,04,1024
|
|
||||||
vsububs,VX,04,1536
|
|
||||||
vsubuhm,VX,04,1088
|
|
||||||
vsubuhs,VX,04,1600
|
|
||||||
vsubuwm,VX,04,1152
|
|
||||||
vsubuws,VX,04,1664
|
|
||||||
vsumsws,VX,04,1928
|
|
||||||
vsum2sws,VX,04,1672
|
|
||||||
vsum4sbs,VX,04,1800
|
|
||||||
vsum4shs,VX,04,1608
|
|
||||||
vsum4ubs,VX,04,1544
|
|
||||||
vupkhpx,VY,04,846
|
|
||||||
vupkhsb,VY,04,526
|
|
||||||
vupkhsh,VY,04,590
|
|
||||||
vupklpx,VY,04,974
|
|
||||||
vupklsb,VY,04,654
|
|
||||||
vupklsh,VY,04,718
|
|
||||||
vxor,VX,04,122
|
|
||||||
Vendored
-6
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
$CC data2code.c -o data2code && ./data2code data.txt >powah_gen_base.hpp
|
|
||||||
$CC --target=powerpc64le test.S -c -o test && objdump -SC test
|
|
||||||
Vendored
-222
@@ -1,222 +0,0 @@
|
|||||||
add[o][.],Add,XO,31,266
|
|
||||||
addc[o][.],Add Carrying,XO,31,10
|
|
||||||
adde[o][.],Add Extended,XO,31,138
|
|
||||||
addi,Add Immediate,D,14,
|
|
||||||
addic,Add Immediate Carrying,D,12,
|
|
||||||
addic.,Add Immediate Carrying and Record,D,13,
|
|
||||||
addis,Add Immediate Shifted,D,15,
|
|
||||||
addme[o][.],Add to Minus One Extended,XO,31,234
|
|
||||||
addze[o][.],Add to Zero Extended,XO,31,202
|
|
||||||
and[.],AND,X,31,28
|
|
||||||
andc[.],AND with Complement,X,31,60
|
|
||||||
andi.,AND Immediate,D,28,
|
|
||||||
andis.,AND Immediate Shifted,D,29,
|
|
||||||
b[l][a],Branch,I,18,
|
|
||||||
bc[l][a],Branch Conditional,B,16,
|
|
||||||
bcctr[l],Branch Conditional to Count Register,XL,19,528
|
|
||||||
bclr[l],Branch Conditional Link Register,XL,19,16
|
|
||||||
cmp,Compare,X,31,0
|
|
||||||
cmpi,Compare Immediate,D,11,
|
|
||||||
cmpl,Compare Logical,X,31,32
|
|
||||||
cmpli,Compare Logical Immediate,D,10,
|
|
||||||
cntlzd,Count Leading Zeros Doubleword,X,31,58
|
|
||||||
cntlzw[.],Count Leading Zeros Word,X,31,26
|
|
||||||
crand,Condition Register AND,XL,19,257
|
|
||||||
crandc,Condition Register AND with Complement,XL,19,129
|
|
||||||
creqv,Condition Register Equivalent,XL,19,289
|
|
||||||
crnand,Condition Register NAND,XL,19,225
|
|
||||||
crnor,Condition Register NOR,XL,19,33
|
|
||||||
cror,Condition Register OR,XL,19,449
|
|
||||||
crorc,Condition Register OR with Complement,XL,19,417
|
|
||||||
crxor,Condition Register XOR,XL,19,193
|
|
||||||
dcbf,Data Cache Block Flush,X,31,86
|
|
||||||
dcbi,Data Cache Block Invalidate,X,31,470
|
|
||||||
dcbst,Data Cache Block Store,X,31,54
|
|
||||||
dcbt,Data Cache Block Touch,X,31,278
|
|
||||||
dcbtst,Data Cache Block Touch for Store,X,31,246
|
|
||||||
dcbz,Data Cache Block Set to Zero,X,31,1014
|
|
||||||
divd,Divide Doubleword,XO,31,489
|
|
||||||
divdu,Divide Doubleword Unsigned,XO,31,457
|
|
||||||
divw[o][.],Divide Word,XO,31,491
|
|
||||||
divwu[o][.],Divide Word Unsigned,XO,31,459
|
|
||||||
eciwx,External Control in Word Indexed (opt.),X,31,310
|
|
||||||
ecowx,External Control out Word Indexed (opt.),X,31,438
|
|
||||||
eieio,Enforce In-order Execution of I/O,X,31,854
|
|
||||||
eqv[.],Equivalent,X,31,284
|
|
||||||
extsb[.],Extend Sign Byte,X,31,954
|
|
||||||
extsh[.],Extend Sign Halfword,XO,31,922
|
|
||||||
extsw,Extend Sign Word,X,31,986
|
|
||||||
fabs[.],Floating Absolute Value,X,63,264
|
|
||||||
fadd[.],Floating Add,A,63,21
|
|
||||||
fadds[.],Floating Add Single,A,59,21
|
|
||||||
fcfid,Floating Convert from Integer Doubleword,X,63,846
|
|
||||||
fcmpo,Floating Compare Ordered,X,63,32
|
|
||||||
fcmpu,Floating Compare Unordered,XL,63,0
|
|
||||||
fctid,Floating Convert to Integer Doubleword,X,63,814
|
|
||||||
fctidz,Floating Convert to Integer Doubleword with Round Toward Zero,X,63,815
|
|
||||||
fctiw[.],Floating Convert to Integer Word,X,63,14
|
|
||||||
fctiwz[.],Floating Convert to Integer Word with Round to Zero,XL,63,15
|
|
||||||
fdiv[.],Floating Divide,A,63,18
|
|
||||||
fdivs[.],Floating Divide Single,A,59,18
|
|
||||||
fmadd[.],Floating Multiply-Add,A,63,29
|
|
||||||
fmadds[.],Floating Multiply-Add Single,A,59,29
|
|
||||||
fmr[.],Floating Move Register,X,63,72
|
|
||||||
fmsub[.],Floating Multiply-Subtract,A,63,28
|
|
||||||
fmsubs[.],Floating Multiply-Subtract Single,A,59,28
|
|
||||||
fmul[.],Floating Multiply,A,63,25
|
|
||||||
fmuls[.],Floating Multiply Single,A,59,25
|
|
||||||
fnabs[.],Floating Negative Absolute Value,X,63,136
|
|
||||||
fneg[.],Floating Negate,X,63,40
|
|
||||||
fnmadd[.],Floating Negative Multiply-Add,A,63,31
|
|
||||||
fnmadds[.],Floating Negative Multiply-Add Single,A,59,31
|
|
||||||
fnmsub[.],Floating Negative Multiply-Subtract,A,63,30
|
|
||||||
fnmsubs[.],Floating Negative Multiply-Subtract Single,A,59,30
|
|
||||||
fres[.],Floating Reciprocal Estimate Single (optional),A,59,24
|
|
||||||
frsp[.],Floating Round to Single Precision,X,63,12
|
|
||||||
frsqrte[.],Floating Reciprocal Square Root Estimate (optional),A,63,26
|
|
||||||
fsel[.],Floating-Point Select (optional),A,63,23
|
|
||||||
fsub[.],Floating Subtract,A,63,20
|
|
||||||
fsubs[.],Floating Subtract Single,A,59,20
|
|
||||||
icbi,Instruction Cache Block Invalidate,X,31,982
|
|
||||||
isync,Instruction Synchronize,X,19,150
|
|
||||||
lbz,Load Byte and Zero,D,34,
|
|
||||||
lbzu,Load Byte and Zero with Update,D,35,
|
|
||||||
lbzux,Load Byte and Zero with Update Indexed,X,31,119
|
|
||||||
lbzx,Load Byte and Zero Indexed,X,31,87
|
|
||||||
ld,Load Doubleword,DS,58,0
|
|
||||||
ldarx,Load Doubleword and Reserve Indexed,X,31,84
|
|
||||||
ldu,Load Doubleword with Update,DS,58,1
|
|
||||||
ldux,Load Doubleword with Update Indexed,X,31,53
|
|
||||||
ldx,Load Doubleword Indexed,X,31,21
|
|
||||||
lfd,Load Floating-Point Double,D,50,
|
|
||||||
lfdu,Load Floating-Point Double with Update,D,51,
|
|
||||||
lfdux,Load Floating-Point Double with Update Indexed,X,31,631
|
|
||||||
lfdx,Load Floating-Point Double Indexed,X,31,599
|
|
||||||
lfs,Load Floating-Point Single,D,48,
|
|
||||||
lfsu,Load Floating-Point Single with Update,D,49,
|
|
||||||
lfsux,Load Floating-Point Single with Update Indexed,X,31,567
|
|
||||||
lfsx,Load Floating-Point Single Indexed,X,31,535
|
|
||||||
lha,Load Half Algebraic,D,42,
|
|
||||||
lhau,Load Half Algebraic with Update,D,43,
|
|
||||||
lhaux,Load Half Algebraic with Update Indexed,X,31,375
|
|
||||||
lhax,Load Half Algebraic Indexed,X,31,343
|
|
||||||
lhbrx,Load Half Byte-Reversed Indexed,X,31,790
|
|
||||||
lhz,Load Half and Zero,D,40,
|
|
||||||
lhzu,Load Half and Zero with Update,D,41,
|
|
||||||
lhzux,Load Half and Zero with Update Indexed,X,31,331
|
|
||||||
lhzx,Load Half and Zero Indexed,X,31,279
|
|
||||||
lmw,Load Multiple Word,D,46,
|
|
||||||
lswi,Load String Word Immediate,X,31,597
|
|
||||||
lswx,Load String Word Indexed,X,31,533
|
|
||||||
lwa,Load Word Algebraic,DS,58,2
|
|
||||||
lwarx,Load Word and Reserve Indexed,X,31,20
|
|
||||||
lwaux,Load Word Algebraic with Update Indexed,X,31,373
|
|
||||||
lwax,Load Word Algebraic Indexed,X,31,341
|
|
||||||
lwbrx,Load Word Byte-Reversed Indexed,X,31,534
|
|
||||||
lwz,Load Word and Zero,D,32,
|
|
||||||
lwzu,Load Word with Zero Update,D,33,
|
|
||||||
lwzux,Load Word and Zero with Update Indexed,X,31,55
|
|
||||||
lwzx,Load Word and Zero Indexed,X,31,23
|
|
||||||
mcrf,Move Condition Register Field,XL,19,0
|
|
||||||
mcrfs,Move to Condition Register from FPSCR,X,63,64
|
|
||||||
mcrxr,Move to Condition Register from XER,X,31,512
|
|
||||||
mfcr,Move from Condition Register,X,31,19
|
|
||||||
mffs[.],Move from FPSCR,X,63,583
|
|
||||||
mfmsr,Move from Machine State Register,X,31,83
|
|
||||||
mfspr,Move from Special-Purpose Register,X,31,339
|
|
||||||
mfsr,Move from Segment Register,X,31,595
|
|
||||||
mfsrin,Move from Segment Register Indirect,X,31,659
|
|
||||||
mtcrf,Move to Condition Register Fields,XFX,31,144
|
|
||||||
mtfsb0[.],Move to FPSCR Bit 0,X,63,70
|
|
||||||
mtfsb1[.],Move to FPSCR Bit 1,X,63,38
|
|
||||||
mtfsf[.],Move to FPSCR Fields,XFL,63,711
|
|
||||||
mtfsfi[.],Move to FPSCR Field Immediate,X,63,134
|
|
||||||
mtmsr,Move to Machine State Register,X,31,146
|
|
||||||
mtspr,Move to Special-Purpose Register,X,31,467
|
|
||||||
mtsr,Move to Segment Register,X,31,210
|
|
||||||
mtsrin,Move to Segment Register Indirect,X,31,242
|
|
||||||
mulhd,Multiply High Doubleword,XO,31,73
|
|
||||||
mulhdu,Multiply High Doubleword Unsigned,XO,31,9
|
|
||||||
mulhw[.],Multiply High Word,XO,31,75
|
|
||||||
mulhwu[.],Multiply High Word Unsigned,XO,31,11
|
|
||||||
mulld,Multiply Low Doubleword,XO,31,233
|
|
||||||
mulli,Multiply Low Immediate,D,07,
|
|
||||||
mullw[o][.],Multiply Low Word,XO,31,235
|
|
||||||
nand[.],NAND,X,31,476
|
|
||||||
neg[o][.],Negate,XO,31,104
|
|
||||||
nor[.],NOR,X,31,124
|
|
||||||
or[.],OR,X,31,444
|
|
||||||
orc[.],OR with Complement,X,31,412
|
|
||||||
ori,OR Immediate,D,24,
|
|
||||||
oris,OR Immediate Shifted,D,25,
|
|
||||||
rfi,Return from Interrupt,X,19,50
|
|
||||||
rldcl,Rotate Left Doubleword then Clear Left,MDS,30,8
|
|
||||||
rldcr,Rotate Left Doubleword then Clear Right,MDS,30,9
|
|
||||||
rldic,Rotate Left Doubleword Immediate then Clear,MD,30,2
|
|
||||||
rldicl,Rotate Left Doubleword Immediate then Clear Left,MD,30,0
|
|
||||||
rldicr,Rotate Left Doubleword Immediate then Clear Right,MD,30,1
|
|
||||||
rldimi,Rotate Left Doubleword Immediate then Mask Insert,MD,30,3
|
|
||||||
rlwimi[.],Rotate Left Word Immediate then Mask Insert,M,20,
|
|
||||||
rlwinm[.],Rotate Left Word Immediate then AND with Mask,M,21,
|
|
||||||
rlwnm[.],Rotate Left Word then AND with Mask,M,23,
|
|
||||||
sc,System Call,SC,17,
|
|
||||||
si,Subtract Immediate,D,12,
|
|
||||||
si.,Subtract Immediate and Record,D,13,
|
|
||||||
slbia,SLB Invalidate All,X,31,498
|
|
||||||
slbie,SLB Invalidate Entry,X,31,434
|
|
||||||
sld,Shift Left Doubleword,X,31,27
|
|
||||||
slw[.],Shift Left Word,X,31,24
|
|
||||||
srad,Shift Right Algebraic Doubleword,X,31,794
|
|
||||||
sradi,Shift Right Algebraic Doubleword Immediate,XS,31,413
|
|
||||||
srd,Shift Right Doubleword,X,31,539
|
|
||||||
sraw[.],Shift Right Algebraic Word,X,31,792
|
|
||||||
srawi[.],Shift Right Algebraic Word Immediate,X,31,824
|
|
||||||
srw[.],Shift Right Word,X,31,536
|
|
||||||
stb,Store Byte,D,38,
|
|
||||||
stbu,Store Byte with Update,D,39,
|
|
||||||
stbux,Store Byte with Update Indexed,X,31,247
|
|
||||||
stbx,Store Byte Indexed,X,31,215
|
|
||||||
std,Store Doubleword,DS,62,0
|
|
||||||
stdcx,Store Doubleword Conditional Indexed,X,31,214
|
|
||||||
stdu,Store Doubleword with Update,DS,62,1
|
|
||||||
stdux,Store Doubleword with Update Indexed,X,31,181
|
|
||||||
stdx,Store Doubleword Indexed,X,31,149
|
|
||||||
stfd,Store Floating-Point Double,D,54,
|
|
||||||
stfdu,Store Floating-Point Double with Update,D,55,
|
|
||||||
stfdux,Store Floating-Point Double with Update Indexed,X,31,759
|
|
||||||
stfdx,Store Floating-Point Double Indexed,X,31,727
|
|
||||||
stfiwx,Store Floating-Point as Integer Word Indexed (optional),X,31,983
|
|
||||||
stfs,Store Floating-Point Single,D,52,
|
|
||||||
stfsu,Store Floating-Point Single with Update,D,53,
|
|
||||||
stfsux,Store Floating-Point Single with Update Indexed,X,31,695
|
|
||||||
stfsx,Store Floating-Point Single Indexed,X,31,663
|
|
||||||
sth,Store Half,D,44,
|
|
||||||
sthbrx,Store Half Byte-Reverse Indexed,X,31,918
|
|
||||||
sthu,Store Half with Update,D,45,
|
|
||||||
sthux,Store Half with Update Indexed,X,31,439
|
|
||||||
sthx,Store Half Indexed,X,31,407
|
|
||||||
stmw,Store Multiple Word,D,47,
|
|
||||||
stswi,Store String Word Immediate,X,31,725
|
|
||||||
stswx,Store String Word Indexed,X,31,661
|
|
||||||
stw,Store,D,36,
|
|
||||||
stwbrx,Store Word Byte-Reversed Indexed,X,31,662
|
|
||||||
stwcx.,Store Word Conditional Indexed,X,31,150
|
|
||||||
stwu,Store Word with Update,D,37,
|
|
||||||
stwux,Store Word with Update Indexed,X,31,183
|
|
||||||
stwx,Store Word Indexed,X,31,151
|
|
||||||
subf[o][.],Subtract from,XO,31,40
|
|
||||||
subfc[o][.],Subtract from Carrying,XO,31,08
|
|
||||||
subfe[o][.],Subtract from Extended,XO,31,136
|
|
||||||
subfic,Subtract from Immediate Carrying,D,08,
|
|
||||||
subfme[o][.],Subtract from Minus One Extended,XO,31,232
|
|
||||||
subfze[o][.],Subtract from Zero Extended,XO,31,200
|
|
||||||
sync,Synchronize,X,31,598
|
|
||||||
td,Trap Doubleword,X,31,68
|
|
||||||
tdi,Trap Doubleword Immediate,D,2,
|
|
||||||
tlbie,Translation Look-aside Buffer Invalidate Entry (optional),X,31,306
|
|
||||||
tlbsync,Translation Look-aside Buffer Synchronize (optional),X,31,566
|
|
||||||
tw,Trap Word,X,31,04
|
|
||||||
twi,Trap Word Immediate,D,03,
|
|
||||||
xor[.],XOR,X,31,316
|
|
||||||
xori,XOR Immediate,D,26,
|
|
||||||
xoris,XOR Immediate Shift,D,27,
|
|
||||||
Vendored
-343
@@ -1,343 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <string.h>
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
printf(
|
|
||||||
"// this file is autogenerated DO NOT MODIFY\n"
|
|
||||||
"#pragma once\n"
|
|
||||||
);
|
|
||||||
FILE* fp = fopen(argv[1], "rt");
|
|
||||||
if (fp) {
|
|
||||||
char line[80];
|
|
||||||
while (fgets(line, sizeof line, fp) != NULL) {
|
|
||||||
bool with_o = strstr(line, "[o]"), with_d = strstr(line, "[.]");
|
|
||||||
char* p = strchr(line, '\n'), *name = strchr(line, ','), *mem = line;
|
|
||||||
if (p) *p = '\0';
|
|
||||||
if (name) {
|
|
||||||
*name++ = '\0';
|
|
||||||
char *form = strchr(name, ',');
|
|
||||||
if (form) {
|
|
||||||
*form++ = '\0';
|
|
||||||
char *opc = strchr(form, ',');
|
|
||||||
if (opc) {
|
|
||||||
*opc++ = '\0';
|
|
||||||
char *sec = strchr(opc, ',');
|
|
||||||
if (sec) {
|
|
||||||
struct b_info { const char *s; int o; int p; } infos[] = {
|
|
||||||
{"",1,0},
|
|
||||||
{"LT",1,12},
|
|
||||||
{"LE",2,4},
|
|
||||||
{"NG",2,4},
|
|
||||||
{"EQ",3,12},
|
|
||||||
{"GE",1,4},
|
|
||||||
{"NL",1,4},
|
|
||||||
{"GT",2,12},
|
|
||||||
{"NE",3,4},
|
|
||||||
{"SO",4,12},
|
|
||||||
{"UN",4,12},
|
|
||||||
{"NS",4,4},
|
|
||||||
{"NU",4,4},
|
|
||||||
};
|
|
||||||
#define OP_EXT ((i_opcode << 26) | (i_extopc << 1))
|
|
||||||
if (strchr(mem, '[') != NULL) *strchr(mem, '[') = '\0';
|
|
||||||
if (strchr(mem, '.') != NULL) *strchr(mem, '.') = '_';
|
|
||||||
*sec++ = '\0';
|
|
||||||
for (int i = 0; i < strlen(mem); ++i)
|
|
||||||
mem[i] = toupper(mem[i]);
|
|
||||||
int i_opcode = atoi(opc);
|
|
||||||
int i_extopc = atoi(sec);
|
|
||||||
//printf("// %s\n", mem);
|
|
||||||
if (!strcmp(form, "XO")) {
|
|
||||||
if (!strcmp(mem, "EXTSH")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, false, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sC(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, true, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, false, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sC_(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, R0, true, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, false, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sO(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, true, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, false, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sO_(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, rb, true, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "X")) {
|
|
||||||
if (!strcmp(mem, "CMPL") || !strcmp(mem, "CMP")) {
|
|
||||||
printf(
|
|
||||||
"void %s(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, GPR{(bf << 2) | l}, ra, rb, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else if (!strcmp(mem, "CNTLZD") || !strcmp(mem, "CNTLZW") || !strcmp(mem, "EXTSB") || !strcmp(mem, "EXTSH") || !strcmp(mem, "EXTSW")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, R0, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, R0, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, rb, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra, GPR const rb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, rb, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "I")) {
|
|
||||||
printf(
|
|
||||||
"void %s(Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, i, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
printf(
|
|
||||||
"void %sL(Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, i, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else if (!strcmp(form, "B")) {
|
|
||||||
for (int i = 0; i < 12; ++i) {
|
|
||||||
printf(
|
|
||||||
"void %s%s(CPR const cr, Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, %i, cr.index + %i, i, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, i_opcode << 26, infos[i].p, infos[i].o - 1);
|
|
||||||
printf(
|
|
||||||
"void %s%sL(CPR const cr, Label const& i) {"
|
|
||||||
" emit_reloc_%s(0x%08x, %i, cr.index + %i, i, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, i_opcode << 26, infos[i].p, infos[i].o - 1);
|
|
||||||
if (!strcmp(mem, "BC")) mem[1] = '\0';
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "D")) {
|
|
||||||
if (!strcmp(mem, "CMPLI") || !strcmp(mem, "CMPI")) {
|
|
||||||
printf(
|
|
||||||
"void %s(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, GPR{(bf << 2) | l}, ra, d); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else if (!strcmp(mem, "ANDIS_") || !strcmp(mem, "ANDI_")
|
|
||||||
|| !strcmp(mem, "ORI") || !strcmp(mem, "ORIS")
|
|
||||||
|| !strcmp(mem, "XORI") || !strcmp(mem, "XORIS")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, ra, rt, d); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, d); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "SC")) {
|
|
||||||
printf(
|
|
||||||
"void %s(uint32_t lev) {"
|
|
||||||
" emit_%s(0x%08x, lev); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, i_opcode << 26);
|
|
||||||
} else if (!strcmp(form, "DS")) {
|
|
||||||
#define OP_EXT_DS ((i_opcode << 26) | (i_extopc << 0))
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, d >> 2); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT_DS);
|
|
||||||
#undef OP_EXT_DS
|
|
||||||
} else if (!strcmp(form, "XS")) {
|
|
||||||
#define OP_EXT_XS ((i_opcode << 26) | (i_extopc << 2))
|
|
||||||
/* HUGE DIFFERENCE DO NOT REMOVE */
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, GPR const ra, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, sh, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT_XS);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rt, GPR const ra, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, rt, ra, sh, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT_XS);
|
|
||||||
#undef OP_EXT_XS
|
|
||||||
} else if (!strcmp(form, "XL")) {
|
|
||||||
if (!strcmp(mem, "BCLR")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
if (!strcmp(mem, "BCLR")) mem[1] = '\0';
|
|
||||||
for (int i = 1; i < 12; ++i) {
|
|
||||||
printf(
|
|
||||||
"void %s%sLR(CPR const cr) {"
|
|
||||||
" emit_%s(0x%08x, %i, cr.index + %i, 0, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, OP_EXT, infos[i].p, infos[i].o - 1);
|
|
||||||
printf(
|
|
||||||
"void %s%sLRL(CPR const cr) {"
|
|
||||||
" emit_%s(0x%08x, %i, cr.index + %i, 0, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, infos[i].s, form, OP_EXT, infos[i].p, infos[i].o - 1);
|
|
||||||
}
|
|
||||||
} else if (mem[0] == 'B') {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(GPR const bt, CPR const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const bt, Cond const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, cond2offset(ba), bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(GPR const bt, Cond const ba, GPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, cond2offset(ba), bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(CPR const bt, CPR const ba, CPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %sL(CPR const bt, CPR const ba, CPR const bb) {"
|
|
||||||
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "M")) {
|
|
||||||
if (!strcmp(mem, "RLWNM")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb.index, mb, me, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb.index, mb, me, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, sh, mb, me, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, sh, mb, me, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
} else if (!strcmp(form, "MD")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, mb, sh, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, (i_opcode << 26) | (i_extopc << 2));
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, mb, sh, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, (i_opcode << 26) | (i_extopc << 2));
|
|
||||||
} else if (!strcmp(form, "MDS")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb, mb, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) {"
|
|
||||||
" emit_%s(0x%08x, ra, rs, rb, mb, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else if (!strcmp(form, "A")) {
|
|
||||||
printf(
|
|
||||||
"void %s(FPR const frt, FPR const fra, FPR const frb, FPR const frc) {"
|
|
||||||
" emit_%s(0x%08x, frt, fra, frb, frc, false); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
printf(
|
|
||||||
"void %s_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) {"
|
|
||||||
" emit_%s(0x%08x, frt, fra, frb, frc, true); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else if (!strcmp(form, "XFX")) {
|
|
||||||
printf(
|
|
||||||
"void %s(GPR const rt, uint32_t spr) {"
|
|
||||||
" emit_%s(0x%08x, rt, spr); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
} else {
|
|
||||||
printf(
|
|
||||||
"void %s() {"
|
|
||||||
" emit_%s(0x%08x); "
|
|
||||||
"}\n"
|
|
||||||
, mem, form, OP_EXT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//printf("%s\n", line);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
Vendored
-401
@@ -1,401 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#undef NDEBUG
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
|
||||||
#include <utility>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
//#ifndef __cpp_lib_unreachable
|
|
||||||
namespace std {
|
|
||||||
[[noreturn]] inline void unreachable() {
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
|
||||||
__assume(false);
|
|
||||||
#else // GCC, Clang
|
|
||||||
__builtin_unreachable();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
namespace powah {
|
|
||||||
|
|
||||||
// Symbolic conditions
|
|
||||||
enum class Cond : uint8_t {
|
|
||||||
LT, LE, NG, EQ, GE, NL, GT, NE, SO, UN, NS, NU
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GPR { uint32_t index; };
|
|
||||||
struct FPR { uint32_t index; };
|
|
||||||
struct VPR { uint32_t index; };
|
|
||||||
struct CPR { uint32_t index; };
|
|
||||||
struct Label { uint32_t index; };
|
|
||||||
|
|
||||||
constexpr inline GPR R0{0};
|
|
||||||
constexpr inline GPR R1{1};
|
|
||||||
constexpr inline GPR R2{2};
|
|
||||||
constexpr inline GPR R3{3};
|
|
||||||
constexpr inline GPR R4{4};
|
|
||||||
constexpr inline GPR R5{5};
|
|
||||||
constexpr inline GPR R6{6};
|
|
||||||
constexpr inline GPR R7{7};
|
|
||||||
constexpr inline GPR R8{8};
|
|
||||||
constexpr inline GPR R9{9};
|
|
||||||
constexpr inline GPR R10{10};
|
|
||||||
constexpr inline GPR R11{11};
|
|
||||||
constexpr inline GPR R12{12};
|
|
||||||
constexpr inline GPR R13{13};
|
|
||||||
constexpr inline GPR R14{14};
|
|
||||||
constexpr inline GPR R15{15};
|
|
||||||
constexpr inline GPR R16{16};
|
|
||||||
constexpr inline GPR R17{17};
|
|
||||||
constexpr inline GPR R18{18};
|
|
||||||
constexpr inline GPR R19{19};
|
|
||||||
constexpr inline GPR R20{20};
|
|
||||||
constexpr inline GPR R21{21};
|
|
||||||
constexpr inline GPR R22{22};
|
|
||||||
constexpr inline GPR R23{23};
|
|
||||||
constexpr inline GPR R24{24};
|
|
||||||
constexpr inline GPR R25{25};
|
|
||||||
constexpr inline GPR R26{26};
|
|
||||||
constexpr inline GPR R27{27};
|
|
||||||
constexpr inline GPR R28{28};
|
|
||||||
constexpr inline GPR R29{29};
|
|
||||||
constexpr inline GPR R30{30};
|
|
||||||
constexpr inline GPR R31{31};
|
|
||||||
|
|
||||||
constexpr inline FPR FR0{0};
|
|
||||||
constexpr inline FPR FR1{1};
|
|
||||||
constexpr inline FPR FR2{2};
|
|
||||||
constexpr inline FPR FR3{3};
|
|
||||||
constexpr inline FPR FR4{4};
|
|
||||||
constexpr inline FPR FR5{5};
|
|
||||||
constexpr inline FPR FR6{6};
|
|
||||||
constexpr inline FPR FR7{7};
|
|
||||||
constexpr inline FPR FR8{8};
|
|
||||||
constexpr inline FPR FR9{9};
|
|
||||||
constexpr inline FPR FR10{10};
|
|
||||||
constexpr inline FPR FR11{11};
|
|
||||||
constexpr inline FPR FR12{12};
|
|
||||||
constexpr inline FPR FR13{13};
|
|
||||||
constexpr inline FPR FR14{14};
|
|
||||||
constexpr inline FPR FR15{15};
|
|
||||||
constexpr inline FPR FR16{16};
|
|
||||||
constexpr inline FPR FR17{17};
|
|
||||||
constexpr inline FPR FR18{18};
|
|
||||||
constexpr inline FPR FR19{19};
|
|
||||||
constexpr inline FPR FR20{20};
|
|
||||||
constexpr inline FPR FR21{21};
|
|
||||||
constexpr inline FPR FR22{22};
|
|
||||||
constexpr inline FPR FR23{23};
|
|
||||||
constexpr inline FPR FR24{24};
|
|
||||||
constexpr inline FPR FR25{25};
|
|
||||||
constexpr inline FPR FR26{26};
|
|
||||||
constexpr inline FPR FR27{27};
|
|
||||||
constexpr inline FPR FR28{28};
|
|
||||||
constexpr inline FPR FR29{29};
|
|
||||||
constexpr inline FPR FR30{30};
|
|
||||||
constexpr inline FPR FR31{31};
|
|
||||||
|
|
||||||
// They call it CPR because when programmers see this code they-
|
|
||||||
constexpr inline CPR CR0{0};
|
|
||||||
constexpr inline CPR CR1{4};
|
|
||||||
constexpr inline CPR CR2{8};
|
|
||||||
constexpr inline CPR CR3{12};
|
|
||||||
constexpr inline CPR CR4{16};
|
|
||||||
constexpr inline CPR CR5{20};
|
|
||||||
constexpr inline CPR CR6{24};
|
|
||||||
constexpr inline CPR CR7{28};
|
|
||||||
|
|
||||||
constexpr uint32_t XER_SO = 32;
|
|
||||||
constexpr uint32_t XER_OV = 33;
|
|
||||||
constexpr uint32_t XER_CA = 34;
|
|
||||||
|
|
||||||
enum class RelocKind : uint8_t {
|
|
||||||
FormB,
|
|
||||||
FormI,
|
|
||||||
};
|
|
||||||
struct RelocInfo {
|
|
||||||
uint32_t offset;
|
|
||||||
RelocKind kind;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Context {
|
|
||||||
Context() = default;
|
|
||||||
Context(void* ptr, size_t size)
|
|
||||||
: base{reinterpret_cast<uint32_t*>(ptr)}
|
|
||||||
, offset{0}
|
|
||||||
, size{uint32_t(size)} {
|
|
||||||
|
|
||||||
}
|
|
||||||
~Context() = default;
|
|
||||||
|
|
||||||
std::vector<uint32_t> labels;
|
|
||||||
std::vector<std::pair<uint32_t, RelocInfo>> relocs;
|
|
||||||
|
|
||||||
Label DefineLabel() {
|
|
||||||
labels.push_back(0);
|
|
||||||
return Label{ uint32_t(labels.size() - 1) };
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyRelocs() {
|
|
||||||
for (auto const &[index, info] : relocs) {
|
|
||||||
//assert(labels[index] != 0); //label must have an addr
|
|
||||||
int32_t rel = (int32_t)labels[index] - (int32_t)info.offset;
|
|
||||||
switch (info.kind) {
|
|
||||||
case RelocKind::FormB:
|
|
||||||
base[info.offset] |= bitExt(rel, 16, 14);
|
|
||||||
break;
|
|
||||||
case RelocKind::FormI:
|
|
||||||
base[info.offset] |= bitExt(rel, 6, 24);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
relocs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LABEL(Label l) {
|
|
||||||
assert(labels[l.index] == 0);
|
|
||||||
labels[l.index] = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr uint32_t cond2offset(Cond c) noexcept {
|
|
||||||
switch (c) {
|
|
||||||
case Cond::LT: return 1;
|
|
||||||
case Cond::LE: return 2;
|
|
||||||
case Cond::NG: return 2;
|
|
||||||
case Cond::EQ: return 3;
|
|
||||||
case Cond::GE: return 1;
|
|
||||||
case Cond::NL: return 1;
|
|
||||||
case Cond::GT: return 2;
|
|
||||||
case Cond::NE: return 3;
|
|
||||||
case Cond::SO: return 4;
|
|
||||||
case Cond::UN: return 4;
|
|
||||||
case Cond::NS: return 4;
|
|
||||||
case Cond::NU: return 4;
|
|
||||||
default: return 0; //hopefully icc isn't stupid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t bitExt(uint32_t value, uint32_t offs, uint32_t n) {
|
|
||||||
uint32_t mask = (1UL << n) - 1;
|
|
||||||
return (value & mask) << (32 - (n + offs));
|
|
||||||
}
|
|
||||||
void emit_XO(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool oe, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| bitExt(oe, 21, 1)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_D(uint32_t op, GPR const rt, GPR const ra, uint32_t d) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| (d & 0xffff)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_X(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_XS(uint32_t op, GPR const rt, GPR const ra, uint32_t sh, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
((rt.index & 0x1f) << 16)
|
|
||||||
| ((ra.index & 0x1f) << 21)
|
|
||||||
| ((sh & 0x1f) << 11)
|
|
||||||
| ((sh >> 4) & 0x02)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_reloc_I(uint32_t op, Label const& l, bool lk) {
|
|
||||||
relocs.emplace_back(l.index, RelocInfo{ offset, RelocKind::FormI });
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(lk, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_reloc_B(uint32_t op, uint32_t bo, uint32_t cri, Label const& l, bool lk) {
|
|
||||||
relocs.emplace_back(l.index, RelocInfo{ offset, RelocKind::FormB });
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(bo, 6, 5)
|
|
||||||
| bitExt(cri, 11, 5)
|
|
||||||
| bitExt(lk, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_XL(uint32_t op, uint32_t bt, uint32_t ba, uint32_t bb, bool lk) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(bt, 6, 5)
|
|
||||||
| bitExt(ba, 11, 5)
|
|
||||||
| bitExt(bb, 16, 5)
|
|
||||||
| bitExt(lk, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_A(uint32_t op, FPR const frt, FPR const fra, FPR const frb, FPR const frc, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(frt.index, 6, 5)
|
|
||||||
| bitExt(fra.index, 11, 5)
|
|
||||||
| bitExt(frb.index, 16, 5)
|
|
||||||
| bitExt(frc.index, 21, 5)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_DS(uint32_t op, GPR const rt, GPR const ra, uint32_t d) {
|
|
||||||
//assert(d & 0x03 == 0);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rt.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(d, 16, 14)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_M(uint32_t op, GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me, bool rc) {
|
|
||||||
assert(sh <= 0x3f && mb <= 0x3f);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| ((sh & 0x1f) << 11)
|
|
||||||
| ((mb & 0x1f) << 6)
|
|
||||||
| ((me & 0x1f) << 1)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_MD(uint32_t op, GPR const rs, GPR const ra, GPR const rb, uint32_t mb, bool rc) {
|
|
||||||
assert(mb <= 0x3f);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_MD(uint32_t op, GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, bool rc) {
|
|
||||||
assert(sh <= 0x3f && mb <= 0x3f);
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
|
||||||
| ((sh & 0x1f) << 11) | ((sh >> 4) & 0x02)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_MDS(uint32_t op, GPR const rs, GPR const ra, GPR const rb, uint32_t mb, bool rc) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
bitExt(rs.index, 6, 5)
|
|
||||||
| bitExt(ra.index, 11, 5)
|
|
||||||
| bitExt(rb.index, 16, 5)
|
|
||||||
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
|
||||||
| bitExt(rc, 31, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_XFL(uint32_t op) {
|
|
||||||
(void)op;
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
void emit_XFX(uint32_t op, GPR const rt, uint32_t spr) {
|
|
||||||
base[offset++] = (op |
|
|
||||||
(rt.index & 0x1f) << 21
|
|
||||||
| ((spr & 0xff) << 12)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void emit_SC(uint32_t op, uint32_t lev) {
|
|
||||||
(void)op;
|
|
||||||
(void)lev;
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extended Memmonics, hand coded :)
|
|
||||||
void MR(GPR const ra, GPR const rs) { OR(ra, rs, rs); }
|
|
||||||
void NOP() { ORI(R0, R0, 0); }
|
|
||||||
void NOT(GPR const ra, GPR const rs) { NOR(ra, rs, rs); }
|
|
||||||
|
|
||||||
void ROTLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, n, 0); }
|
|
||||||
void ROTRDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 64 - n, 0); }
|
|
||||||
|
|
||||||
void ROTLWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, n, 0, 31); }
|
|
||||||
void ROTRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 32 - n, 0, 31); }
|
|
||||||
|
|
||||||
void ROTLW(GPR const ra, GPR const rs, GPR const rb) { RLWNM(ra, rs, rb, 0, 31); }
|
|
||||||
void ROTLD(GPR const ra, GPR const rs, GPR const rb) { RLDCL(ra, rs, rb, 0); }
|
|
||||||
|
|
||||||
void EXTLDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICR(ra, rs, b, n - 1); }
|
|
||||||
void SLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICR(ra, rs, n, 63 - n); }
|
|
||||||
void CLRLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 0, n); }
|
|
||||||
|
|
||||||
void EXTRDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICL(ra, rs, b + n, 64 - n); }
|
|
||||||
void SRDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 64 - n, n); }
|
|
||||||
void CLLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICR(ra, rs, 0, n); }
|
|
||||||
void CLRSLDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICR(ra, rs, n, b - n); }
|
|
||||||
|
|
||||||
void EXTLWI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLWINM(ra, rs, b, 0, n - 1); }
|
|
||||||
void SRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 32 - n, n, 31); }
|
|
||||||
void CLRRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 0, 0, 31 - n); }
|
|
||||||
|
|
||||||
void CRSET(CPR const bx) { CREQV(bx, bx, bx); }
|
|
||||||
void CRCLR(CPR const bx) { CRXOR(bx, bx, bx); }
|
|
||||||
void CRMOVE(CPR const bx, CPR const by) { CROR(bx, by, by); }
|
|
||||||
void CRNOT(CPR const bx, CPR const by) { CRNOR(bx, by, by); }
|
|
||||||
|
|
||||||
void CMPLDI(CPR const cr, GPR const rx, uint32_t v) { CMPLI(cr.index, 1, rx, v); }
|
|
||||||
void CMPLWI(CPR const cr, GPR const rx, uint32_t v) { CMPLI(cr.index, 0, rx, v); }
|
|
||||||
void CMPLD(CPR const cr, GPR const rx, GPR const ry) { CMPL(cr.index, 1, rx, ry); }
|
|
||||||
void CMPLW(CPR const cr, GPR const rx, GPR const ry) { CMPL(cr.index, 0, rx, ry); }
|
|
||||||
void CMPLDI(GPR const rx, uint32_t v) { CMPLI(0, 1, rx, v); }
|
|
||||||
void CMPLWI(GPR const rx, uint32_t v) { CMPLI(0, 0, rx, v); }
|
|
||||||
void CMPLD(GPR const rx, GPR const ry) { CMPL(0, 1, rx, ry); }
|
|
||||||
void CMPLW(GPR const rx, GPR const ry) { CMPL(0, 0, rx, ry); }
|
|
||||||
|
|
||||||
void CMPWI(CPR const cr, GPR const rx, uint32_t si) { CMPI(cr.index, 0, rx, si); }
|
|
||||||
void CMPW(CPR const cr, GPR const rx, GPR const ry) { CMP(cr.index, 0, rx, ry); }
|
|
||||||
void CMPDI(CPR const cr, GPR const rx, uint32_t si) { CMPI(cr.index, 1, rx, si); }
|
|
||||||
void CMPD(CPR const cr, GPR const rx, GPR const ry) { CMP(cr.index, 1, rx, ry); }
|
|
||||||
void CMPWI(GPR const rx, uint32_t si) { CMPI(0, 0, rx, si); }
|
|
||||||
void CMPW(GPR const rx, GPR const ry) { CMP(0, 0, rx, ry); }
|
|
||||||
void CMPDI(GPR const rx, uint32_t si) { CMPI(0, 1, rx, si); }
|
|
||||||
void CMPD(GPR const rx, GPR const ry) { CMP(0, 1, rx, ry); }
|
|
||||||
|
|
||||||
void LI(GPR const rx, uint32_t value) { ADDI(rx, R0, value); }
|
|
||||||
void LIS(GPR const rx, uint32_t value) { ADDIS(rx, R0, value); }
|
|
||||||
|
|
||||||
void MFLR(GPR const rt) { MFSPR(powah::GPR{8}, rt, powah::GPR{0}); }
|
|
||||||
void MTLR(GPR const rt) { MTSPR(powah::GPR{8}, rt, powah::GPR{0}); }
|
|
||||||
void BLR() { base[offset++] = 0x4e800020; } //BCLR(R0, CR0, R0);
|
|
||||||
|
|
||||||
void MFCTR(GPR const rt) { MFSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
|
||||||
void MTCTR(GPR const rt) { MTSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
|
||||||
void BCTRL() { base[offset++] = 0x4e800421; } //BCCTRL(R0, CR0, R0);
|
|
||||||
void BCTR() { base[offset++] = 0x4e800420; } //BCCTR(R0, CR0, R0);
|
|
||||||
|
|
||||||
// TODO: PowerPC 11 stuff
|
|
||||||
void ISEL(GPR const rd, GPR const ra, GPR const rb, uint32_t d) {
|
|
||||||
(void)rd;
|
|
||||||
(void)ra;
|
|
||||||
(void)rb;
|
|
||||||
(void)d;
|
|
||||||
std::unreachable();
|
|
||||||
}
|
|
||||||
void ISELLT(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 0); }
|
|
||||||
void ISELGT(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 1); }
|
|
||||||
void ISELEQ(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 2); }
|
|
||||||
|
|
||||||
// Rawly pasted because fuck you
|
|
||||||
#include "powah_gen_base.hpp"
|
|
||||||
|
|
||||||
uint32_t* base = nullptr;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
uint32_t size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
Vendored
-487
@@ -1,487 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// this file is autogenerated DO NOT MODIFY
|
|
||||||
#pragma once
|
|
||||||
void ADD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, false, false); }
|
|
||||||
void ADDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, true, false); }
|
|
||||||
void ADD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, false, true); }
|
|
||||||
void ADDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, true, true); }
|
|
||||||
void ADDC(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, false, false); }
|
|
||||||
void ADDCO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, true, false); }
|
|
||||||
void ADDC_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, false, true); }
|
|
||||||
void ADDCO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, true, true); }
|
|
||||||
void ADDE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, false, false); }
|
|
||||||
void ADDEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, true, false); }
|
|
||||||
void ADDE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, false, true); }
|
|
||||||
void ADDEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, true, true); }
|
|
||||||
void ADDI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x38000000, rt, ra, d); }
|
|
||||||
void ADDIC(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x30000000, rt, ra, d); }
|
|
||||||
void ADDIC_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x34000000, rt, ra, d); }
|
|
||||||
void ADDIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x3c000000, rt, ra, d); }
|
|
||||||
void ADDME(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, false, false); }
|
|
||||||
void ADDMEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, true, false); }
|
|
||||||
void ADDME_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, false, true); }
|
|
||||||
void ADDMEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, true, true); }
|
|
||||||
void ADDZE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, false, false); }
|
|
||||||
void ADDZEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, true, false); }
|
|
||||||
void ADDZE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, false, true); }
|
|
||||||
void ADDZEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, true, true); }
|
|
||||||
void AND(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000038, ra, rt, rb, false); }
|
|
||||||
void AND_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000038, ra, rt, rb, true); }
|
|
||||||
void ANDC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000078, ra, rt, rb, false); }
|
|
||||||
void ANDC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000078, ra, rt, rb, true); }
|
|
||||||
void ANDI_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x70000000, ra, rt, d); }
|
|
||||||
void ANDIS_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x74000000, ra, rt, d); }
|
|
||||||
void B(Label const& i) { emit_reloc_I(0x48000000, i, false); }
|
|
||||||
void BL(Label const& i) { emit_reloc_I(0x48000000, i, true); }
|
|
||||||
void BC(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 0, cr.index + 0, i, false); }
|
|
||||||
void BCL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 0, cr.index + 0, i, true); }
|
|
||||||
void BLT(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 0, i, false); }
|
|
||||||
void BLTL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 0, i, true); }
|
|
||||||
void BLE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, false); }
|
|
||||||
void BLEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, true); }
|
|
||||||
void BNG(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, false); }
|
|
||||||
void BNGL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, true); }
|
|
||||||
void BEQ(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 2, i, false); }
|
|
||||||
void BEQL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 2, i, true); }
|
|
||||||
void BGE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, false); }
|
|
||||||
void BGEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, true); }
|
|
||||||
void BNL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, false); }
|
|
||||||
void BNLL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, true); }
|
|
||||||
void BGT(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 1, i, false); }
|
|
||||||
void BGTL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 1, i, true); }
|
|
||||||
void BNE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 2, i, false); }
|
|
||||||
void BNEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 2, i, true); }
|
|
||||||
void BSO(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, false); }
|
|
||||||
void BSOL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, true); }
|
|
||||||
void BUN(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, false); }
|
|
||||||
void BUNL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, true); }
|
|
||||||
void BNS(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 3, i, false); }
|
|
||||||
void BNSL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 3, i, true); }
|
|
||||||
void BCCTR(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, ba.index, bb.index, false); }
|
|
||||||
void BCCTRL(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, ba.index, bb.index, true); }
|
|
||||||
void BCCTR(GPR const bt, Cond const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, cond2offset(ba), bb.index, false); }
|
|
||||||
void BCCTRL(GPR const bt, Cond const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, cond2offset(ba), bb.index, true); }
|
|
||||||
void BCLR(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000020, bt.index, ba.index, bb.index, false); }
|
|
||||||
void BCLRL(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000020, bt.index, ba.index, bb.index, true); }
|
|
||||||
void BLTLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 0, 0, false); }
|
|
||||||
void BLTLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 0, 0, true); }
|
|
||||||
void BLELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, false); }
|
|
||||||
void BLELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, true); }
|
|
||||||
void BNGLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, false); }
|
|
||||||
void BNGLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, true); }
|
|
||||||
void BEQLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 2, 0, false); }
|
|
||||||
void BEQLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 2, 0, true); }
|
|
||||||
void BGELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, false); }
|
|
||||||
void BGELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, true); }
|
|
||||||
void BNLLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, false); }
|
|
||||||
void BNLLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, true); }
|
|
||||||
void BGTLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 1, 0, false); }
|
|
||||||
void BGTLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 1, 0, true); }
|
|
||||||
void BNELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 2, 0, false); }
|
|
||||||
void BNELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 2, 0, true); }
|
|
||||||
void BSOLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, false); }
|
|
||||||
void BSOLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, true); }
|
|
||||||
void BUNLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, false); }
|
|
||||||
void BUNLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, true); }
|
|
||||||
void BNSLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 3, 0, false); }
|
|
||||||
void BNSLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 3, 0, true); }
|
|
||||||
void CMP(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) { emit_X(0x7c000000, GPR{(bf << 2) | l}, ra, rb, false); }
|
|
||||||
void CMPI(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) { emit_D(0x2c000000, GPR{(bf << 2) | l}, ra, d); }
|
|
||||||
void CMPL(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) { emit_X(0x7c000040, GPR{(bf << 2) | l}, ra, rb, false); }
|
|
||||||
void CMPLI(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) { emit_D(0x28000000, GPR{(bf << 2) | l}, ra, d); }
|
|
||||||
void CNTLZD(GPR const rt, GPR const ra) { emit_X(0x7c000074, ra, rt, R0, false); }
|
|
||||||
void CNTLZD_(GPR const rt, GPR const ra) { emit_X(0x7c000074, ra, rt, R0, true); }
|
|
||||||
void CNTLZW(GPR const rt, GPR const ra) { emit_X(0x7c000034, ra, rt, R0, false); }
|
|
||||||
void CNTLZW_(GPR const rt, GPR const ra) { emit_X(0x7c000034, ra, rt, R0, true); }
|
|
||||||
void CRAND(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000202, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRANDL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000202, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRANDC(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000102, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRANDCL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000102, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CREQV(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000242, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CREQVL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000242, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRNAND(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c0001c2, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRNANDL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c0001c2, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRNOR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000042, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRNORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000042, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CROR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000382, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000382, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRORC(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000342, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRORCL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000342, bt.index, ba.index, bb.index, true); }
|
|
||||||
void CRXOR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000182, bt.index, ba.index, bb.index, false); }
|
|
||||||
void CRXORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000182, bt.index, ba.index, bb.index, true); }
|
|
||||||
void DCBF(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ac, ra, rt, rb, false); }
|
|
||||||
void DCBF_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ac, ra, rt, rb, true); }
|
|
||||||
void DCBI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003ac, ra, rt, rb, false); }
|
|
||||||
void DCBI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003ac, ra, rt, rb, true); }
|
|
||||||
void DCBST(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006c, ra, rt, rb, false); }
|
|
||||||
void DCBST_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006c, ra, rt, rb, true); }
|
|
||||||
void DCBT(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022c, ra, rt, rb, false); }
|
|
||||||
void DCBT_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022c, ra, rt, rb, true); }
|
|
||||||
void DCBTST(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ec, ra, rt, rb, false); }
|
|
||||||
void DCBTST_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ec, ra, rt, rb, true); }
|
|
||||||
void DCBZ(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ec, ra, rt, rb, false); }
|
|
||||||
void DCBZ_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ec, ra, rt, rb, true); }
|
|
||||||
void DIVD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, false, false); }
|
|
||||||
void DIVDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, true, false); }
|
|
||||||
void DIVD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, false, true); }
|
|
||||||
void DIVDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, true, true); }
|
|
||||||
void DIVDU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, false, false); }
|
|
||||||
void DIVDUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, true, false); }
|
|
||||||
void DIVDU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, false, true); }
|
|
||||||
void DIVDUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, true, true); }
|
|
||||||
void DIVW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, false, false); }
|
|
||||||
void DIVWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, true, false); }
|
|
||||||
void DIVW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, false, true); }
|
|
||||||
void DIVWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, true, true); }
|
|
||||||
void DIVWU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, false, false); }
|
|
||||||
void DIVWUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, true, false); }
|
|
||||||
void DIVWU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, false, true); }
|
|
||||||
void DIVWUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, true, true); }
|
|
||||||
void ECIWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00026c, ra, rt, rb, false); }
|
|
||||||
void ECIWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00026c, ra, rt, rb, true); }
|
|
||||||
void ECOWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036c, ra, rt, rb, false); }
|
|
||||||
void ECOWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036c, ra, rt, rb, true); }
|
|
||||||
void EIEIO(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0006ac, ra, rt, rb, false); }
|
|
||||||
void EIEIO_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0006ac, ra, rt, rb, true); }
|
|
||||||
void EQV(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000238, ra, rt, rb, false); }
|
|
||||||
void EQV_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000238, ra, rt, rb, true); }
|
|
||||||
void EXTSB(GPR const rt, GPR const ra) { emit_X(0x7c000774, ra, rt, R0, false); }
|
|
||||||
void EXTSB_(GPR const rt, GPR const ra) { emit_X(0x7c000774, ra, rt, R0, true); }
|
|
||||||
void EXTSH(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, false, false); }
|
|
||||||
void EXTSHC(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, true, false); }
|
|
||||||
void EXTSH_(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, false, true); }
|
|
||||||
void EXTSHC_(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, true, true); }
|
|
||||||
void EXTSW(GPR const rt, GPR const ra) { emit_X(0x7c0007b4, ra, rt, R0, false); }
|
|
||||||
void EXTSW_(GPR const rt, GPR const ra) { emit_X(0x7c0007b4, ra, rt, R0, true); }
|
|
||||||
void FABS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000210, ra, rt, rb, false); }
|
|
||||||
void FABS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000210, ra, rt, rb, true); }
|
|
||||||
void FADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002a, frt, fra, frb, frc, false); }
|
|
||||||
void FADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002a, frt, fra, frb, frc, true); }
|
|
||||||
void FADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00002a, frt, fra, frb, frc, false); }
|
|
||||||
void FADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00002a, frt, fra, frb, frc, true); }
|
|
||||||
void FCFID(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00069c, ra, rt, rb, false); }
|
|
||||||
void FCFID_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00069c, ra, rt, rb, true); }
|
|
||||||
void FCMPO(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000040, ra, rt, rb, false); }
|
|
||||||
void FCMPO_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000040, ra, rt, rb, true); }
|
|
||||||
void FCMPU(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc000000, bt.index, ba.index, bb.index, false); }
|
|
||||||
void FCMPUL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc000000, bt.index, ba.index, bb.index, true); }
|
|
||||||
void FCTID(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065c, ra, rt, rb, false); }
|
|
||||||
void FCTID_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065c, ra, rt, rb, true); }
|
|
||||||
void FCTIDZ(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065e, ra, rt, rb, false); }
|
|
||||||
void FCTIDZ_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065e, ra, rt, rb, true); }
|
|
||||||
void FCTIW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00001c, ra, rt, rb, false); }
|
|
||||||
void FCTIW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00001c, ra, rt, rb, true); }
|
|
||||||
void FCTIWZ(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc00001e, bt.index, ba.index, bb.index, false); }
|
|
||||||
void FCTIWZL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc00001e, bt.index, ba.index, bb.index, true); }
|
|
||||||
void FDIV(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000024, frt, fra, frb, frc, false); }
|
|
||||||
void FDIV_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000024, frt, fra, frb, frc, true); }
|
|
||||||
void FDIVS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000024, frt, fra, frb, frc, false); }
|
|
||||||
void FDIVS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000024, frt, fra, frb, frc, true); }
|
|
||||||
void FMADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003a, frt, fra, frb, frc, false); }
|
|
||||||
void FMADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003a, frt, fra, frb, frc, true); }
|
|
||||||
void FMADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003a, frt, fra, frb, frc, false); }
|
|
||||||
void FMADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003a, frt, fra, frb, frc, true); }
|
|
||||||
void FMR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000090, ra, rt, rb, false); }
|
|
||||||
void FMR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000090, ra, rt, rb, true); }
|
|
||||||
void FMSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000038, frt, fra, frb, frc, false); }
|
|
||||||
void FMSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000038, frt, fra, frb, frc, true); }
|
|
||||||
void FMSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000038, frt, fra, frb, frc, false); }
|
|
||||||
void FMSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000038, frt, fra, frb, frc, true); }
|
|
||||||
void FMUL(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000032, frt, fra, frb, frc, false); }
|
|
||||||
void FMUL_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000032, frt, fra, frb, frc, true); }
|
|
||||||
void FMULS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000032, frt, fra, frb, frc, false); }
|
|
||||||
void FMULS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000032, frt, fra, frb, frc, true); }
|
|
||||||
void FNABS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000110, ra, rt, rb, false); }
|
|
||||||
void FNABS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000110, ra, rt, rb, true); }
|
|
||||||
void FNEG(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000050, ra, rt, rb, false); }
|
|
||||||
void FNEG_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000050, ra, rt, rb, true); }
|
|
||||||
void FNMADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003e, frt, fra, frb, frc, false); }
|
|
||||||
void FNMADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003e, frt, fra, frb, frc, true); }
|
|
||||||
void FNMADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003e, frt, fra, frb, frc, false); }
|
|
||||||
void FNMADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003e, frt, fra, frb, frc, true); }
|
|
||||||
void FNMSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003c, frt, fra, frb, frc, false); }
|
|
||||||
void FNMSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003c, frt, fra, frb, frc, true); }
|
|
||||||
void FNMSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003c, frt, fra, frb, frc, false); }
|
|
||||||
void FNMSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003c, frt, fra, frb, frc, true); }
|
|
||||||
void FRES(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000030, frt, fra, frb, frc, false); }
|
|
||||||
void FRES_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000030, frt, fra, frb, frc, true); }
|
|
||||||
void FRSP(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000018, ra, rt, rb, false); }
|
|
||||||
void FRSP_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000018, ra, rt, rb, true); }
|
|
||||||
void FRSQRTE(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000034, frt, fra, frb, frc, false); }
|
|
||||||
void FRSQRTE_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000034, frt, fra, frb, frc, true); }
|
|
||||||
void FSEL(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002e, frt, fra, frb, frc, false); }
|
|
||||||
void FSEL_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002e, frt, fra, frb, frc, true); }
|
|
||||||
void FSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000028, frt, fra, frb, frc, false); }
|
|
||||||
void FSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000028, frt, fra, frb, frc, true); }
|
|
||||||
void FSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000028, frt, fra, frb, frc, false); }
|
|
||||||
void FSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000028, frt, fra, frb, frc, true); }
|
|
||||||
void ICBI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ac, ra, rt, rb, false); }
|
|
||||||
void ICBI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ac, ra, rt, rb, true); }
|
|
||||||
void ISYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c00012c, ra, rt, rb, false); }
|
|
||||||
void ISYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c00012c, ra, rt, rb, true); }
|
|
||||||
void LBZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x88000000, rt, ra, d); }
|
|
||||||
void LBZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x8c000000, rt, ra, d); }
|
|
||||||
void LBZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ee, ra, rt, rb, false); }
|
|
||||||
void LBZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ee, ra, rt, rb, true); }
|
|
||||||
void LBZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ae, ra, rt, rb, false); }
|
|
||||||
void LBZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ae, ra, rt, rb, true); }
|
|
||||||
void LD(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000000, rt, ra, d >> 2); }
|
|
||||||
void LDARX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a8, ra, rt, rb, false); }
|
|
||||||
void LDARX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a8, ra, rt, rb, true); }
|
|
||||||
void LDU(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000001, rt, ra, d >> 2); }
|
|
||||||
void LDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006a, ra, rt, rb, false); }
|
|
||||||
void LDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006a, ra, rt, rb, true); }
|
|
||||||
void LDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002a, ra, rt, rb, false); }
|
|
||||||
void LDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002a, ra, rt, rb, true); }
|
|
||||||
void LFD(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc8000000, rt, ra, d); }
|
|
||||||
void LFDU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xcc000000, rt, ra, d); }
|
|
||||||
void LFDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ee, ra, rt, rb, false); }
|
|
||||||
void LFDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ee, ra, rt, rb, true); }
|
|
||||||
void LFDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ae, ra, rt, rb, false); }
|
|
||||||
void LFDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ae, ra, rt, rb, true); }
|
|
||||||
void LFS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc0000000, rt, ra, d); }
|
|
||||||
void LFSU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc4000000, rt, ra, d); }
|
|
||||||
void LFSUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046e, ra, rt, rb, false); }
|
|
||||||
void LFSUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046e, ra, rt, rb, true); }
|
|
||||||
void LFSX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042e, ra, rt, rb, false); }
|
|
||||||
void LFSX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042e, ra, rt, rb, true); }
|
|
||||||
void LHA(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa8000000, rt, ra, d); }
|
|
||||||
void LHAU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xac000000, rt, ra, d); }
|
|
||||||
void LHAUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ee, ra, rt, rb, false); }
|
|
||||||
void LHAUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ee, ra, rt, rb, true); }
|
|
||||||
void LHAX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ae, ra, rt, rb, false); }
|
|
||||||
void LHAX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ae, ra, rt, rb, true); }
|
|
||||||
void LHBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00062c, ra, rt, rb, false); }
|
|
||||||
void LHBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00062c, ra, rt, rb, true); }
|
|
||||||
void LHZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa0000000, rt, ra, d); }
|
|
||||||
void LHZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa4000000, rt, ra, d); }
|
|
||||||
void LHZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000296, ra, rt, rb, false); }
|
|
||||||
void LHZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000296, ra, rt, rb, true); }
|
|
||||||
void LHZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022e, ra, rt, rb, false); }
|
|
||||||
void LHZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022e, ra, rt, rb, true); }
|
|
||||||
void LMW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb8000000, rt, ra, d); }
|
|
||||||
void LSWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004aa, ra, rt, rb, false); }
|
|
||||||
void LSWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004aa, ra, rt, rb, true); }
|
|
||||||
void LSWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042a, ra, rt, rb, false); }
|
|
||||||
void LSWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042a, ra, rt, rb, true); }
|
|
||||||
void LWA(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000002, rt, ra, d >> 2); }
|
|
||||||
void LWARX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000028, ra, rt, rb, false); }
|
|
||||||
void LWARX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000028, ra, rt, rb, true); }
|
|
||||||
void LWAUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ea, ra, rt, rb, false); }
|
|
||||||
void LWAUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ea, ra, rt, rb, true); }
|
|
||||||
void LWAX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002aa, ra, rt, rb, false); }
|
|
||||||
void LWAX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002aa, ra, rt, rb, true); }
|
|
||||||
void LWBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042c, ra, rt, rb, false); }
|
|
||||||
void LWBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042c, ra, rt, rb, true); }
|
|
||||||
void LWZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x80000000, rt, ra, d); }
|
|
||||||
void LWZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x84000000, rt, ra, d); }
|
|
||||||
void LWZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006e, ra, rt, rb, false); }
|
|
||||||
void LWZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006e, ra, rt, rb, true); }
|
|
||||||
void LWZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002e, ra, rt, rb, false); }
|
|
||||||
void LWZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002e, ra, rt, rb, true); }
|
|
||||||
void MCRF(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000000, bt.index, ba.index, bb.index, false); }
|
|
||||||
void MCRFL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000000, bt.index, ba.index, bb.index, true); }
|
|
||||||
void MCRFS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000080, ra, rt, rb, false); }
|
|
||||||
void MCRFS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000080, ra, rt, rb, true); }
|
|
||||||
void MCRXR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000400, ra, rt, rb, false); }
|
|
||||||
void MCRXR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000400, ra, rt, rb, true); }
|
|
||||||
void MFCR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000026, ra, rt, rb, false); }
|
|
||||||
void MFCR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000026, ra, rt, rb, true); }
|
|
||||||
void MFFS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00048e, ra, rt, rb, false); }
|
|
||||||
void MFFS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00048e, ra, rt, rb, true); }
|
|
||||||
void MFMSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a6, ra, rt, rb, false); }
|
|
||||||
void MFMSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a6, ra, rt, rb, true); }
|
|
||||||
void MFSPR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002a6, ra, rt, rb, false); }
|
|
||||||
void MFSPR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002a6, ra, rt, rb, true); }
|
|
||||||
void MFSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004a6, ra, rt, rb, false); }
|
|
||||||
void MFSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004a6, ra, rt, rb, true); }
|
|
||||||
void MFSRIN(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000526, ra, rt, rb, false); }
|
|
||||||
void MFSRIN_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000526, ra, rt, rb, true); }
|
|
||||||
void MTCRF(GPR const rt, uint32_t spr) { emit_XFX(0x7c000120, rt, spr); }
|
|
||||||
void MTFSB0(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00008c, ra, rt, rb, false); }
|
|
||||||
void MTFSB0_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00008c, ra, rt, rb, true); }
|
|
||||||
void MTFSB1(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00004c, ra, rt, rb, false); }
|
|
||||||
void MTFSB1_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00004c, ra, rt, rb, true); }
|
|
||||||
void MTFSF() { emit_XFL(0xfc00058e); }
|
|
||||||
void MTFSFI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00010c, ra, rt, rb, false); }
|
|
||||||
void MTFSFI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00010c, ra, rt, rb, true); }
|
|
||||||
void MTMSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000124, ra, rt, rb, false); }
|
|
||||||
void MTMSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000124, ra, rt, rb, true); }
|
|
||||||
void MTSPR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003a6, ra, rt, rb, false); }
|
|
||||||
void MTSPR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003a6, ra, rt, rb, true); }
|
|
||||||
void MTSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001a4, ra, rt, rb, false); }
|
|
||||||
void MTSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001a4, ra, rt, rb, true); }
|
|
||||||
void MTSRIN(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001e4, ra, rt, rb, false); }
|
|
||||||
void MTSRIN_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001e4, ra, rt, rb, true); }
|
|
||||||
void MULHD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, false, false); }
|
|
||||||
void MULHDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, true, false); }
|
|
||||||
void MULHD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, false, true); }
|
|
||||||
void MULHDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, true, true); }
|
|
||||||
void MULHDU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, false, false); }
|
|
||||||
void MULHDUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, true, false); }
|
|
||||||
void MULHDU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, false, true); }
|
|
||||||
void MULHDUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, true, true); }
|
|
||||||
void MULHW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, false, false); }
|
|
||||||
void MULHWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, true, false); }
|
|
||||||
void MULHW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, false, true); }
|
|
||||||
void MULHWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, true, true); }
|
|
||||||
void MULHWU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, false, false); }
|
|
||||||
void MULHWUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, true, false); }
|
|
||||||
void MULHWU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, false, true); }
|
|
||||||
void MULHWUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, true, true); }
|
|
||||||
void MULLD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, false, false); }
|
|
||||||
void MULLDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, true, false); }
|
|
||||||
void MULLD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, false, true); }
|
|
||||||
void MULLDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, true, true); }
|
|
||||||
void MULLI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x1c000000, rt, ra, d); }
|
|
||||||
void MULLW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, false, false); }
|
|
||||||
void MULLWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, true, false); }
|
|
||||||
void MULLW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, false, true); }
|
|
||||||
void MULLWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, true, true); }
|
|
||||||
void NAND(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003b8, ra, rt, rb, false); }
|
|
||||||
void NAND_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003b8, ra, rt, rb, true); }
|
|
||||||
void NEG(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, false, false); }
|
|
||||||
void NEGO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, true, false); }
|
|
||||||
void NEG_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, false, true); }
|
|
||||||
void NEGO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, true, true); }
|
|
||||||
void NOR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000f8, ra, rt, rb, false); }
|
|
||||||
void NOR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000f8, ra, rt, rb, true); }
|
|
||||||
void OR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000378, ra, rt, rb, false); }
|
|
||||||
void OR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000378, ra, rt, rb, true); }
|
|
||||||
void ORC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000338, ra, rt, rb, false); }
|
|
||||||
void ORC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000338, ra, rt, rb, true); }
|
|
||||||
void ORI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x60000000, ra, rt, d); }
|
|
||||||
void ORIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x64000000, ra, rt, d); }
|
|
||||||
void RFI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c000064, ra, rt, rb, false); }
|
|
||||||
void RFI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c000064, ra, rt, rb, true); }
|
|
||||||
void RLDCL(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000010, ra, rs, rb, mb, false); }
|
|
||||||
void RLDCL_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000010, ra, rs, rb, mb, true); }
|
|
||||||
void RLDCR(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000012, ra, rs, rb, mb, false); }
|
|
||||||
void RLDCR_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000012, ra, rs, rb, mb, true); }
|
|
||||||
void RLDIC(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000008, ra, rs, mb, sh, false); }
|
|
||||||
void RLDIC_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000008, ra, rs, mb, sh, true); }
|
|
||||||
void RLDICL(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000000, ra, rs, mb, sh, false); }
|
|
||||||
void RLDICL_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000000, ra, rs, mb, sh, true); }
|
|
||||||
void RLDICR(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000004, ra, rs, mb, sh, false); }
|
|
||||||
void RLDICR_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000004, ra, rs, mb, sh, true); }
|
|
||||||
void RLDIMI(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x7800000c, ra, rs, mb, sh, false); }
|
|
||||||
void RLDIMI_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x7800000c, ra, rs, mb, sh, true); }
|
|
||||||
void RLWIMI(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x50000000, ra, rs, sh, mb, me, false); }
|
|
||||||
void RLWIMI_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x50000000, ra, rs, sh, mb, me, true); }
|
|
||||||
void RLWINM(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x54000000, ra, rs, sh, mb, me, false); }
|
|
||||||
void RLWINM_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x54000000, ra, rs, sh, mb, me, true); }
|
|
||||||
void RLWNM(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) { emit_M(0x5c000000, ra, rs, rb.index, mb, me, false); }
|
|
||||||
void RLWNM_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) { emit_M(0x5c000000, ra, rs, rb.index, mb, me, true); }
|
|
||||||
void SC(uint32_t lev) { emit_SC(0x44000000, lev); }
|
|
||||||
void SI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x30000000, rt, ra, d); }
|
|
||||||
void SI_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x34000000, rt, ra, d); }
|
|
||||||
void SLBIA(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003e4, ra, rt, rb, false); }
|
|
||||||
void SLBIA_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003e4, ra, rt, rb, true); }
|
|
||||||
void SLBIE(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000364, ra, rt, rb, false); }
|
|
||||||
void SLBIE_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000364, ra, rt, rb, true); }
|
|
||||||
void SLD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000036, ra, rt, rb, false); }
|
|
||||||
void SLD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000036, ra, rt, rb, true); }
|
|
||||||
void SLW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000030, ra, rt, rb, false); }
|
|
||||||
void SLW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000030, ra, rt, rb, true); }
|
|
||||||
void SRAD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000634, ra, rt, rb, false); }
|
|
||||||
void SRAD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000634, ra, rt, rb, true); }
|
|
||||||
void SRADI(GPR const rt, GPR const ra, uint32_t sh) { emit_XS(0x7c000674, rt, ra, sh, false); }
|
|
||||||
void SRADI_(GPR const rt, GPR const ra, uint32_t sh) { emit_XS(0x7c000674, rt, ra, sh, true); }
|
|
||||||
void SRD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000436, ra, rt, rb, false); }
|
|
||||||
void SRD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000436, ra, rt, rb, true); }
|
|
||||||
void SRAW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000630, ra, rt, rb, false); }
|
|
||||||
void SRAW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000630, ra, rt, rb, true); }
|
|
||||||
void SRAWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000670, ra, rt, rb, false); }
|
|
||||||
void SRAWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000670, ra, rt, rb, true); }
|
|
||||||
void SRW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000430, ra, rt, rb, false); }
|
|
||||||
void SRW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000430, ra, rt, rb, true); }
|
|
||||||
void STB(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x98000000, rt, ra, d); }
|
|
||||||
void STBU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x9c000000, rt, ra, d); }
|
|
||||||
void STBUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ee, ra, rt, rb, false); }
|
|
||||||
void STBUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ee, ra, rt, rb, true); }
|
|
||||||
void STBX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ae, ra, rt, rb, false); }
|
|
||||||
void STBX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ae, ra, rt, rb, true); }
|
|
||||||
void STD(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xf8000000, rt, ra, d >> 2); }
|
|
||||||
void STDCX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ac, ra, rt, rb, false); }
|
|
||||||
void STDCX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ac, ra, rt, rb, true); }
|
|
||||||
void STDU(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xf8000001, rt, ra, d >> 2); }
|
|
||||||
void STDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016a, ra, rt, rb, false); }
|
|
||||||
void STDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016a, ra, rt, rb, true); }
|
|
||||||
void STDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012a, ra, rt, rb, false); }
|
|
||||||
void STDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012a, ra, rt, rb, true); }
|
|
||||||
void STFD(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd8000000, rt, ra, d); }
|
|
||||||
void STFDU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xdc000000, rt, ra, d); }
|
|
||||||
void STFDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ee, ra, rt, rb, false); }
|
|
||||||
void STFDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ee, ra, rt, rb, true); }
|
|
||||||
void STFDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ae, ra, rt, rb, false); }
|
|
||||||
void STFDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ae, ra, rt, rb, true); }
|
|
||||||
void STFIWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ae, ra, rt, rb, false); }
|
|
||||||
void STFIWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ae, ra, rt, rb, true); }
|
|
||||||
void STFS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd0000000, rt, ra, d); }
|
|
||||||
void STFSU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd4000000, rt, ra, d); }
|
|
||||||
void STFSUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00056e, ra, rt, rb, false); }
|
|
||||||
void STFSUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00056e, ra, rt, rb, true); }
|
|
||||||
void STFSX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052e, ra, rt, rb, false); }
|
|
||||||
void STFSX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052e, ra, rt, rb, true); }
|
|
||||||
void STH(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb0000000, rt, ra, d); }
|
|
||||||
void STHBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00072c, ra, rt, rb, false); }
|
|
||||||
void STHBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00072c, ra, rt, rb, true); }
|
|
||||||
void STHU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb4000000, rt, ra, d); }
|
|
||||||
void STHUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036e, ra, rt, rb, false); }
|
|
||||||
void STHUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036e, ra, rt, rb, true); }
|
|
||||||
void STHX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00032e, ra, rt, rb, false); }
|
|
||||||
void STHX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00032e, ra, rt, rb, true); }
|
|
||||||
void STMW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xbc000000, rt, ra, d); }
|
|
||||||
void STSWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005aa, ra, rt, rb, false); }
|
|
||||||
void STSWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005aa, ra, rt, rb, true); }
|
|
||||||
void STSWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052a, ra, rt, rb, false); }
|
|
||||||
void STSWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052a, ra, rt, rb, true); }
|
|
||||||
void STW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x90000000, rt, ra, d); }
|
|
||||||
void STWBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052c, ra, rt, rb, false); }
|
|
||||||
void STWBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052c, ra, rt, rb, true); }
|
|
||||||
void STWCX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012c, ra, rt, rb, false); }
|
|
||||||
void STWCX__(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012c, ra, rt, rb, true); }
|
|
||||||
void STWU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x94000000, rt, ra, d); }
|
|
||||||
void STWUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016e, ra, rt, rb, false); }
|
|
||||||
void STWUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016e, ra, rt, rb, true); }
|
|
||||||
void STWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012e, ra, rt, rb, false); }
|
|
||||||
void STWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012e, ra, rt, rb, true); }
|
|
||||||
void SUBF(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, false, false); }
|
|
||||||
void SUBFO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, true, false); }
|
|
||||||
void SUBF_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, false, true); }
|
|
||||||
void SUBFO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, true, true); }
|
|
||||||
void SUBFC(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, false, false); }
|
|
||||||
void SUBFCO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, true, false); }
|
|
||||||
void SUBFC_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, false, true); }
|
|
||||||
void SUBFCO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, true, true); }
|
|
||||||
void SUBFE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, false, false); }
|
|
||||||
void SUBFEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, true, false); }
|
|
||||||
void SUBFE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, false, true); }
|
|
||||||
void SUBFEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, true, true); }
|
|
||||||
void SUBFIC(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x20000000, rt, ra, d); }
|
|
||||||
void SUBFME(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, false, false); }
|
|
||||||
void SUBFMEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, true, false); }
|
|
||||||
void SUBFME_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, false, true); }
|
|
||||||
void SUBFMEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, true, true); }
|
|
||||||
void SUBFZE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, false, false); }
|
|
||||||
void SUBFZEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, true, false); }
|
|
||||||
void SUBFZE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, false, true); }
|
|
||||||
void SUBFZEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, true, true); }
|
|
||||||
void SYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ac, ra, rt, rb, false); }
|
|
||||||
void SYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ac, ra, rt, rb, true); }
|
|
||||||
void TD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000088, ra, rt, rb, false); }
|
|
||||||
void TD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000088, ra, rt, rb, true); }
|
|
||||||
void TDI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x08000000, rt, ra, d); }
|
|
||||||
void TLBIE(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000264, ra, rt, rb, false); }
|
|
||||||
void TLBIE_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000264, ra, rt, rb, true); }
|
|
||||||
void TLBSYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046c, ra, rt, rb, false); }
|
|
||||||
void TLBSYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046c, ra, rt, rb, true); }
|
|
||||||
void TW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000008, ra, rt, rb, false); }
|
|
||||||
void TW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000008, ra, rt, rb, true); }
|
|
||||||
void TWI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x0c000000, rt, ra, d); }
|
|
||||||
void XOR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000278, ra, rt, rb, false); }
|
|
||||||
void XOR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000278, ra, rt, rb, true); }
|
|
||||||
void XORI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x68000000, ra, rt, d); }
|
|
||||||
void XORIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x6c000000, ra, rt, d); }
|
|
||||||
Vendored
-340
@@ -1,340 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include "powah_emit.hpp"
|
|
||||||
|
|
||||||
#define EB32(X) __bswap32(X)
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: addi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
|
|
||||||
ctx.ADDI(powah::R2, powah::R2, 0);
|
|
||||||
ctx.ADDIS(powah::R2, powah::R12, 0);
|
|
||||||
REQUIRE(data[0] == EB32(0x00004238));
|
|
||||||
REQUIRE(data[1] == EB32(0x00004c3c));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: std/mr", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
|
|
||||||
ctx.STD(powah::R26, powah::R1, 144);
|
|
||||||
ctx.MR(powah::R26, powah::R4);
|
|
||||||
ctx.STD(powah::R30, powah::R1, 176);
|
|
||||||
ctx.MR(powah::R30, powah::R3);
|
|
||||||
ctx.RLDICR(powah::R4, powah::R5, 25, 6);
|
|
||||||
ctx.STD(powah::R28, powah::R1, 160);
|
|
||||||
REQUIRE(data[0] == EB32(0x900041fb));
|
|
||||||
REQUIRE(data[1] == EB32(0x78239a7c));
|
|
||||||
REQUIRE(data[2] == EB32(0xb000c1fb));
|
|
||||||
REQUIRE(data[3] == EB32(0x781b7e7c));
|
|
||||||
REQUIRE(data[4] == EB32(0x84c9a478));
|
|
||||||
REQUIRE(data[5] == EB32(0xa00081fb));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: sldi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
|
|
||||||
ctx.SLDI(powah::R3, powah::R5, 37);
|
|
||||||
REQUIRE(data[0] == EB32(0x862ea378));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: rldicr", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 0, 0);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 1, 0);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 0, 1);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 1, 1);
|
|
||||||
ctx.RLDICR(powah::R1, powah::R1, 31, 31);
|
|
||||||
REQUIRE(data[0] == EB32(0x04002178));
|
|
||||||
REQUIRE(data[1] == EB32(0x04082178));
|
|
||||||
REQUIRE(data[2] == EB32(0x44002178));
|
|
||||||
REQUIRE(data[3] == EB32(0x44082178));
|
|
||||||
REQUIRE(data[4] == EB32(0xc4ff2178));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: mr/or/std", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.MR(powah::R27, powah::R7);
|
|
||||||
ctx.MR(powah::R29, powah::R6);
|
|
||||||
ctx.OR(powah::R3, powah::R3, powah::R4);
|
|
||||||
ctx.MR(powah::R4, powah::R28);
|
|
||||||
ctx.CRMOVE(powah::CPR{8}, powah::CPR{1});
|
|
||||||
ctx.MR(powah::R25, powah::R5);
|
|
||||||
ctx.OR(powah::R3, powah::R3, powah::R26);
|
|
||||||
ctx.STD(powah::R3, powah::R1, 56);
|
|
||||||
ctx.MR(powah::R3, powah::R30);
|
|
||||||
REQUIRE(data[0] == EB32(0x783bfb7c));
|
|
||||||
REQUIRE(data[1] == EB32(0x7833dd7c));
|
|
||||||
REQUIRE(data[2] == EB32(0x7823637c));
|
|
||||||
REQUIRE(data[3] == EB32(0x78e3847f));
|
|
||||||
REQUIRE(data[4] == EB32(0x820b014d));
|
|
||||||
REQUIRE(data[5] == EB32(0x782bb97c));
|
|
||||||
REQUIRE(data[6] == EB32(0x78d3637c));
|
|
||||||
REQUIRE(data[7] == EB32(0x380061f8));
|
|
||||||
REQUIRE(data[8] == EB32(0x78f3c37f));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: ld/crand+addi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.LD(powah::R4, powah::R1, 72);
|
|
||||||
ctx.LWZ(powah::R5, powah::R1, 80);
|
|
||||||
ctx.CRAND(powah::CPR{20}, powah::CPR{10}, powah::CPR{9});
|
|
||||||
ctx.ADDI(powah::R6, powah::R4, 4);
|
|
||||||
ctx.ANDIS_(powah::R4, powah::R5, 1992);
|
|
||||||
ctx.LD(powah::R5, powah::R30, 1984);
|
|
||||||
ctx.LBZ(powah::R3, powah::R1, 84);
|
|
||||||
ctx.CLRLDI(powah::R26, powah::R6, 8);
|
|
||||||
ctx.STW(powah::R4, powah::R1, 80);
|
|
||||||
ctx.ADDI(powah::R5, powah::R5, 1);
|
|
||||||
ctx.STD(powah::R26, powah::R1, 72);
|
|
||||||
ctx.STD(powah::R5, powah::R30, 1984);
|
|
||||||
REQUIRE(data[0] == EB32(0x480081e8));
|
|
||||||
REQUIRE(data[1] == EB32(0x5000a180));
|
|
||||||
REQUIRE(data[2] == EB32(0x024a8a4e));
|
|
||||||
REQUIRE(data[3] == EB32(0x0400c438));
|
|
||||||
REQUIRE(data[4] == EB32(0xc807a474));
|
|
||||||
REQUIRE(data[5] == EB32(0xc007bee8));
|
|
||||||
REQUIRE(data[6] == EB32(0x54006188));
|
|
||||||
REQUIRE(data[7] == EB32(0x0002da78));
|
|
||||||
REQUIRE(data[8] == EB32(0x50008190));
|
|
||||||
REQUIRE(data[9] == EB32(0x0100a538));
|
|
||||||
REQUIRE(data[10] == EB32(0x480041fb));
|
|
||||||
REQUIRE(data[11] == EB32(0xc007bef8));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: rotldi", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 16);
|
|
||||||
ctx.ROTLDI(powah::R4, powah::R3, 8);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 8, 48);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 24);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 16, 40);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 32);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 24, 32);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 48);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 40, 16);
|
|
||||||
ctx.ROTLDI(powah::R5, powah::R3, 56);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R5, 48, 8);
|
|
||||||
ctx.RLDIMI(powah::R4, powah::R3, 56, 0);
|
|
||||||
ctx.MR(powah::R3, powah::R4);
|
|
||||||
REQUIRE(data[0] == EB32(0x00806578));
|
|
||||||
REQUIRE(data[1] == EB32(0x00406478));
|
|
||||||
REQUIRE(data[2] == EB32(0x2c44a478));
|
|
||||||
REQUIRE(data[3] == EB32(0x00c06578));
|
|
||||||
REQUIRE(data[4] == EB32(0x2c82a478));
|
|
||||||
REQUIRE(data[5] == EB32(0x02006578));
|
|
||||||
REQUIRE(data[6] == EB32(0x2cc0a478));
|
|
||||||
REQUIRE(data[7] == EB32(0x02806578));
|
|
||||||
REQUIRE(data[8] == EB32(0x0e44a478));
|
|
||||||
REQUIRE(data[9] == EB32(0x02c06578));
|
|
||||||
REQUIRE(data[10] == EB32(0x0e82a478));
|
|
||||||
REQUIRE(data[11] == EB32(0x0ec06478));
|
|
||||||
REQUIRE(data[12] == EB32(0x7823837c));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: branch-backwards", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
powah::Label l_3 = ctx.DefineLabel();
|
|
||||||
ctx.LABEL(l_3);
|
|
||||||
ctx.ADD(powah::R1, powah::R2, powah::R3);
|
|
||||||
ctx.B(l_3);
|
|
||||||
ctx.ApplyRelocs();
|
|
||||||
REQUIRE(data[0] == EB32(0x141a227c));
|
|
||||||
REQUIRE(data[1] == EB32(0xfcffff4b));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: rlwimi madness", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.ROTLWI(powah::R10, powah::R3, 24);
|
|
||||||
ctx.SRDI(powah::R9, powah::R3, 32);
|
|
||||||
ctx.RLWIMI(powah::R10, powah::R3, 8, 8, 15);
|
|
||||||
ctx.RLWIMI(powah::R10, powah::R3, 8, 24, 31);
|
|
||||||
ctx.ROTLWI(powah::R3, powah::R9, 24);
|
|
||||||
ctx.RLWIMI(powah::R3, powah::R9, 8, 8, 15);
|
|
||||||
ctx.RLWIMI(powah::R3, powah::R9, 8, 24, 31);
|
|
||||||
ctx.RLDIMI(powah::R3, powah::R10, 32, 0);
|
|
||||||
REQUIRE(data[0] == EB32(0x3ec06a54));
|
|
||||||
REQUIRE(data[1] == EB32(0x22006978));
|
|
||||||
REQUIRE(data[2] == EB32(0x1e426a50));
|
|
||||||
REQUIRE(data[3] == EB32(0x3e466a50));
|
|
||||||
REQUIRE(data[4] == EB32(0x3ec02355));
|
|
||||||
REQUIRE(data[5] == EB32(0x1e422351));
|
|
||||||
REQUIRE(data[6] == EB32(0x3e462351));
|
|
||||||
REQUIRE(data[7] == EB32(0x0e004379));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
0: 78 1b 68 7c mr 8, 3
|
|
||||||
4: 38 28 83 7c and 3, 4, 5
|
|
||||||
8: 74 00 6a 7c cntlzd 10, 3
|
|
||||||
c: 76 06 69 7c sradi 9, 3, 32
|
|
||||||
10: 82 d1 4a 79 rldicl 10, 10, 58, 6
|
|
||||||
14: 00 00 29 55 rlwinm 9, 9, 0, 0, 0
|
|
||||||
18: 64 f0 4a 79 sldi 10, 10, 30
|
|
||||||
1c: 78 53 29 7d or 9, 9, 10
|
|
||||||
20: 00 00 28 f9 std 9, 0(8)
|
|
||||||
24: 20 00 80 4e blr
|
|
||||||
*/
|
|
||||||
TEST_CASE("ppc64: functor-2", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
ctx.MR(powah::R8, powah::R3);
|
|
||||||
ctx.AND(powah::R3, powah::R4, powah::R5);
|
|
||||||
ctx.CNTLZD(powah::R10, powah::R3);
|
|
||||||
ctx.SRADI(powah::R9, powah::R3, 32);
|
|
||||||
ctx.RLDICL(powah::R10, powah::R10, 58, 6);
|
|
||||||
ctx.RLWINM(powah::R9, powah::R9, 0, 0, 0);
|
|
||||||
ctx.SLDI(powah::R10, powah::R10, 30);
|
|
||||||
ctx.OR(powah::R9, powah::R9, powah::R10);
|
|
||||||
ctx.STD(powah::R9, powah::R8, 0);
|
|
||||||
ctx.BLR();
|
|
||||||
REQUIRE(data[0] == EB32(0x781b687c));
|
|
||||||
REQUIRE(data[1] == EB32(0x3828837c));
|
|
||||||
REQUIRE(data[2] == EB32(0x74006a7c));
|
|
||||||
REQUIRE(data[3] == EB32(0x7606697c));
|
|
||||||
REQUIRE(data[4] == EB32(0x82d14a79));
|
|
||||||
REQUIRE(data[5] == EB32(0x00002955));
|
|
||||||
REQUIRE(data[6] == EB32(0x64f04a79));
|
|
||||||
REQUIRE(data[7] == EB32(0x7853297d));
|
|
||||||
REQUIRE(data[8] == EB32(0x000028f9));
|
|
||||||
REQUIRE(data[9] == EB32(0x2000804e));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ppc64: functor-1", "[ppc64]") {
|
|
||||||
std::vector<uint32_t> data(64);
|
|
||||||
powah::Context ctx(data.data(), data.size());
|
|
||||||
powah::Label l_4 = ctx.DefineLabel();
|
|
||||||
powah::Label l_7 = ctx.DefineLabel();
|
|
||||||
ctx.CMPLD(powah::CR0, powah::R3, powah::R4);
|
|
||||||
ctx.MR(powah::R9, powah::R3);
|
|
||||||
ctx.BGT(powah::CR0, l_7);
|
|
||||||
ctx.CMPLDI(powah::CR0, powah::R3, 3781);
|
|
||||||
ctx.LI(powah::R3, 1);
|
|
||||||
ctx.BGTLR(powah::CR0);
|
|
||||||
ctx.CMPLD(powah::CR0, powah::R9, powah::R5);
|
|
||||||
ctx.BLE(powah::CR0, l_4);
|
|
||||||
ctx.SUBF(powah::R5, powah::R9, powah::R5);
|
|
||||||
ctx.XOR(powah::R3, powah::R5, powah::R4);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.LABEL(l_4);
|
|
||||||
ctx.ADD(powah::R5, powah::R4, powah::R5);
|
|
||||||
ctx.ADD(powah::R3, powah::R5, powah::R9);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.LABEL(l_7);
|
|
||||||
ctx.ADD(powah::R3, powah::R4, powah::R5);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.ApplyRelocs();
|
|
||||||
REQUIRE(data[0] == EB32(0x4020237c));
|
|
||||||
REQUIRE(data[1] == EB32(0x781b697c));
|
|
||||||
REQUIRE(data[2] == EB32(0x30008141));
|
|
||||||
REQUIRE(data[3] == EB32(0xc50e2328));
|
|
||||||
REQUIRE(data[4] == EB32(0x01006038));
|
|
||||||
REQUIRE(data[5] == EB32(0x2000814d));
|
|
||||||
REQUIRE(data[6] == EB32(0x4028297c));
|
|
||||||
REQUIRE(data[7] == EB32(0x10008140));
|
|
||||||
REQUIRE(data[8] == EB32(0x5028a97c));
|
|
||||||
REQUIRE(data[9] == EB32(0x7822a37c));
|
|
||||||
REQUIRE(data[10] == EB32(0x2000804e));
|
|
||||||
REQUIRE(data[11] == EB32(0x142aa47c));
|
|
||||||
REQUIRE(data[12] == EB32(0x144a657c));
|
|
||||||
REQUIRE(data[13] == EB32(0x2000804e));
|
|
||||||
REQUIRE(data[14] == EB32(0x142a647c));
|
|
||||||
REQUIRE(data[15] == EB32(0x2000804e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ARCHITECTURE_powerpc64)
|
|
||||||
/*
|
|
||||||
0: d619637c mullw 3, 3, 3
|
|
||||||
4: 20006378 clrldi 3, 3, 32
|
|
||||||
8: 2000804e blr
|
|
||||||
*/
|
|
||||||
TEST_CASE("ppc64: live-exec square", "[ppc64]") {
|
|
||||||
uint32_t* data = (uint32_t*)mmap(nullptr, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
REQUIRE(data != nullptr);
|
|
||||||
|
|
||||||
powah::Context ctx((void*)data, 4096);
|
|
||||||
ctx.MULLW(powah::R3, powah::R3, powah::R3);
|
|
||||||
ctx.CLRLDI(powah::R3, powah::R3, 32);
|
|
||||||
ctx.BLR();
|
|
||||||
REQUIRE(data[0] == EB32(0xd619637c));
|
|
||||||
REQUIRE(data[1] == EB32(0x20006378));
|
|
||||||
REQUIRE(data[2] == EB32(0x2000804e));
|
|
||||||
|
|
||||||
auto* fn = (int (*)(int))data;
|
|
||||||
REQUIRE(fn(4) == 4 * 4);
|
|
||||||
REQUIRE(fn(8) == 8 * 8);
|
|
||||||
|
|
||||||
munmap((void*)data, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
int f(int a, int b, int c) {
|
|
||||||
a += (a > b) ? b - 0xffff : c + 402, b += 2, c &= b*c;
|
|
||||||
return a * a + b ^ c & b;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
TEST_CASE("ppc64: live-exec xoralu", "[ppc64]") {
|
|
||||||
uint32_t* data = (uint32_t*)mmap(nullptr, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
REQUIRE(data != nullptr);
|
|
||||||
|
|
||||||
powah::Context ctx((void*)data, 4096);
|
|
||||||
powah::Label l_2 = ctx.DefineLabel();
|
|
||||||
powah::Label l_3 = ctx.DefineLabel();
|
|
||||||
ctx.CMPW(powah::R3, powah::R4);
|
|
||||||
ctx.BGT(powah::CR0, l_2);
|
|
||||||
ctx.ADDI(powah::R6, powah::R5, 402);
|
|
||||||
ctx.B(l_3);
|
|
||||||
ctx.LABEL(l_2);
|
|
||||||
ctx.ADDI(powah::R6, powah::R4, 1);
|
|
||||||
ctx.ADDIS(powah::R6, powah::R6, -1);
|
|
||||||
ctx.LABEL(l_3);
|
|
||||||
ctx.ADDI(powah::R4, powah::R4, 2);
|
|
||||||
ctx.ADD(powah::R3, powah::R6, powah::R3);
|
|
||||||
ctx.MULLW(powah::R6, powah::R4, powah::R5);
|
|
||||||
ctx.MULLW(powah::R3, powah::R3, powah::R3);
|
|
||||||
ctx.AND(powah::R5, powah::R5, powah::R6);
|
|
||||||
ctx.ADD(powah::R3, powah::R3, powah::R4);
|
|
||||||
ctx.AND(powah::R4, powah::R5, powah::R4);
|
|
||||||
ctx.XOR(powah::R3, powah::R3, powah::R4);
|
|
||||||
ctx.EXTSW(powah::R3, powah::R3);
|
|
||||||
ctx.BLR();
|
|
||||||
ctx.ApplyRelocs();
|
|
||||||
REQUIRE(data[0] == EB32(0x0020037c));
|
|
||||||
REQUIRE(data[1] == EB32(0x0c008141));
|
|
||||||
REQUIRE(data[2] == EB32(0x9201c538));
|
|
||||||
REQUIRE(data[3] == EB32(0x0c000048));
|
|
||||||
REQUIRE(data[4] == EB32(0x0100c438));
|
|
||||||
REQUIRE(data[5] == EB32(0xffffc63c));
|
|
||||||
REQUIRE(data[6] == EB32(0x02008438));
|
|
||||||
REQUIRE(data[7] == EB32(0x141a667c));
|
|
||||||
REQUIRE(data[8] == EB32(0xd629c47c));
|
|
||||||
REQUIRE(data[9] == EB32(0xd619637c));
|
|
||||||
REQUIRE(data[10] == EB32(0x3830a57c));
|
|
||||||
REQUIRE(data[11] == EB32(0x1422637c));
|
|
||||||
REQUIRE(data[12] == EB32(0x3820a47c));
|
|
||||||
REQUIRE(data[13] == EB32(0x7822637c));
|
|
||||||
REQUIRE(data[14] == EB32(0xb407637c));
|
|
||||||
REQUIRE(data[15] == EB32(0x2000804e));
|
|
||||||
|
|
||||||
auto const orig = [](int a, int b, int c) {
|
|
||||||
a += (a > b) ? b - 0xffff : c + 402, b += 2, c &= b*c;
|
|
||||||
return a * a + b ^ c & b;
|
|
||||||
};
|
|
||||||
auto* fn = (int (*)(int, int, int))data;
|
|
||||||
REQUIRE(fn(0, 1, 2) == orig(0, 1, 2));
|
|
||||||
REQUIRE(fn(6456, 4564, 4564561) == orig(6456, 4564, 4564561));
|
|
||||||
|
|
||||||
munmap((void*)data, 4096);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Vendored
+184
@@ -0,0 +1,184 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
|
||||||
|
*
|
||||||
|
* The LLVM Compiler Infrastructure
|
||||||
|
*
|
||||||
|
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||||
|
* Source Licenses. See LICENSE.TXT for details.
|
||||||
|
*
|
||||||
|
* ===----------------------------------------------------------------------===
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//#include "int_util.h"
|
||||||
|
|
||||||
|
/* Default is not to use posix_memalign, so systems like Android
|
||||||
|
* can use thread local data without heavier POSIX memory allocators.
|
||||||
|
*/
|
||||||
|
#ifndef EMUTLS_USE_POSIX_MEMALIGN
|
||||||
|
#define EMUTLS_USE_POSIX_MEMALIGN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For every TLS variable xyz,
|
||||||
|
* there is one __emutls_control variable named __emutls_v.xyz.
|
||||||
|
* If xyz has non-zero initial value, __emutls_v.xyz's "value"
|
||||||
|
* will point to __emutls_t.xyz, which has the initial value.
|
||||||
|
*/
|
||||||
|
typedef struct __emutls_control {
|
||||||
|
size_t size; /* size of the object in bytes */
|
||||||
|
size_t align; /* alignment of the object in bytes */
|
||||||
|
union {
|
||||||
|
uintptr_t index; /* data[index-1] is the object address */
|
||||||
|
void* address; /* object address, when in single thread env */
|
||||||
|
} object;
|
||||||
|
void* value; /* null or non-zero initial value for the object */
|
||||||
|
} __emutls_control;
|
||||||
|
|
||||||
|
static inline void* emutls_memalign_alloc(size_t align, size_t size) {
|
||||||
|
void *base;
|
||||||
|
#if EMUTLS_USE_POSIX_MEMALIGN
|
||||||
|
if (posix_memalign(&base, align, size) != 0)
|
||||||
|
abort();
|
||||||
|
#else
|
||||||
|
#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
|
||||||
|
char* object;
|
||||||
|
if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
|
||||||
|
abort();
|
||||||
|
base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
|
||||||
|
& ~(uintptr_t)(align - 1));
|
||||||
|
|
||||||
|
((void**)base)[-1] = object;
|
||||||
|
#endif
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void emutls_memalign_free(void* base) {
|
||||||
|
#if EMUTLS_USE_POSIX_MEMALIGN
|
||||||
|
free(base);
|
||||||
|
#else
|
||||||
|
/* The mallocated address is in ((void**)base)[-1] */
|
||||||
|
free(((void**)base)[-1]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Emulated TLS objects are always allocated at run-time. */
|
||||||
|
static inline void* emutls_allocate_object(__emutls_control* control) {
|
||||||
|
/* Use standard C types, check with gcc's emutls.o. */
|
||||||
|
//typedef unsigned int gcc_word __attribute__((mode(word)));
|
||||||
|
//typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
|
||||||
|
//COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
|
||||||
|
//COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
|
||||||
|
//COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
|
||||||
|
|
||||||
|
size_t size = control->size;
|
||||||
|
size_t align = control->align;
|
||||||
|
if (align < sizeof(void*))
|
||||||
|
align = sizeof(void*);
|
||||||
|
/* Make sure that align is power of 2. */
|
||||||
|
if ((align & (align - 1)) != 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
void* base = emutls_memalign_alloc(align, size);
|
||||||
|
if (control->value)
|
||||||
|
memcpy(base, control->value, size);
|
||||||
|
else
|
||||||
|
memset(base, 0, size);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static size_t emutls_num_object = 0; /* number of allocated TLS objects */
|
||||||
|
|
||||||
|
typedef struct emutls_address_array {
|
||||||
|
uintptr_t size; /* number of elements in the 'data' array */
|
||||||
|
void* data[];
|
||||||
|
} emutls_address_array;
|
||||||
|
|
||||||
|
static pthread_key_t emutls_pthread_key;
|
||||||
|
|
||||||
|
static void emutls_key_destructor(void* ptr) {
|
||||||
|
emutls_address_array* array = (emutls_address_array*)ptr;
|
||||||
|
uintptr_t i;
|
||||||
|
for (i = 0; i < array->size; ++i) {
|
||||||
|
if (array->data[i])
|
||||||
|
emutls_memalign_free(array->data[i]);
|
||||||
|
}
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emutls_init(void) {
|
||||||
|
if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns control->object.index; set index if not allocated yet. */
|
||||||
|
static inline uintptr_t emutls_get_index(__emutls_control* control) {
|
||||||
|
uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
|
||||||
|
if (!index) {
|
||||||
|
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once(&once, emutls_init);
|
||||||
|
pthread_mutex_lock(&emutls_mutex);
|
||||||
|
index = control->object.index;
|
||||||
|
if (!index) {
|
||||||
|
index = ++emutls_num_object;
|
||||||
|
__atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&emutls_mutex);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Updates newly allocated thread local emutls_address_array. */
|
||||||
|
static inline void emutls_check_array_set_size(emutls_address_array* array,
|
||||||
|
uintptr_t size) {
|
||||||
|
if (array == NULL)
|
||||||
|
abort();
|
||||||
|
array->size = size;
|
||||||
|
pthread_setspecific(emutls_pthread_key, (void*)array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the new 'data' array size, number of elements,
|
||||||
|
* which must be no smaller than the given index.
|
||||||
|
*/
|
||||||
|
static inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
|
||||||
|
/* Need to allocate emutls_address_array with one extra slot
|
||||||
|
* to store the data array size.
|
||||||
|
* Round up the emutls_address_array size to multiple of 16.
|
||||||
|
*/
|
||||||
|
return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the thread local emutls_address_array.
|
||||||
|
* Extends its size if necessary to hold address at index.
|
||||||
|
*/
|
||||||
|
static inline emutls_address_array* emutls_get_address_array(uintptr_t index) {
|
||||||
|
emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
|
||||||
|
if (array == NULL) {
|
||||||
|
uintptr_t new_size = emutls_new_data_array_size(index);
|
||||||
|
array = calloc(new_size + 1, sizeof(void*));
|
||||||
|
emutls_check_array_set_size(array, new_size);
|
||||||
|
} else if (index > array->size) {
|
||||||
|
uintptr_t orig_size = array->size;
|
||||||
|
uintptr_t new_size = emutls_new_data_array_size(index);
|
||||||
|
array = realloc(array, (new_size + 1) * sizeof(void*));
|
||||||
|
if (array)
|
||||||
|
memset(array->data + orig_size, 0,
|
||||||
|
(new_size - orig_size) * sizeof(void*));
|
||||||
|
emutls_check_array_set_size(array, new_size);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* __emutls_get_address(__emutls_control* control) {
|
||||||
|
uintptr_t index = emutls_get_index(control);
|
||||||
|
emutls_address_array* array = emutls_get_address_array(index);
|
||||||
|
if (array->data[index - 1] == NULL)
|
||||||
|
array->data[index - 1] = emutls_allocate_object(control);
|
||||||
|
return array->data[index - 1];
|
||||||
|
}
|
||||||
Vendored
+44
@@ -0,0 +1,44 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define STUB_WEAK(name) \
|
||||||
|
extern "C" void name() { \
|
||||||
|
printf("called " #name); \
|
||||||
|
asm volatile("ud2"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STUB_ZERO(name) \
|
||||||
|
extern "C" int name() { \
|
||||||
|
printf("called " #name " = ret zero"); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" int __pthread_cxa_finalize();
|
||||||
|
extern "C" void __cxa_thread_atexit_impl() {
|
||||||
|
//printf("__cxa_thread_atexit_impl called!\n");
|
||||||
|
//__pthread_cxa_finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
STUB_WEAK(ZSTD_trace_compress_begin)
|
||||||
|
STUB_WEAK(ZSTD_trace_compress_end)
|
||||||
|
STUB_WEAK(ZSTD_trace_decompress_begin)
|
||||||
|
STUB_WEAK(ZSTD_trace_decompress_end)
|
||||||
|
|
||||||
|
extern "C" thread_local struct {
|
||||||
|
char pad[512];
|
||||||
|
} _ThreadRuneLocale = {};
|
||||||
|
extern "C" struct {
|
||||||
|
char pad[512];
|
||||||
|
} __h_errno = {};
|
||||||
|
|
||||||
|
FILE* __stderrp = stdout;
|
||||||
|
FILE* __stdinp = stdin;
|
||||||
|
|
||||||
|
#undef STUB_WEAK
|
||||||
|
|
||||||
|
// THIS MAKES STD::COUT AND SUCH WORK :)
|
||||||
|
#include <iostream>
|
||||||
|
std::ios_base::Init init;
|
||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64 OR ARCHITECTURE_powerpc64) AND NOT YUZU_STATIC_ROOM)
|
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -245,4 +245,10 @@ target_sources(audio_core PRIVATE
|
|||||||
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||||
|
|
||||||
|
if(OPENORBIS)
|
||||||
|
target_sources(audio_core PRIVATE
|
||||||
|
sink/ps4_sink.cpp
|
||||||
|
sink/ps4_sink.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(audio_core)
|
create_target_directory_groups(audio_core)
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
#include <stop_token>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <orbis/AudioOut.h>
|
||||||
|
|
||||||
|
#include "audio_core/common/common.h"
|
||||||
|
#include "audio_core/sink/ps4_sink.h"
|
||||||
|
#include "audio_core/sink/sink_stream.h"
|
||||||
|
#include "common/alignment.h"
|
||||||
|
#include "common/logging.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
|
/// @brief PS4 sink stream, responsible for sinking samples to hardware.
|
||||||
|
struct PS4SinkStream final : public SinkStream {
|
||||||
|
/// @brief Create a new sink stream.
|
||||||
|
/// @param device_channels_ - Number of channels supported by the hardware.
|
||||||
|
/// @param system_channels_ - Number of channels the audio systems expect.
|
||||||
|
/// @param output_device - Name of the output device to use for this stream.
|
||||||
|
/// @param input_device - Name of the input device to use for this stream.
|
||||||
|
/// @param type_ - Type of this stream.
|
||||||
|
/// @param system_ - Core system.
|
||||||
|
/// @param event - Event used only for audio renderer, signalled on buffer consume.
|
||||||
|
PS4SinkStream(u32 device_channels_, u32 system_channels_, const std::string& output_device, const std::string& input_device, StreamType type_, Core::System& system_)
|
||||||
|
: SinkStream{system_, type_}
|
||||||
|
{
|
||||||
|
system_channels = system_channels_;
|
||||||
|
device_channels = device_channels_;
|
||||||
|
|
||||||
|
constexpr size_t PREFERRED_SAMPLE_COUNT = 1024;
|
||||||
|
auto const param = (device_channels > 1 ? ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO : ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO);
|
||||||
|
audio_dev = sceAudioOutOpen(ORBIS_USER_SERVICE_USER_ID_SYSTEM, ORBIS_AUDIO_OUT_PORT_TYPE_MAIN, 0, PREFERRED_SAMPLE_COUNT, TargetSampleRate, param);
|
||||||
|
if (audio_dev > 0) {
|
||||||
|
audio_thread = std::jthread([=, this](std::stop_token stop_token) {
|
||||||
|
std::array<s16, PREFERRED_SAMPLE_COUNT * MaxChannels> buffer;
|
||||||
|
while (!stop_token.stop_requested()) {
|
||||||
|
if (this->type == StreamType::In) {
|
||||||
|
this->ProcessAudioIn(buffer, PREFERRED_SAMPLE_COUNT);
|
||||||
|
(void)buffer; // TODO: microphone support
|
||||||
|
} else {
|
||||||
|
int err = 0;
|
||||||
|
std::fill(buffer.begin(), buffer.end(), 0);
|
||||||
|
this->ProcessAudioOutAndRender(buffer, PREFERRED_SAMPLE_COUNT);
|
||||||
|
sceAudioOutOutput(audio_dev, nullptr);
|
||||||
|
if ((err = sceAudioOutOutput(audio_dev, buffer.data())) < 0)
|
||||||
|
LOG_ERROR(Service_Audio, "{}", err);
|
||||||
|
}
|
||||||
|
// Wait for pause, we don't really have a native pause
|
||||||
|
// so this is the best i can do
|
||||||
|
while (paused && !stop_token.stop_requested())
|
||||||
|
asm volatile ("pause"); //dont shootup cpu usage to 100%
|
||||||
|
}
|
||||||
|
sceAudioOutClose(audio_dev);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to create audio device! {:#x}", uint32_t(audio_dev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~PS4SinkStream() override {
|
||||||
|
LOG_DEBUG(Service_Audio, "Destroying PS4 stream {}", name);
|
||||||
|
if (audio_thread.joinable()) {
|
||||||
|
audio_thread.request_stop();
|
||||||
|
audio_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finalize() override {
|
||||||
|
if (audio_dev > 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(bool resume = false) override {
|
||||||
|
if (audio_dev > 0 && paused) {
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop() override {
|
||||||
|
if (audio_dev > 0 && !paused) {
|
||||||
|
SignalPause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::jthread audio_thread;
|
||||||
|
int32_t audio_dev{};
|
||||||
|
};
|
||||||
|
|
||||||
|
PS4Sink::PS4Sink(std::string_view target_device_name) {
|
||||||
|
int32_t rc = sceAudioOutInit();
|
||||||
|
if (rc == 0 || unsigned(rc) == ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT) {
|
||||||
|
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||||
|
output_device = target_device_name;
|
||||||
|
} else {
|
||||||
|
output_device.clear();
|
||||||
|
}
|
||||||
|
device_channels = 2;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_Audio, "Unable to open audio out! {:#x}", uint32_t(rc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PS4Sink::~PS4Sink() = default;
|
||||||
|
|
||||||
|
/// @brief Create a new sink stream.
|
||||||
|
/// @param system - Core system.
|
||||||
|
/// @param system_channels - Number of channels the audio system expects. May differ from the device's channel count.
|
||||||
|
/// @param name - Name of this stream.
|
||||||
|
/// @param type - Type of this stream, render/in/out.
|
||||||
|
/// @return A pointer to the created SinkStream
|
||||||
|
SinkStream* PS4Sink::AcquireSinkStream(Core::System& system, u32 system_channels_, const std::string&, StreamType type) {
|
||||||
|
system_channels = system_channels_;
|
||||||
|
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<PS4SinkStream>(device_channels, system_channels, output_device, input_device, type, system));
|
||||||
|
return stream.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::CloseStream(SinkStream* stream) {
|
||||||
|
for (size_t i = 0; i < sink_streams.size(); i++) {
|
||||||
|
if (sink_streams[i].get() == stream) {
|
||||||
|
sink_streams[i].reset();
|
||||||
|
sink_streams.erase(sink_streams.begin() + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::CloseStreams() {
|
||||||
|
sink_streams.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 PS4Sink::GetDeviceVolume() const {
|
||||||
|
return sink_streams.size() > 0 ? sink_streams[0]->GetDeviceVolume() : 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::SetDeviceVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams)
|
||||||
|
stream->SetDeviceVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::SetSystemVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams)
|
||||||
|
stream->SetSystemVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ListPS4SinkDevices(bool capture) {
|
||||||
|
return {{"Default"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetPS4Latency() {
|
||||||
|
return TargetSampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "audio_core/sink/sink.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
class SinkStream;
|
||||||
|
|
||||||
|
/// @brief PS4 backend sink, holds multiple output streams and is responsible for sinking samples to
|
||||||
|
/// hardware. Used by Audio Render, Audio In and Audio Out.
|
||||||
|
struct PS4Sink final : public Sink {
|
||||||
|
explicit PS4Sink(std::string_view device_id);
|
||||||
|
~PS4Sink() override;
|
||||||
|
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels, const std::string& name, StreamType type) override;
|
||||||
|
void CloseStream(SinkStream* stream) override;
|
||||||
|
void CloseStreams() override;
|
||||||
|
f32 GetDeviceVolume() const override;
|
||||||
|
void SetDeviceVolume(f32 volume) override;
|
||||||
|
void SetSystemVolume(f32 volume) override;
|
||||||
|
/// Name of the output device used by streams
|
||||||
|
std::string output_device;
|
||||||
|
/// Name of the input device used by streams
|
||||||
|
std::string input_device;
|
||||||
|
/// Vector of streams managed by this sink
|
||||||
|
std::vector<SinkStreamPtr> sink_streams;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> ListPS4SinkDevices(bool capture);
|
||||||
|
u32 GetPS4Latency();
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
#include "audio_core/sink/sdl3_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
#include "audio_core/sink/ps4_sink.h"
|
||||||
|
#endif
|
||||||
#include "audio_core/sink/null_sink.h"
|
#include "audio_core/sink/null_sink.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
@@ -42,6 +45,16 @@ struct SinkDetails {
|
|||||||
|
|
||||||
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||||
constexpr SinkDetails sink_details[] = {
|
constexpr SinkDetails sink_details[] = {
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
SinkDetails{
|
||||||
|
Settings::AudioEngine::Ps4,
|
||||||
|
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||||
|
return std::make_unique<PS4Sink>(device_id);
|
||||||
|
},
|
||||||
|
&ListPS4SinkDevices,
|
||||||
|
&GetPS4Latency,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
SinkDetails{
|
SinkDetails{
|
||||||
Settings::AudioEngine::Cubeb,
|
Settings::AudioEngine::Cubeb,
|
||||||
@@ -96,7 +109,9 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
|||||||
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
||||||
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||||
// causes audio issues, in that case go with SDL.
|
// causes audio issues, in that case go with SDL.
|
||||||
#if defined(HAVE_CUBEB) && defined(HAVE_SDL3)
|
#if defined(__OPENORBIS__)
|
||||||
|
iter = find_backend(Settings::AudioEngine::Ps4);
|
||||||
|
#elif defined(HAVE_CUBEB) && defined(HAVE_SDL3)
|
||||||
iter = find_backend(Settings::AudioEngine::Cubeb);
|
iter = find_backend(Settings::AudioEngine::Cubeb);
|
||||||
if (iter->latency() > TargetSampleCount * 3) {
|
if (iter->latency() > TargetSampleCount * 3) {
|
||||||
iter = find_backend(Settings::AudioEngine::Sdl3);
|
iter = find_backend(Settings::AudioEngine::Sdl3);
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ if(CXX_CLANG)
|
|||||||
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>)
|
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Has to be BEFORE httplib
|
||||||
if (BOOST_NO_HEADERS)
|
if (BOOST_NO_HEADERS)
|
||||||
target_link_libraries(common PUBLIC Boost::algorithm Boost::heap Boost::icl Boost::pool)
|
target_link_libraries(common PUBLIC Boost::algorithm Boost::heap Boost::icl Boost::pool)
|
||||||
else()
|
else()
|
||||||
|
|||||||
+12
-10
@@ -20,6 +20,9 @@
|
|||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define fileno _fileno
|
#define fileno _fileno
|
||||||
@@ -402,28 +405,27 @@ u64 IOFile::GetSize() const {
|
|||||||
file_size = Android::GetSize(file_path);
|
file_size = Android::GetSize(file_path);
|
||||||
} else {
|
} else {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
file_size = fs::file_size(file_path, ec);
|
file_size = fs::file_size(file_path, ec);
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
LOG_ERROR(Common_Filesystem,
|
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", PathToUTF8String(file_path), ec.message());
|
||||||
"Failed to retrieve the file size of path={}, ec_message={}",
|
|
||||||
PathToUTF8String(file_path), ec.message());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
// TODO: implementation of fs::file_size() is buggy on PS4, why?
|
||||||
|
// probably toolchain issue... ugh
|
||||||
|
OrbisKernelStat st{};
|
||||||
|
stat(file_path.c_str(), reinterpret_cast<struct stat *>(std::addressof(st)));
|
||||||
|
auto const file_size = st.st_size;
|
||||||
|
LOG_DEBUG(Common_Filesystem, "size for {} = {}", file_path.c_str(), file_size);
|
||||||
#else
|
#else
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
const auto file_size = fs::file_size(file_path, ec);
|
const auto file_size = fs::file_size(file_path, ec);
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
|
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", PathToUTF8String(file_path), ec.message());
|
||||||
PathToUTF8String(file_path), ec.message());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return file_size;
|
return file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,11 +174,14 @@ bool CreateDir(const fs::path& path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe this is what causes death?
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
if (!Exists(path.parent_path())) {
|
if (!Exists(path.parent_path())) {
|
||||||
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
||||||
PathToUTF8String(path));
|
PathToUTF8String(path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (IsDir(path)) {
|
if (IsDir(path)) {
|
||||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
||||||
|
|||||||
+11
-12
@@ -130,6 +130,10 @@ public:
|
|||||||
ASSERT(!eden_path.empty());
|
ASSERT(!eden_path.empty());
|
||||||
eden_path_cache = eden_path / CACHE_DIR;
|
eden_path_cache = eden_path / CACHE_DIR;
|
||||||
eden_path_config = eden_path / CONFIG_DIR;
|
eden_path_config = eden_path / CONFIG_DIR;
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
eden_path = "/data/eden";
|
||||||
|
eden_path_cache = eden_path / CACHE_DIR;
|
||||||
|
eden_path_config = eden_path / CONFIG_DIR;
|
||||||
#else
|
#else
|
||||||
eden_path = GetCurrentDir() / PORTABLE_DIR;
|
eden_path = GetCurrentDir() / PORTABLE_DIR;
|
||||||
if (!Exists(eden_path) || !IsDir(eden_path)) {
|
if (!Exists(eden_path) || !IsDir(eden_path)) {
|
||||||
@@ -172,12 +176,11 @@ public:
|
|||||||
GenerateEdenPath(EdenPath::ShaderDir, eden_path_cache / SHADER_DIR);
|
GenerateEdenPath(EdenPath::ShaderDir, eden_path_cache / SHADER_DIR);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
GenerateLegacyPath(EmuPath::RyujinxDir, GetAppDataRoamingDirectory() / RYUJINX_DIR);
|
GenerateLegacyPath(EmuPath::RyujinxDir, GetAppDataRoamingDirectory() / RYUJINX_DIR);
|
||||||
#else
|
#elif !defined(__OPENORBIS__)
|
||||||
// In Ryujinx's infinite wisdom, it places EVERYTHING in the config directory on UNIX
|
// In Ryujinx's infinite wisdom, it places EVERYTHING in the config directory on UNIX
|
||||||
// This is incredibly stupid and violates a million XDG standards, but whatever
|
// This is incredibly stupid and violates a million XDG standards, but whatever
|
||||||
GenerateLegacyPath(EmuPath::RyujinxDir, GetDataDirectory("XDG_CONFIG_HOME") / RYUJINX_DIR);
|
GenerateLegacyPath(EmuPath::RyujinxDir, GetDataDirectory("XDG_CONFIG_HOME") / RYUJINX_DIR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -339,36 +342,33 @@ fs::path GetAppDataRoamingDirectory() {
|
|||||||
return fs_appdata_roaming_path;
|
return fs_appdata_roaming_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
|
||||||
|
// Not required/defined
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
fs::path GetHomeDirectory() {
|
fs::path GetHomeDirectory() {
|
||||||
const char* home_env_var = getenv("HOME");
|
const char* home_env_var = getenv("HOME");
|
||||||
|
|
||||||
if (home_env_var) {
|
if (home_env_var) {
|
||||||
return fs::path{home_env_var};
|
return fs::path{home_env_var};
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(Common_Filesystem,
|
LOG_INFO(Common_Filesystem,
|
||||||
"$HOME is not defined in the environment variables, "
|
"$HOME is not defined in the environment variables, "
|
||||||
"attempting to query passwd to get the home path of the current user");
|
"attempting to query passwd to get the home path of the current user");
|
||||||
|
|
||||||
const auto* pw = getpwuid(getuid());
|
const auto* pw = getpwuid(getuid());
|
||||||
|
|
||||||
if (!pw) {
|
if (!pw) {
|
||||||
LOG_ERROR(Common_Filesystem, "Failed to get the home path of the current user");
|
LOG_ERROR(Common_Filesystem, "Failed to get the home path of the current user");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs::path{pw->pw_dir};
|
return fs::path{pw->pw_dir};
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path GetDataDirectory(const std::string& env_name) {
|
fs::path GetDataDirectory(const std::string& env_name) {
|
||||||
const char* data_env_var = getenv(env_name.c_str());
|
const char* data_env_var = getenv(env_name.c_str());
|
||||||
|
|
||||||
if (data_env_var) {
|
if (data_env_var) {
|
||||||
return fs::path{data_env_var};
|
return fs::path{data_env_var};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env_name == "XDG_DATA_HOME") {
|
if (env_name == "XDG_DATA_HOME") {
|
||||||
return GetHomeDirectory() / ".local/share";
|
return GetHomeDirectory() / ".local/share";
|
||||||
} else if (env_name == "XDG_CACHE_HOME") {
|
} else if (env_name == "XDG_CACHE_HOME") {
|
||||||
@@ -376,7 +376,6 @@ fs::path GetDataDirectory(const std::string& env_name) {
|
|||||||
} else if (env_name == "XDG_CONFIG_HOME") {
|
} else if (env_name == "XDG_CONFIG_HOME") {
|
||||||
return GetHomeDirectory() / ".config";
|
return GetHomeDirectory() / ".config";
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,14 +73,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t backing_size{};
|
|
||||||
size_t virtual_size{};
|
|
||||||
|
|
||||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||||
// Low level handler for the platform dependent memory routines
|
// Low level handler for the platform dependent memory routines
|
||||||
class Impl;
|
class Impl;
|
||||||
std::unique_ptr<Impl> impl;
|
std::unique_ptr<Impl> impl;
|
||||||
#endif
|
#endif
|
||||||
|
size_t backing_size{};
|
||||||
|
size_t virtual_size{};
|
||||||
u8* backing_base{};
|
u8* backing_base{};
|
||||||
u8* virtual_base{};
|
u8* virtual_base{};
|
||||||
size_t virtual_base_offset{};
|
size_t virtual_base_offset{};
|
||||||
|
|||||||
@@ -3,8 +3,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// TODO: httplib port can't use OpenSSL because of package misconfigs on OO toolchain
|
||||||
|
// right now the solution is to tell httplib that OpenSSL doesn't exist, but that's bad
|
||||||
|
// and the issue is a bit more of how OpenSSL lacks some essential functionality
|
||||||
|
// which is a bit annoying to reconfigure atm.
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES 1
|
#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES 1
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
|
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
|
|||||||
@@ -236,7 +236,6 @@ struct ColorConsoleBackend final : public Backend {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
/// @brief Backend that writes to a file passed into the constructor
|
/// @brief Backend that writes to a file passed into the constructor
|
||||||
struct FileBackend final : public Backend {
|
struct FileBackend final : public Backend {
|
||||||
explicit FileBackend(const std::filesystem::path filename) noexcept {
|
explicit FileBackend(const std::filesystem::path filename) noexcept {
|
||||||
@@ -299,7 +298,7 @@ private:
|
|||||||
std::size_t bytes_written = 0;
|
std::size_t bytes_written = 0;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/// @brief Backend that writes to Visual Studio's output window
|
/// @brief Backend that writes to Visual Studio's output window
|
||||||
struct DebuggerBackend final : public Backend {
|
struct DebuggerBackend final : public Backend {
|
||||||
@@ -343,10 +342,8 @@ struct Impl {
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
void ForEachBackend(F&& lambda) noexcept {
|
void ForEachBackend(F&& lambda) noexcept {
|
||||||
lambda(static_cast<Backend&>(color_console_backend));
|
lambda(static_cast<Backend&>(color_console_backend));
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
if (file_backend)
|
if (file_backend)
|
||||||
lambda(static_cast<Backend&>(*file_backend));
|
lambda(static_cast<Backend&>(*file_backend));
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
lambda(static_cast<Backend&>(debugger_backend));
|
lambda(static_cast<Backend&>(debugger_backend));
|
||||||
#endif
|
#endif
|
||||||
@@ -357,9 +354,7 @@ struct Impl {
|
|||||||
|
|
||||||
Filter filter;
|
Filter filter;
|
||||||
ColorConsoleBackend color_console_backend{};
|
ColorConsoleBackend color_console_backend{};
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
std::optional<FileBackend> file_backend;
|
std::optional<FileBackend> file_backend;
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DebuggerBackend debugger_backend{};
|
DebuggerBackend debugger_backend{};
|
||||||
#endif
|
#endif
|
||||||
@@ -396,12 +391,10 @@ void Initialize() {
|
|||||||
} else {
|
} else {
|
||||||
logging_instance.emplace();
|
logging_instance.emplace();
|
||||||
logging_instance->filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
logging_instance->filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
using namespace Common::FS;
|
using namespace Common::FS;
|
||||||
const auto& log_dir = GetEdenPath(EdenPath::LogDir);
|
const auto& log_dir = GetEdenPath(EdenPath::LogDir);
|
||||||
void(CreateDir(log_dir));
|
void(CreateDir(log_dir));
|
||||||
logging_instance->file_backend.emplace(log_dir / LOG_FILE);
|
logging_instance->file_backend.emplace(log_dir / LOG_FILE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -8,7 +11,7 @@
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(__OPENORBIS__))
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ std::optional<std::string> MakeRequest(const std::string& url, const std::string
|
|||||||
client->set_read_timeout(timeout_seconds);
|
client->set_read_timeout(timeout_seconds);
|
||||||
client->set_write_timeout(timeout_seconds);
|
client->set_write_timeout(timeout_seconds);
|
||||||
|
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
#if defined(YUZU_BUNDLED_OPENSSL) && !defined(__OPENORBIS__)
|
||||||
client->load_ca_cert_store(kCert, sizeof(kCert));
|
client->load_ca_cert_store(kCert, sizeof(kCert));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/time_zone.h"
|
#include "common/time_zone.h"
|
||||||
|
|
||||||
#if defined(__linux__ ) && defined(ARCHITECTURE_arm64)
|
#ifdef __unix__
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -187,12 +187,9 @@ bool IsFastmemEnabled() {
|
|||||||
return bool(values.cpuopt_fastmem);
|
return bool(values.cpuopt_fastmem);
|
||||||
else if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe)
|
else if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe)
|
||||||
return bool(values.cpuopt_unsafe_host_mmu);
|
return bool(values.cpuopt_unsafe_host_mmu);
|
||||||
#if defined(__linux__) && defined(ARCHITECTURE_arm64)
|
#if defined(__unix__)
|
||||||
// Only 4kb systems support host MMU right now
|
// TODO: Support this since only 4kb systems support host MMU right now
|
||||||
// TODO: Support this
|
|
||||||
return getpagesize() == 4096;
|
return getpagesize() == 4096;
|
||||||
#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__)
|
|
||||||
return false;
|
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -196,7 +196,14 @@ struct Values {
|
|||||||
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
|
SwitchableSetting<bool> use_multi_core{linkage,
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
// Re-enable once proper TLS support is added
|
||||||
|
false,
|
||||||
|
#else
|
||||||
|
true,
|
||||||
|
#endif
|
||||||
|
"use_multi_core", Category::Core};
|
||||||
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
||||||
MemoryLayout::Memory_4Gb,
|
MemoryLayout::Memory_4Gb,
|
||||||
"memory_layout_mode",
|
"memory_layout_mode",
|
||||||
@@ -330,7 +337,7 @@ struct Values {
|
|||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
|
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
|
||||||
#if defined(__sun__) || defined(__managarm__)
|
#if defined(__sun__) || defined(__managarm__) || defined(__OPENORBIS__)
|
||||||
RendererBackend::OpenGL_GLSL,
|
RendererBackend::OpenGL_GLSL,
|
||||||
#else
|
#else
|
||||||
RendererBackend::Vulkan,
|
RendererBackend::Vulkan,
|
||||||
|
|||||||
@@ -92,14 +92,15 @@ struct EnumMetadata {
|
|||||||
// AudioEngine must be specified discretely due to having existing but slightly different
|
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||||
// canonicalizations
|
// canonicalizations
|
||||||
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||||
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, };
|
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, Ps4, };
|
||||||
template<>
|
template<>
|
||||||
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||||
return {
|
return {
|
||||||
{"auto", AudioEngine::Auto},
|
{"auto", AudioEngine::Auto},
|
||||||
{"cubeb", AudioEngine::Cubeb},
|
{"cubeb", AudioEngine::Cubeb},
|
||||||
{"sdl3", AudioEngine::Sdl3},
|
{"sdl3", AudioEngine::Sdl3},
|
||||||
{"null", AudioEngine::Null},
|
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||||
|
{"ps4", AudioEngine::Ps4},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
|
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
|
||||||
|
|||||||
@@ -12,10 +12,36 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
#include <ranges>
|
||||||
|
#include <csignal>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <boost/container/static_vector.hpp>
|
||||||
|
#include <orbis/SystemService.h>
|
||||||
|
#include <orbis/libkernel.h>
|
||||||
|
typedef void (*SceKernelExceptionHandler)(int32_t, void*);
|
||||||
|
extern "C" int32_t sceKernelInstallExceptionHandler(int32_t signum, SceKernelExceptionHandler handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/sparse_large_vector.h"
|
#include "common/sparse_large_vector.h"
|
||||||
|
|
||||||
|
// PlayStation 4
|
||||||
|
// Flag needs to be undef-ed on non PS4 since it has different semantics
|
||||||
|
// on some platforms.
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
# ifndef MAP_SYSTEM
|
||||||
|
# define MAP_SYSTEM 0x2000
|
||||||
|
# endif
|
||||||
|
# ifndef MAP_VOID
|
||||||
|
# define MAP_VOID 0x100
|
||||||
|
# endif
|
||||||
|
// sigaction(2) has a motherfucking bug on musl where the thing isnt even properly prefixed
|
||||||
|
# undef sa_sigaction
|
||||||
|
# define sa_sigaction __sa_handler.__sa_sigaction
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -97,6 +123,103 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
|
|||||||
#define MAP_NOCORE 0
|
#define MAP_NOCORE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
|
||||||
|
namespace Orbis {
|
||||||
|
constexpr size_t ORBIS_PAGE_SIZE = 16384;
|
||||||
|
|
||||||
|
struct Ucontext {
|
||||||
|
struct Sigset {
|
||||||
|
u64 bits[2];
|
||||||
|
} uc_sigmask;
|
||||||
|
int field1_0x10[12];
|
||||||
|
struct Mcontext {
|
||||||
|
u64 mc_onstack;
|
||||||
|
u64 mc_rdi;
|
||||||
|
u64 mc_rsi;
|
||||||
|
u64 mc_rdx;
|
||||||
|
u64 mc_rcx;
|
||||||
|
u64 mc_r8;
|
||||||
|
u64 mc_r9;
|
||||||
|
u64 mc_rax;
|
||||||
|
u64 mc_rbx;
|
||||||
|
u64 mc_rbp;
|
||||||
|
u64 mc_r10;
|
||||||
|
u64 mc_r11;
|
||||||
|
u64 mc_r12;
|
||||||
|
u64 mc_r13;
|
||||||
|
u64 mc_r14;
|
||||||
|
u64 mc_r15;
|
||||||
|
int mc_trapno;
|
||||||
|
u16 mc_fs;
|
||||||
|
u16 mc_gs;
|
||||||
|
u64 mc_addr;
|
||||||
|
int mc_flags;
|
||||||
|
u16 mc_es;
|
||||||
|
u16 mc_ds;
|
||||||
|
u64 mc_err;
|
||||||
|
u64 mc_rip;
|
||||||
|
u64 mc_cs;
|
||||||
|
u64 mc_rflags;
|
||||||
|
u64 mc_rsp;
|
||||||
|
u64 mc_ss;
|
||||||
|
u64 mc_len;
|
||||||
|
u64 mc_fpformat;
|
||||||
|
u64 mc_ownedfp;
|
||||||
|
u64 mc_lbrfrom;
|
||||||
|
u64 mc_lbrto;
|
||||||
|
u64 mc_aux1;
|
||||||
|
u64 mc_aux2;
|
||||||
|
u64 mc_fpstate[104];
|
||||||
|
u64 mc_fsbase;
|
||||||
|
u64 mc_gsbase;
|
||||||
|
u64 mc_spare[6];
|
||||||
|
} uc_mcontext;
|
||||||
|
struct Ucontext* uc_link;
|
||||||
|
struct ExStack {
|
||||||
|
void* ss_sp;
|
||||||
|
std::size_t ss_size;
|
||||||
|
int ss_flags;
|
||||||
|
int _align;
|
||||||
|
} uc_stack;
|
||||||
|
int uc_flags;
|
||||||
|
int __spare[4];
|
||||||
|
int field7_0x4f4[3];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static boost::container::static_vector<std::pair<void*, size_t>, 16> swap_regions;
|
||||||
|
static std::mutex evil_swap_mutex;
|
||||||
|
extern "C" int sceKernelRemoveExceptionHandler(s32 sig_num);
|
||||||
|
static void SwapHandler(int sig, void* raw_context) {
|
||||||
|
std::unique_lock lk{evil_swap_mutex};
|
||||||
|
auto& mctx = ((Orbis::Ucontext*)raw_context)->uc_mcontext;
|
||||||
|
if (auto const it = std::ranges::find_if(swap_regions, [addr = mctx.mc_addr](auto const& e) {
|
||||||
|
return uintptr_t(addr) >= uintptr_t(e.first) && uintptr_t(addr) < uintptr_t(e.first) + e.second;
|
||||||
|
}); it != swap_regions.end()) {
|
||||||
|
size_t const page_size = Orbis::ORBIS_PAGE_SIZE * 128; //128K
|
||||||
|
size_t const page_mask = ~(page_size - 1);
|
||||||
|
// should replace the existing mapping... ugh
|
||||||
|
void* aligned_addr = reinterpret_cast<void*>(uintptr_t(mctx.mc_addr) & page_mask);
|
||||||
|
void* res = mmap(aligned_addr, page_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
|
if (res == MAP_FAILED) {
|
||||||
|
LOG_ERROR(HW_Memory, "{:#x},{} @ {}:{:#x}", mctx.mc_addr, aligned_addr, it->first, it->second);
|
||||||
|
sceKernelRemoveExceptionHandler(SIGSEGV); // to not catch the next signal
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(HW_Memory, "{:#x},{} @ {}:{:#x}", mctx.mc_addr, aligned_addr, it->first, it->second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(HW_Memory, "fault in addr {:#x} at {:#x}", mctx.mc_addr, mctx.mc_rip); // print caller address
|
||||||
|
sceKernelRemoveExceptionHandler(SIGSEGV); // to not catch the next signal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void InitSwap() noexcept {
|
||||||
|
sceKernelInstallExceptionHandler(SIGSEGV, &SwapHandler);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void InitSwap() noexcept {}
|
||||||
|
#endif
|
||||||
|
|
||||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||||
if (auto page = HostPageSize; size % page != 0) {
|
if (auto page = HostPageSize; size % page != 0) {
|
||||||
LOG_WARNING(HW_Memory, "Allocating unaligned large vector with size {:#x}; aligning to {} page size", size, page);
|
LOG_WARNING(HW_Memory, "Allocating unaligned large vector with size {:#x}; aligning to {} page size", size, page);
|
||||||
@@ -118,6 +241,37 @@ void* AllocateMemoryPages(std::size_t size) noexcept {
|
|||||||
base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||||
}
|
}
|
||||||
ASSERT_MSG(base, "Failed to reserve {:#x} sized region with error {}", size, GetLastError());
|
ASSERT_MSG(base, "Failed to reserve {:#x} sized region with error {}", size, GetLastError());
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
bool use_void_mem = true;
|
||||||
|
void* base = nullptr;
|
||||||
|
if (size < 4294967296ull) {
|
||||||
|
size_t align = Orbis::ORBIS_PAGE_SIZE;
|
||||||
|
off_t offset;
|
||||||
|
int32_t res;
|
||||||
|
size = (size + align - 1) / align * align;
|
||||||
|
if ((res = sceKernelAllocateDirectMemory(0, ORBIS_KERNEL_MAIN_DMEM_SIZE, size, align, ORBIS_KERNEL_WB_ONION, &offset)) == 0) {
|
||||||
|
if ((res = sceKernelMapDirectMemory(&base, size, ORBIS_KERNEL_PROT_CPU_READ | ORBIS_KERNEL_PROT_CPU_WRITE, 0, offset, size)) == 0) {
|
||||||
|
if ((res = sceKernelMprotect(base, size, VM_PROT_ALL)) == 0 && base != nullptr) {
|
||||||
|
LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", size, base);
|
||||||
|
use_void_mem = false; //Memory properly mapped
|
||||||
|
} else {
|
||||||
|
sceKernelReleaseDirectMemory(offset, size);
|
||||||
|
LOG_ERROR(HW_Memory, "{} = sceKernelMprotect({}, {})", res, offset, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sceKernelReleaseDirectMemory(offset, size);
|
||||||
|
LOG_ERROR(HW_Memory, "{} = sceKernelMapDirectMemory({}, {})", res, offset, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(HW_Memory, "{} = sceKernelAllocateDirectMemory({}, {}, {})", res, size, align, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (use_void_mem) {
|
||||||
|
base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0);
|
||||||
|
LOG_WARNING(HW_Memory, "Using VoidMem for {} bytes area @ {}", size, base);
|
||||||
|
ASSERT(base != MAP_FAILED);
|
||||||
|
swap_regions.emplace_back(base, size);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
void* base = mmap(nullptr, size, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0);
|
void* base = mmap(nullptr, size, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0);
|
||||||
if (base == MAP_FAILED)
|
if (base == MAP_FAILED)
|
||||||
@@ -135,6 +289,15 @@ void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
|
|||||||
return;
|
return;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
|
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
if (auto const it = std::ranges::find_if(swap_regions, [=](auto const& e) {
|
||||||
|
return uintptr_t(base) >= uintptr_t(e.first) && uintptr_t(base) < uintptr_t(e.first) + e.second;
|
||||||
|
}); it != swap_regions.end()) {
|
||||||
|
int rc = munmap(base, size);
|
||||||
|
ASSERT(rc == 0);
|
||||||
|
} else {
|
||||||
|
sceKernelCheckedReleaseDirectMemory(off_t(base), size_t(size));
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ASSERT(munmap(base, size) == 0);
|
ASSERT(munmap(base, size) == 0);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const u64 HostPageMask = ~(HostPageSize - 1);
|
|||||||
|
|
||||||
void* AllocateMemoryPages(std::size_t size) noexcept;
|
void* AllocateMemoryPages(std::size_t size) noexcept;
|
||||||
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
||||||
|
void InitSwap() noexcept;
|
||||||
|
|
||||||
/// A large page-aligned buffer that has optimized memory usage for zero-writes.
|
/// A large page-aligned buffer that has optimized memory usage for zero-writes.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@@ -1241,7 +1241,7 @@ if (HAS_NCE)
|
|||||||
target_link_libraries(core PRIVATE merry::oaknut)
|
target_link_libraries(core PRIVATE merry::oaknut)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_powerpc64 OR ARCHITECTURE_powerpc64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
arm/dynarmic/arm_dynarmic_64.cpp
|
arm/dynarmic/arm_dynarmic_64.cpp
|
||||||
|
|||||||
@@ -206,7 +206,9 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
|
|||||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||||
|
|
||||||
// Code cache size
|
// Code cache size
|
||||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
#if defined(__OPENORBIS__)
|
||||||
|
config.code_cache_size = std::uint32_t(8_MiB);
|
||||||
|
#elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||||
config.code_cache_size = std::uint32_t(128_MiB);
|
config.code_cache_size = std::uint32_t(128_MiB);
|
||||||
#else
|
#else
|
||||||
config.code_cache_size = std::uint32_t(512_MiB);
|
config.code_cache_size = std::uint32_t(512_MiB);
|
||||||
|
|||||||
@@ -258,7 +258,9 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
|
|||||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||||
|
|
||||||
// Code cache size
|
// Code cache size
|
||||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
#if defined(__OPENORBIS__)
|
||||||
|
config.code_cache_size = std::uint32_t(8_MiB);
|
||||||
|
#elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||||
config.code_cache_size = std::uint32_t(128_MiB);
|
config.code_cache_size = std::uint32_t(128_MiB);
|
||||||
#else
|
#else
|
||||||
config.code_cache_size = std::uint32_t(512_MiB);
|
config.code_cache_size = std::uint32_t(512_MiB);
|
||||||
|
|||||||
@@ -29,11 +29,8 @@ public:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const {
|
Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const {
|
||||||
return GetPhysicalAddr(reinterpret_cast<uintptr_t>(ptr));
|
return (reinterpret_cast<uintptr_t>(ptr) -
|
||||||
}
|
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer())) +
|
||||||
|
|
||||||
Common::PhysicalAddress GetPhysicalAddr(uintptr_t ptr) const {
|
|
||||||
return (ptr - reinterpret_cast<uintptr_t>(buffer.BackingBasePointer())) +
|
|
||||||
DramMemoryMap::Base;
|
DramMemoryMap::Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -461,8 +461,19 @@ std::vector<VirtualFile> RealVfsDirectory::GetFiles() const {
|
|||||||
|
|
||||||
FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) const {
|
FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) const {
|
||||||
const auto full_path = FS::SanitizePath(path + '/' + std::string(path_));
|
const auto full_path = FS::SanitizePath(path + '/' + std::string(path_));
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
// DO NOT USE NORMAL STAT, it's bugged on OO toolchain
|
||||||
|
OrbisKernelStat st{};
|
||||||
|
const auto stat_result = stat(full_path.c_str(), reinterpret_cast<struct stat *>(std::addressof(st)));
|
||||||
|
if (stat_result != 0)
|
||||||
|
return {};
|
||||||
|
return {
|
||||||
|
.created{u64(st.st_ctime)},
|
||||||
|
.accessed{u64(st.st_atime)},
|
||||||
|
.modified{u64(st.st_mtime)},
|
||||||
|
};
|
||||||
|
#else
|
||||||
const auto fs_path = std::filesystem::path{FS::ToU8String(full_path)};
|
const auto fs_path = std::filesystem::path{FS::ToU8String(full_path)};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
struct _stat64 file_status;
|
struct _stat64 file_status;
|
||||||
const auto stat_result = _wstat64(fs_path.c_str(), &file_status);
|
const auto stat_result = _wstat64(fs_path.c_str(), &file_status);
|
||||||
@@ -470,16 +481,14 @@ FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) cons
|
|||||||
struct stat file_status;
|
struct stat file_status;
|
||||||
const auto stat_result = stat(fs_path.c_str(), &file_status);
|
const auto stat_result = stat(fs_path.c_str(), &file_status);
|
||||||
#endif
|
#endif
|
||||||
|
if (stat_result != 0)
|
||||||
if (stat_result != 0) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
.created{static_cast<u64>(file_status.st_ctime)},
|
.created{u64(file_status.st_ctime)},
|
||||||
.accessed{static_cast<u64>(file_status.st_atime)},
|
.accessed{u64(file_status.st_atime)},
|
||||||
.modified{static_cast<u64>(file_status.st_mtime)},
|
.modified{u64(file_status.st_mtime)},
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
|
std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ std::vector<u8> DownloadImage(const std::string& url_path, const std::filesystem
|
|||||||
cli.set_connection_timeout(std::chrono::seconds(2));
|
cli.set_connection_timeout(std::chrono::seconds(2));
|
||||||
cli.set_read_timeout(std::chrono::seconds(2));
|
cli.set_read_timeout(std::chrono::seconds(2));
|
||||||
|
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
#if defined(YUZU_BUNDLED_OPENSSL) && !defined(__OPENORBIS__)
|
||||||
cli.load_ca_cert_store(kCert, sizeof(kCert));
|
cli.load_ca_cert_store(kCert, sizeof(kCert));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,13 @@ struct FontRegion {
|
|||||||
|
|
||||||
// The below data is specific to shared font data dumped from Switch on f/w 2.2
|
// The below data is specific to shared font data dumped from Switch on f/w 2.2
|
||||||
// Virtual address and offsets/sizes likely will vary by dump
|
// Virtual address and offsets/sizes likely will vary by dump
|
||||||
[[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
|
[[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR = 0x00000009d3016000ULL;
|
||||||
constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be
|
constexpr u32 EXPECTED_RESULT = 0x7f9a0218; // What we expect the decrypted bfttf first 4 bytes to be
|
||||||
constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
|
constexpr u32 EXPECTED_MAGIC = 0x36f81a1e; // What we expect the encrypted bfttf first 4 bytes to be
|
||||||
constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
|
constexpr u64 SHARED_FONT_MEM_SIZE = 0x1100000;
|
||||||
constexpr FontRegion EMPTY_REGION{0, 0};
|
constexpr FontRegion EMPTY_REGION{0, 0};
|
||||||
|
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
static void DecryptSharedFont(const std::span<u32 const> input, std::span<u8> output, std::size_t& offset) {
|
static void DecryptSharedFont(const std::span<u32 const> input, std::span<u8> output, std::size_t& offset) {
|
||||||
ASSERT(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE && "Shared fonts exceeds 17mb!");
|
ASSERT(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE && "Shared fonts exceeds 17mb!");
|
||||||
ASSERT(input[0] == EXPECTED_MAGIC && "Failed to derive key, unexpected magic number");
|
ASSERT(input[0] == EXPECTED_MAGIC && "Failed to derive key, unexpected magic number");
|
||||||
@@ -51,6 +52,7 @@ static void DecryptSharedFont(const std::span<u32 const> input, std::span<u8> ou
|
|||||||
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
||||||
offset += transformed_font.size() * sizeof(u32);
|
offset += transformed_font.size() * sizeof(u32);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
|
void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
|
||||||
ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
|
ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
|
||||||
@@ -70,7 +72,7 @@ void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, s
|
|||||||
const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC);
|
const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC);
|
||||||
std::vector<u32> transformed_font(input.size() + 2);
|
std::vector<u32> transformed_font(input.size() + 2);
|
||||||
transformed_font[0] = Common::swap32(EXPECTED_MAGIC);
|
transformed_font[0] = Common::swap32(EXPECTED_MAGIC);
|
||||||
transformed_font[1] = Common::swap32(static_cast<u32>(input.size() * sizeof(u32))) ^ key;
|
transformed_font[1] = Common::swap32(u32(input.size() * sizeof(u32))) ^ key;
|
||||||
std::transform(input.begin(), input.end(), transformed_font.begin() + 2, [key](u32 in) { return in ^ key; });
|
std::transform(input.begin(), input.end(), transformed_font.begin() + 2, [key](u32 in) { return in ^ key; });
|
||||||
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
||||||
offset += transformed_font.size() * sizeof(u32);
|
offset += transformed_font.size() * sizeof(u32);
|
||||||
@@ -83,8 +85,10 @@ struct IPlatformServiceManager::Impl {
|
|||||||
// Automatically populated based on shared_fonts dump or system archives.
|
// Automatically populated based on shared_fonts dump or system archives.
|
||||||
// 6 builtin fonts + extra 2 for whatever may come after
|
// 6 builtin fonts + extra 2 for whatever may come after
|
||||||
boost::container::static_vector<FontRegion, 8> shared_font_regions;
|
boost::container::static_vector<FontRegion, 8> shared_font_regions;
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
/// Backing memory for the shared font data
|
/// Backing memory for the shared font data
|
||||||
std::array<u8, SHARED_FONT_MEM_SIZE> shared_font;
|
std::array<u8, SHARED_FONT_MEM_SIZE> shared_font;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
|
IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
|
||||||
@@ -111,49 +115,40 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
auto& fsc = system.GetFileSystemController();
|
auto& fsc = system.GetFileSystemController();
|
||||||
|
|
||||||
// Attempt to load shared font data from disk
|
// Attempt to load shared font data from disk
|
||||||
const auto* nand = fsc.GetSystemNANDContents();
|
const auto* nand = fsc.GetSystemNANDContents();
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
// Rebuild shared fonts from data ncas or synthesize
|
// Rebuild shared fonts from data ncas or synthesize
|
||||||
for (auto& font : SHARED_FONTS) {
|
for (auto& font : SHARED_FONTS) {
|
||||||
FileSys::VirtualFile romfs;
|
FileSys::VirtualFile romfs;
|
||||||
const auto nca =
|
if (auto const nca = nand->GetEntry(u64(font.first), FileSys::ContentRecordType::Data); nca)
|
||||||
nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
|
|
||||||
if (nca) {
|
|
||||||
romfs = nca->GetRomFS();
|
romfs = nca->GetRomFS();
|
||||||
}
|
if (!romfs)
|
||||||
|
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(u64(font.first));
|
||||||
if (!romfs) {
|
if (romfs) {
|
||||||
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(static_cast<u64>(font.first));
|
if (auto const extracted_romfs = FileSys::ExtractRomFS(romfs); extracted_romfs) {
|
||||||
}
|
if (auto const font_fp = extracted_romfs->GetFile(font.second); font_fp) {
|
||||||
|
std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32));
|
||||||
if (!romfs) {
|
font_fp->ReadBytes<u32>(font_data_u32.data(), font_fp->GetSize());
|
||||||
|
// We need to be BigEndian as u32s for the xor encryption
|
||||||
|
std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), Common::swap32);
|
||||||
|
// Font offset and size do not account for the header
|
||||||
|
const FontRegion region{u32(offset + 8), u32((font_data_u32.size() * sizeof(u32)) - 8)};
|
||||||
|
DecryptSharedFont(font_data_u32, impl->shared_font, offset);
|
||||||
|
impl->shared_font_regions.push_back(region);
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", font.first, font.second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", font.first);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first);
|
LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto extracted_romfs = FileSys::ExtractRomFS(romfs);
|
|
||||||
if (!extracted_romfs) {
|
|
||||||
LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", font.first);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto font_fp = extracted_romfs->GetFile(font.second);
|
|
||||||
if (!font_fp) {
|
|
||||||
LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", font.first, font.second);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32));
|
|
||||||
font_fp->ReadBytes<u32>(font_data_u32.data(), font_fp->GetSize());
|
|
||||||
// We need to be BigEndian as u32s for the xor encryption
|
|
||||||
std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(),
|
|
||||||
Common::swap32);
|
|
||||||
// Font offset and size do not account for the header
|
|
||||||
const FontRegion region{u32(offset + 8), u32((font_data_u32.size() * sizeof(u32)) - 8)};
|
|
||||||
DecryptSharedFont(font_data_u32, impl->shared_font, offset);
|
|
||||||
impl->shared_font_regions.push_back(region);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
IPlatformServiceManager::~IPlatformServiceManager() = default;
|
IPlatformServiceManager::~IPlatformServiceManager() = default;
|
||||||
@@ -187,8 +182,10 @@ Result IPlatformServiceManager::GetSharedMemoryNativeHandle(OutCopyHandle<Kernel
|
|||||||
// Map backing memory for the font data
|
// Map backing memory for the font data
|
||||||
LOG_DEBUG(Service_NS, "called");
|
LOG_DEBUG(Service_NS, "called");
|
||||||
|
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
// Create shared font memory object
|
// Create shared font memory object
|
||||||
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font.data(), impl->shared_font.size());
|
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font.data(), impl->shared_font.size());
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME: this shouldn't belong to the kernel
|
// FIXME: this shouldn't belong to the kernel
|
||||||
*out_shared_memory_native_handle = &kernel.GetFontSharedMem();
|
*out_shared_memory_native_handle = &kernel.GetFontSharedMem();
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -60,7 +63,11 @@ private:
|
|||||||
std::size_t current_index{0};
|
std::size_t current_index{0};
|
||||||
/// Stores an hour of historical frametime data useful for processing and tracking performance
|
/// Stores an hour of historical frametime data useful for processing and tracking performance
|
||||||
/// regressions with code changes.
|
/// regressions with code changes.
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
std::array<double, 60> perf_history{};
|
||||||
|
#else
|
||||||
std::array<double, 216000> perf_history{};
|
std::array<double, 216000> perf_history{};
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Point when the cumulative counters were reset
|
/// Point when the cumulative counters were reset
|
||||||
Clock::time_point reset_point = Clock::now();
|
Clock::time_point reset_point = Clock::now();
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ add_library(dynarmic STATIC
|
|||||||
interface/halt_reason.h
|
interface/halt_reason.h
|
||||||
interface/exclusive_monitor.h
|
interface/exclusive_monitor.h
|
||||||
interface/optimization_flags.h
|
interface/optimization_flags.h
|
||||||
interface/halt_reason.h
|
|
||||||
ir/acc_type.h
|
ir/acc_type.h
|
||||||
ir/basic_block.cpp
|
ir/basic_block.cpp
|
||||||
ir/basic_block.h
|
ir/basic_block.h
|
||||||
@@ -140,8 +139,10 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
|||||||
# Newer versions of xbyak (>= 7.25.0) have stricter checks that currently
|
# Newer versions of xbyak (>= 7.25.0) have stricter checks that currently
|
||||||
# fail in dynarmic
|
# fail in dynarmic
|
||||||
target_compile_definitions(dynarmic PRIVATE XBYAK_STRICT_CHECK_MEM_REG_SIZE=0)
|
target_compile_definitions(dynarmic PRIVATE XBYAK_STRICT_CHECK_MEM_REG_SIZE=0)
|
||||||
|
|
||||||
target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1)
|
target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1)
|
||||||
target_link_libraries(dynarmic PRIVATE xbyak::xbyak)
|
target_link_libraries(dynarmic PRIVATE xbyak::xbyak)
|
||||||
|
|
||||||
target_architecture_specific_sources(dynarmic "x86_64"
|
target_architecture_specific_sources(dynarmic "x86_64"
|
||||||
backend/x64/abi.cpp
|
backend/x64/abi.cpp
|
||||||
backend/x64/abi.h
|
backend/x64/abi.h
|
||||||
@@ -293,35 +294,6 @@ if ("riscv64" IN_LIST ARCHITECTURE)
|
|||||||
)
|
)
|
||||||
message(WARNING "TODO: Incomplete frontend for this host architecture")
|
message(WARNING "TODO: Incomplete frontend for this host architecture")
|
||||||
endif()
|
endif()
|
||||||
if ("powerpc64" IN_LIST ARCHITECTURE)
|
|
||||||
target_link_libraries(dynarmic PRIVATE powah)
|
|
||||||
target_sources(dynarmic PRIVATE
|
|
||||||
backend/ppc64/abi.h
|
|
||||||
backend/ppc64/emit_context.h
|
|
||||||
backend/ppc64/emit_ppc64_a32.cpp
|
|
||||||
backend/ppc64/emit_ppc64_a64.cpp
|
|
||||||
backend/ppc64/emit_ppc64_misc.cpp
|
|
||||||
backend/ppc64/emit_ppc64_data_processing.cpp
|
|
||||||
backend/ppc64/emit_ppc64_floating_point.cpp
|
|
||||||
backend/ppc64/emit_ppc64_vector.cpp
|
|
||||||
backend/ppc64/emit_ppc64.cpp
|
|
||||||
backend/ppc64/emit_ppc64.h
|
|
||||||
backend/ppc64/exclusive_monitor.cpp
|
|
||||||
backend/ppc64/reg_alloc.cpp
|
|
||||||
backend/ppc64/reg_alloc.h
|
|
||||||
backend/ppc64/stack_layout.h
|
|
||||||
backend/ppc64/hostloc.h
|
|
||||||
common/spin_lock_ppc64.cpp
|
|
||||||
common/spin_lock_ppc64.h
|
|
||||||
# A32
|
|
||||||
backend/ppc64/a32_core.h
|
|
||||||
backend/ppc64/a32_interface.cpp
|
|
||||||
# A64
|
|
||||||
backend/ppc64/a64_core.h
|
|
||||||
backend/ppc64/a64_interface.cpp
|
|
||||||
backend/ppc64/code_block.h
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ("loongarch64" IN_LIST ARCHITECTURE)
|
if ("loongarch64" IN_LIST ARCHITECTURE)
|
||||||
target_link_libraries(dynarmic PRIVATE lagoon::lagoon)
|
target_link_libraries(dynarmic PRIVATE lagoon::lagoon)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#if defined(ARCHITECTURE_x86_64)
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend::X64 {
|
||||||
class BlockOfCode;
|
class BlockOfCode;
|
||||||
}
|
} // namespace Dynarmic::Backend::X64
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
#elif defined(ARCHITECTURE_arm64)
|
||||||
namespace oaknut {
|
namespace oaknut {
|
||||||
class CodeBlock;
|
class CodeBlock;
|
||||||
@@ -30,10 +30,6 @@ class CodeBlock;
|
|||||||
namespace Dynarmic::Backend::LoongArch64 {
|
namespace Dynarmic::Backend::LoongArch64 {
|
||||||
class CodeBlock;
|
class CodeBlock;
|
||||||
} // namespace Dynarmic::Backend::LoongArch64
|
} // namespace Dynarmic::Backend::LoongArch64
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
class CodeBlock;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
@@ -57,9 +53,6 @@ struct FakeCall {
|
|||||||
struct FakeCall {
|
struct FakeCall {
|
||||||
u64 call_pc;
|
u64 call_pc;
|
||||||
};
|
};
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
struct FakeCall {
|
|
||||||
};
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
@@ -77,8 +70,6 @@ public:
|
|||||||
void Register(RV64::CodeBlock& mem, std::size_t mem_size);
|
void Register(RV64::CodeBlock& mem, std::size_t mem_size);
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
void Register(LoongArch64::CodeBlock& mem, std::size_t mem_size);
|
void Register(LoongArch64::CodeBlock& mem, std::size_t mem_size);
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
void Register(PPC64::CodeBlock& mem, std::size_t mem_size);
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,21 +17,24 @@ ExceptionHandler::ExceptionHandler() = default;
|
|||||||
ExceptionHandler::~ExceptionHandler() = default;
|
ExceptionHandler::~ExceptionHandler() = default;
|
||||||
|
|
||||||
#if defined(ARCHITECTURE_x86_64)
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
void ExceptionHandler::Register(X64::BlockOfCode&)
|
void ExceptionHandler::Register(X64::BlockOfCode&) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
#elif defined(ARCHITECTURE_arm64)
|
||||||
void ExceptionHandler::Register(oaknut::CodeBlock&, std::size_t)
|
void ExceptionHandler::Register(oaknut::CodeBlock&, std::size_t) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
#elif defined(ARCHITECTURE_riscv64)
|
#elif defined(ARCHITECTURE_riscv64)
|
||||||
void ExceptionHandler::Register(RV64::CodeBlock&, std::size_t)
|
void ExceptionHandler::Register(RV64::CodeBlock&, std::size_t) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
void ExceptionHandler::Register(LoongArch64::CodeBlock&, std::size_t)
|
void ExceptionHandler::Register(LoongArch64::CodeBlock&, std::size_t) {
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
// Do nothing
|
||||||
void ExceptionHandler::Register(PPC64::CodeBlock&, std::size_t)
|
}
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -36,8 +35,6 @@
|
|||||||
# include "dynarmic/backend/riscv64/code_block.h"
|
# include "dynarmic/backend/riscv64/code_block.h"
|
||||||
#elif defined(ARCHITECTURE_loongarch64)
|
#elif defined(ARCHITECTURE_loongarch64)
|
||||||
# include "dynarmic/backend/loongarch64/code_block.h"
|
# include "dynarmic/backend/loongarch64/code_block.h"
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
# include "dynarmic/backend/ppc64/code_block.h"
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
@@ -69,12 +66,16 @@ public:
|
|||||||
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
||||||
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
|
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
fmt::print(stderr, "no fastmem on PS4\n");
|
||||||
|
supports_fast_mem = false;
|
||||||
|
#else
|
||||||
stack_t signal_stack{};
|
stack_t signal_stack{};
|
||||||
signal_stack.ss_sp = signal_stack_memory.get();
|
signal_stack.ss_sp = signal_stack_memory.get();
|
||||||
signal_stack.ss_size = stack_size;
|
signal_stack.ss_size = stack_size;
|
||||||
signal_stack.ss_flags = 0;
|
signal_stack.ss_flags = 0;
|
||||||
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
|
fmt::print(stderr, "POSIX SigHandler: init failure at sigaltstack\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -85,16 +86,17 @@ public:
|
|||||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
if (sigaction(SIGSEGV, &sa, &old_sa_segv) != 0) {
|
if (sigaction(SIGSEGV, &sa, &old_sa_segv) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGSEGV handler\n");
|
fmt::print(stderr, "POSIX SigHandler: could not set SIGSEGV handler\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
|
fmt::print(stderr, "POSIX SigHandler: could not set SIGBUS handler\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +150,9 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
|||||||
}
|
}
|
||||||
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
// No fastmem
|
||||||
|
#else
|
||||||
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
||||||
if (retry_sa->sa_flags & SA_SIGINFO) {
|
if (retry_sa->sa_flags & SA_SIGINFO) {
|
||||||
retry_sa->sa_sigaction(sig, info, raw_context);
|
retry_sa->sa_sigaction(sig, info, raw_context);
|
||||||
@@ -161,6 +166,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
retry_sa->sa_handler(sig);
|
retry_sa->sa_handler(sig);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@@ -208,10 +214,6 @@ void ExceptionHandler::Register(RV64::CodeBlock& mem, std::size_t size) {
|
|||||||
void ExceptionHandler::Register(LoongArch64::CodeBlock& mem, std::size_t size) {
|
void ExceptionHandler::Register(LoongArch64::CodeBlock& mem, std::size_t size) {
|
||||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
||||||
}
|
}
|
||||||
#elif defined(ARCHITECTURE_powerpc64)
|
|
||||||
void ExceptionHandler::Register(PPC64::CodeBlock& mem, std::size_t size) {
|
|
||||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
# error "Invalid architecture"
|
# error "Invalid architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include "dynarmic/backend/ppc64/code_block.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
|
||||||
#include "dynarmic/interface/A32/config.h"
|
|
||||||
#include "dynarmic/ir/terminal.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct A32JitState {
|
|
||||||
std::array<u32, 16> regs{};
|
|
||||||
alignas(16) std::array<u32, 64> ext_regs{};
|
|
||||||
u32 upper_location_descriptor;
|
|
||||||
u32 exclusive_state = 0;
|
|
||||||
u32 cpsr_nzcv = 0;
|
|
||||||
u32 fpscr = 0;
|
|
||||||
u32 check_bit = 0;
|
|
||||||
|
|
||||||
IR::LocationDescriptor GetLocationDescriptor() const {
|
|
||||||
return IR::LocationDescriptor{regs[15] | (u64(upper_location_descriptor) << 32)};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
|
||||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
|
||||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
|
||||||
#include "dynarmic/interface/A32/config.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/common/atomic.h"
|
|
||||||
#include "dynarmic/ir/opt_passes.h"
|
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
|
||||||
|
|
||||||
using namespace Dynarmic::Backend::PPC64;
|
|
||||||
using CodePtr = std::uint32_t*;
|
|
||||||
|
|
||||||
struct A32AddressSpace final {
|
|
||||||
explicit A32AddressSpace(const A32::UserConfig& conf)
|
|
||||||
: conf(conf)
|
|
||||||
, cb(conf.code_cache_size)
|
|
||||||
, as(cb.ptr<u8*>(), conf.code_cache_size) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CodePtr GetOrEmit(IR::LocationDescriptor desc) {
|
|
||||||
if (auto const it = block_entries.find(desc.Value()); it != block_entries.end())
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
ir_block.Reset(A32::LocationDescriptor{desc});
|
|
||||||
A32::Translate(ir_block, A32::LocationDescriptor{desc}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
|
||||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
|
||||||
|
|
||||||
block_infos.insert_or_assign(desc.Value(), block_info);
|
|
||||||
block_entries.insert_or_assign(desc.Value(), block_info.entry_point);
|
|
||||||
return block_info.entry_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
block_entries.clear();
|
|
||||||
block_infos.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
EmittedBlockInfo Emit(IR::Block block) {
|
|
||||||
EmittedBlockInfo block_info = EmitPPC64(as, std::move(block), {
|
|
||||||
.enable_cycle_counting = conf.enable_cycle_counting,
|
|
||||||
.always_little_endian = conf.always_little_endian,
|
|
||||||
.a64_variant = false
|
|
||||||
});
|
|
||||||
Link(block_info);
|
|
||||||
return block_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Link(EmittedBlockInfo& block_info) {
|
|
||||||
//UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
IR::Block ir_block = {LocationDescriptor(0, PSR(0), FPSCR(0), false)};
|
|
||||||
const A32::UserConfig conf;
|
|
||||||
CodeBlock cb;
|
|
||||||
powah::Context as;
|
|
||||||
ankerl::unordered_dense::map<u64, CodePtr> block_entries;
|
|
||||||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> block_infos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct A32Core final {
|
|
||||||
static HaltReason Run(A32AddressSpace& process, A32JitState& thread_ctx, volatile u32* halt_reason) {
|
|
||||||
auto const loc = thread_ctx.GetLocationDescriptor();
|
|
||||||
auto const entry = process.GetOrEmit(loc);
|
|
||||||
using CodeFn = HaltReason (*)(A32AddressSpace*, A32JitState*, volatile u32*, void*);
|
|
||||||
return (CodeFn(entry))(&process, &thread_ctx, halt_reason, reinterpret_cast<void*>(&A32Core::Run));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Jit::Impl final {
|
|
||||||
Impl(Jit* jit_interface, A32::UserConfig conf)
|
|
||||||
: conf(conf)
|
|
||||||
, current_address_space(conf)
|
|
||||||
, jit_interface(jit_interface) {}
|
|
||||||
|
|
||||||
HaltReason Run() {
|
|
||||||
ASSERT(!is_executing);
|
|
||||||
is_executing = false;
|
|
||||||
HaltReason hr = A32Core::Run(current_address_space, jit_state, &halt_reason);
|
|
||||||
is_executing = true;
|
|
||||||
RequestCacheInvalidation();
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Step() {
|
|
||||||
// HaltReason hr = A32Core::Step(current_address_space, jit_state, &halt_reason);
|
|
||||||
// RequestCacheInvalidation();
|
|
||||||
return HaltReason{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidateCacheRange(u32 start_address, size_t length) {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u32>::closed(start_address, u32(start_address + length - 1)));
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
jit_state = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
|
||||||
Atomic::Or(&halt_reason, ~u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
|
||||||
Atomic::And(&halt_reason, ~u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 16>& Regs() {
|
|
||||||
return jit_state.regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 16>& Regs() const {
|
|
||||||
return jit_state.regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 64>& ExtRegs() {
|
|
||||||
return jit_state.ext_regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 64>& ExtRegs() const {
|
|
||||||
return jit_state.ext_regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Cpsr() const {
|
|
||||||
return jit_state.cpsr_nzcv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetCpsr(u32 value) {
|
|
||||||
jit_state.cpsr_nzcv = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Fpscr() const {
|
|
||||||
return jit_state.fpscr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFpscr(u32 value) {
|
|
||||||
jit_state.fpscr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearExclusiveState() {
|
|
||||||
jit_state.exclusive_state = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RequestCacheInvalidation() {
|
|
||||||
// UNREACHABLE();
|
|
||||||
invalidate_entire_cache = false;
|
|
||||||
invalid_cache_ranges.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
A32::UserConfig conf;
|
|
||||||
A32JitState jit_state{};
|
|
||||||
A32AddressSpace current_address_space;
|
|
||||||
Jit* jit_interface;
|
|
||||||
volatile u32 halt_reason = 0;
|
|
||||||
bool is_executing = false;
|
|
||||||
|
|
||||||
boost::icl::interval_set<u32> invalid_cache_ranges;
|
|
||||||
bool invalidate_entire_cache = false;
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf) : impl(std::make_unique<Impl>(this, conf)) {}
|
|
||||||
Jit::~Jit() = default;
|
|
||||||
|
|
||||||
HaltReason Jit::Run() {
|
|
||||||
return impl->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Jit::Step() {
|
|
||||||
return impl->Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
|
||||||
impl->ClearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
|
||||||
impl->InvalidateCacheRange(start_address, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::Reset() {
|
|
||||||
impl->Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::HaltExecution(HaltReason hr) {
|
|
||||||
impl->HaltExecution(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearHalt(HaltReason hr) {
|
|
||||||
impl->ClearHalt(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 16>& Jit::Regs() {
|
|
||||||
return impl->Regs();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 16>& Jit::Regs() const {
|
|
||||||
return impl->Regs();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u32, 64>& Jit::ExtRegs() {
|
|
||||||
return impl->ExtRegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<u32, 64>& Jit::ExtRegs() const {
|
|
||||||
return impl->ExtRegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::Cpsr() const {
|
|
||||||
return impl->Cpsr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetCpsr(u32 value) {
|
|
||||||
impl->SetCpsr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::Fpscr() const {
|
|
||||||
return impl->Fpscr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetFpscr(u32 value) {
|
|
||||||
impl->SetFpscr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearExclusiveState() {
|
|
||||||
impl->ClearExclusiveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include "dynarmic/backend/ppc64/code_block.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
|
||||||
#include "dynarmic/interface/A64/a64.h"
|
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
#include "dynarmic/ir/terminal.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct A64JitState {
|
|
||||||
using ProgramCounterType = u32;
|
|
||||||
std::array<u64, 31> regs{};
|
|
||||||
u64 pc = 0;
|
|
||||||
alignas(16) std::array<u64, 64> vec{};
|
|
||||||
u64 sp = 0;
|
|
||||||
u32 upper_location_descriptor = 0;
|
|
||||||
u32 exclusive_state = 0;
|
|
||||||
u32 pstate = 0;
|
|
||||||
u32 fpcr = 0;
|
|
||||||
u32 fpsr = 0;
|
|
||||||
volatile u32 halt_reason = 0;
|
|
||||||
u32 check_bit = 0;
|
|
||||||
|
|
||||||
IR::LocationDescriptor GetLocationDescriptor() const {
|
|
||||||
const u64 fpcr_u64 = u64(fpcr & A64::LocationDescriptor::fpcr_mask) << A64::LocationDescriptor::fpcr_shift;
|
|
||||||
const u64 pc_u64 = pc & A64::LocationDescriptor::pc_mask;
|
|
||||||
return IR::LocationDescriptor{pc_u64 | fpcr_u64};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
|
||||||
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/common/atomic.h"
|
|
||||||
#include "dynarmic/ir/opt_passes.h"
|
|
||||||
#include "dynarmic/interface/A64/a64.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A64 {
|
|
||||||
|
|
||||||
using namespace Dynarmic::Backend::PPC64;
|
|
||||||
using CodePtr = std::uint32_t*;
|
|
||||||
|
|
||||||
struct A64AddressSpace final {
|
|
||||||
explicit A64AddressSpace(const A64::UserConfig& conf)
|
|
||||||
: conf(conf)
|
|
||||||
, cb(conf.code_cache_size)
|
|
||||||
, as(cb.ptr<u8*>(), conf.code_cache_size)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CodePtr GetOrEmit(IR::LocationDescriptor desc) {
|
|
||||||
if (auto const it = block_entries.find(desc.Value()); it != block_entries.end())
|
|
||||||
return it->second;
|
|
||||||
auto const get_code = [this](u64 vaddr) {
|
|
||||||
return conf.callbacks->MemoryReadCode(vaddr);
|
|
||||||
};
|
|
||||||
ir_block.Reset(A64::LocationDescriptor{desc});
|
|
||||||
A64::Translate(ir_block, A64::LocationDescriptor{desc}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
|
||||||
Optimization::Optimize(ir_block, conf, {});
|
|
||||||
fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block));
|
|
||||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
|
||||||
block_infos.insert_or_assign(desc.Value(), block_info);
|
|
||||||
block_entries.insert_or_assign(desc.Value(), block_info.entry_point);
|
|
||||||
return block_info.entry_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
block_entries.clear();
|
|
||||||
block_infos.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
EmittedBlockInfo Emit(IR::Block block) {
|
|
||||||
EmittedBlockInfo block_info = EmitPPC64(as, std::move(block), {
|
|
||||||
.enable_cycle_counting = conf.enable_cycle_counting,
|
|
||||||
.always_little_endian = true,
|
|
||||||
.a64_variant = true
|
|
||||||
});
|
|
||||||
Link(block_info);
|
|
||||||
return block_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Link(EmittedBlockInfo& block_info) {
|
|
||||||
// TODO(lizzie): Block linking
|
|
||||||
// UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
IR::Block ir_block = {LocationDescriptor(0, FP::FPCR(0), false)};
|
|
||||||
const A64::UserConfig conf;
|
|
||||||
CodeBlock cb;
|
|
||||||
powah::Context as;
|
|
||||||
ankerl::unordered_dense::map<u64, CodePtr> block_entries;
|
|
||||||
ankerl::unordered_dense::map<u64, EmittedBlockInfo> block_infos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct A64Core final {
|
|
||||||
using CodeFn = HaltReason (*)(A64AddressSpace*, A64JitState*, volatile u32*, void *fn);
|
|
||||||
static HaltReason Run(A64AddressSpace& process, A64JitState& thread_ctx, volatile u32* halt_reason) {
|
|
||||||
HaltReason hr{};
|
|
||||||
do {
|
|
||||||
const auto loc = thread_ctx.GetLocationDescriptor();
|
|
||||||
const auto entry = process.GetOrEmit(loc);
|
|
||||||
hr = (CodeFn(entry))(&process, &thread_ctx, halt_reason, (void*)&A64Core::Run);
|
|
||||||
} while (hr == HaltReason(0));
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Jit::Impl final {
|
|
||||||
Impl(Jit* jit_interface, A64::UserConfig conf)
|
|
||||||
: conf(conf)
|
|
||||||
, current_address_space(conf)
|
|
||||||
, jit_interface(jit_interface) {}
|
|
||||||
|
|
||||||
HaltReason Run() {
|
|
||||||
ASSERT(!is_executing);
|
|
||||||
is_executing = true;
|
|
||||||
HaltReason hr = A64Core::Run(current_address_space, jit_state, &halt_reason);
|
|
||||||
is_executing = false;
|
|
||||||
RequestCacheInvalidation();
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Step() {
|
|
||||||
// HaltReason hr = A64Core::Step(current_address_space, jit_state, &halt_reason);
|
|
||||||
// RequestCacheInvalidation();
|
|
||||||
return HaltReason{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearCache() {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
invalidate_entire_cache = true;
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidateCacheRange(u64 start_address, size_t length) {
|
|
||||||
std::unique_lock lock{invalidation_mutex};
|
|
||||||
const auto end_address = u64(start_address + length - 1);
|
|
||||||
invalid_cache_ranges.add(boost::icl::discrete_interval<u64>::closed(start_address, end_address));
|
|
||||||
HaltExecution(HaltReason::CacheInvalidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
ASSERT(!is_executing);
|
|
||||||
jit_state = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void HaltExecution(HaltReason hr) {
|
|
||||||
Atomic::Or(&jit_state.halt_reason, u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearHalt(HaltReason hr) {
|
|
||||||
Atomic::And(&jit_state.halt_reason, ~u32(hr));
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetSP() const {
|
|
||||||
return jit_state.sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSP(u64 value) {
|
|
||||||
jit_state.sp = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetPC() const {
|
|
||||||
return jit_state.pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPC(u64 value) {
|
|
||||||
jit_state.pc = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetRegister(size_t index) const {
|
|
||||||
return index == 31 ? GetSP() : jit_state.regs.at(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRegister(size_t index, u64 value) {
|
|
||||||
if (index == 31)
|
|
||||||
return SetSP(value);
|
|
||||||
jit_state.regs.at(index) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u64, 31> GetRegisters() const {
|
|
||||||
return jit_state.regs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRegisters(const std::array<u64, 31>& value) {
|
|
||||||
jit_state.regs = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector GetVector(size_t index) const {
|
|
||||||
return {jit_state.vec.at(index * 2), jit_state.vec.at(index * 2 + 1)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVector(size_t index, Vector value) {
|
|
||||||
jit_state.vec.at(index * 2) = value[0];
|
|
||||||
jit_state.vec.at(index * 2 + 1) = value[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<Vector, 32> GetVectors() const {
|
|
||||||
std::array<Vector, 32> ret;
|
|
||||||
static_assert(sizeof(ret) == sizeof(jit_state.vec));
|
|
||||||
std::memcpy(ret.data(), jit_state.vec.data(), sizeof(jit_state.vec));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVectors(const std::array<Vector, 32>& value) {
|
|
||||||
static_assert(sizeof(value) == sizeof(jit_state.vec));
|
|
||||||
std::memcpy(jit_state.vec.data(), value.data(), sizeof(jit_state.vec));
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFpcr() const {
|
|
||||||
return jit_state.fpcr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFpcr(u32 value) {
|
|
||||||
jit_state.fpcr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFpsr() const {
|
|
||||||
return jit_state.fpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFpsr(u32 value) {
|
|
||||||
jit_state.fpsr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetPstate() const {
|
|
||||||
return jit_state.pstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPstate(u32 value) {
|
|
||||||
jit_state.pstate = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearExclusiveState() {
|
|
||||||
jit_state.exclusive_state = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsExecuting() const {
|
|
||||||
return is_executing;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Disassemble() const {
|
|
||||||
// const size_t size = reinterpret_cast<const char*>(block_of_code.getCurr()) - reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
|
||||||
// auto const* p = reinterpret_cast<const char*>(block_of_code.GetCodeBegin());
|
|
||||||
// return Common::DisassemblePPC64(p, p + size);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RequestCacheInvalidation() {
|
|
||||||
// UNREACHABLE();
|
|
||||||
invalidate_entire_cache = false;
|
|
||||||
invalid_cache_ranges.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
A64::UserConfig conf;
|
|
||||||
A64JitState jit_state{};
|
|
||||||
A64AddressSpace current_address_space;
|
|
||||||
Jit* jit_interface;
|
|
||||||
volatile u32 halt_reason = 0;
|
|
||||||
bool is_executing = false;
|
|
||||||
|
|
||||||
boost::icl::interval_set<u64> invalid_cache_ranges;
|
|
||||||
bool invalidate_entire_cache = false;
|
|
||||||
std::mutex invalidation_mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Jit::Jit(UserConfig conf) : impl(std::make_unique<Jit::Impl>(this, conf)) {}
|
|
||||||
Jit::~Jit() = default;
|
|
||||||
|
|
||||||
HaltReason Jit::Run() {
|
|
||||||
return impl->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
HaltReason Jit::Step() {
|
|
||||||
return impl->Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearCache() {
|
|
||||||
impl->ClearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::InvalidateCacheRange(u64 start_address, size_t length) {
|
|
||||||
impl->InvalidateCacheRange(start_address, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::Reset() {
|
|
||||||
impl->Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::HaltExecution(HaltReason hr) {
|
|
||||||
impl->HaltExecution(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearHalt(HaltReason hr) {
|
|
||||||
impl->ClearHalt(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Jit::GetSP() const {
|
|
||||||
return impl->GetSP();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetSP(u64 value) {
|
|
||||||
impl->SetSP(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Jit::GetPC() const {
|
|
||||||
return impl->GetPC();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetPC(u64 value) {
|
|
||||||
impl->SetPC(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Jit::GetRegister(size_t index) const {
|
|
||||||
return impl->GetRegister(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetRegister(size_t index, u64 value) {
|
|
||||||
impl->SetRegister(index, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u64, 31> Jit::GetRegisters() const {
|
|
||||||
return impl->GetRegisters();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetRegisters(const std::array<u64, 31>& value) {
|
|
||||||
impl->SetRegisters(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector Jit::GetVector(size_t index) const {
|
|
||||||
return impl->GetVector(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetVector(size_t index, Vector value) {
|
|
||||||
impl->SetVector(index, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<Vector, 32> Jit::GetVectors() const {
|
|
||||||
return impl->GetVectors();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetVectors(const std::array<Vector, 32>& value) {
|
|
||||||
impl->SetVectors(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::GetFpcr() const {
|
|
||||||
return impl->GetFpcr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetFpcr(u32 value) {
|
|
||||||
impl->SetFpcr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::GetFpsr() const {
|
|
||||||
return impl->GetFpsr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetFpsr(u32 value) {
|
|
||||||
impl->SetFpsr(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Jit::GetPstate() const {
|
|
||||||
return impl->GetPstate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::SetPstate(u32 value) {
|
|
||||||
impl->SetPstate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Jit::ClearExclusiveState() {
|
|
||||||
impl->ClearExclusiveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Jit::IsExecuting() const {
|
|
||||||
return impl->IsExecuting();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Jit::Disassemble() const {
|
|
||||||
return impl->Disassemble();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
/*
|
|
||||||
https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#REG
|
|
||||||
|
|
||||||
r0 Volatile register used in function prologs
|
|
||||||
r1 Stack frame pointer
|
|
||||||
r2 TOC pointer
|
|
||||||
r3 Volatile parameter and return value register
|
|
||||||
r4-r10 Volatile registers used for function parameters
|
|
||||||
r11 Volatile register used in calls by pointer and as an environment pointer for languages which require one
|
|
||||||
r12 Volatile register used for exception handling and glink code
|
|
||||||
r13 Reserved for use as system thread ID
|
|
||||||
r14-r31 Nonvolatile registers used for local variables
|
|
||||||
|
|
||||||
f0 Volatile scratch register
|
|
||||||
f1-f4 Volatile floating point parameter and return value registers
|
|
||||||
f5-f13 Volatile floating point parameter registers
|
|
||||||
f14-f31 Nonvolatile registers
|
|
||||||
|
|
||||||
LR Link register (volatile)
|
|
||||||
CTR Loop counter register (volatile)
|
|
||||||
XER Fixed point exception register (volatile)
|
|
||||||
FPSCR Floating point status and control register (volatile)
|
|
||||||
|
|
||||||
CR0-CR1 Volatile condition code register fields
|
|
||||||
CR2-CR4 Nonvolatile condition code register fields
|
|
||||||
CR5-CR7 Volatile condition code register fields
|
|
||||||
|
|
||||||
v0-v1 Volatile scratch registers
|
|
||||||
v2-v13 Volatile vector parameters registers
|
|
||||||
v14-v19 Volatile scratch registers
|
|
||||||
v20-v31 Non-volatile registers
|
|
||||||
vrsave Non-volatile 32-bit register
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Jit fn signature => (AXXAddressSpace& process, AXXJitState& thread_ctx, volatile u32* halt_reason)
|
|
||||||
constexpr powah::GPR RPROCESS = powah::R3;
|
|
||||||
constexpr powah::GPR RJIT = powah::R4;
|
|
||||||
constexpr powah::GPR RHALTREASON = powah::R5;
|
|
||||||
constexpr powah::GPR RTOCPTR = powah::R6;
|
|
||||||
// temporals
|
|
||||||
constexpr powah::GPR RNZCV = powah::R7;
|
|
||||||
|
|
||||||
constexpr powah::GPR ABI_PARAM1 = powah::R3;
|
|
||||||
constexpr powah::GPR ABI_PARAM2 = powah::R4;
|
|
||||||
constexpr powah::GPR ABI_PARAM3 = powah::R5;
|
|
||||||
constexpr powah::GPR ABI_PARAM4 = powah::R6;
|
|
||||||
|
|
||||||
// See https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#REG
|
|
||||||
constexpr std::initializer_list<u32> GPR_ORDER{
|
|
||||||
// r13 is thread-id
|
|
||||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 //non-volatile
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr std::initializer_list<powah::GPR> ABI_CALLEER_SAVED{
|
|
||||||
powah::R3, powah::R4, powah::R5, powah::R6,
|
|
||||||
powah::R7, powah::R8, powah::R9, powah::R10,
|
|
||||||
powah::R11, powah::R12
|
|
||||||
};
|
|
||||||
constexpr std::initializer_list<powah::GPR> ABI_CALLEE_SAVED{
|
|
||||||
powah::R14, powah::R15, powah::R16, powah::R17,
|
|
||||||
powah::R18, powah::R19, powah::R20, powah::R21,
|
|
||||||
powah::R22, powah::R23, powah::R24, powah::R25,
|
|
||||||
powah::R26, powah::R27, powah::R28, powah::R29,
|
|
||||||
powah::R30, powah::R31
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <new>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
class CodeBlock {
|
|
||||||
public:
|
|
||||||
explicit CodeBlock(size_t size_) noexcept : size{size_} {
|
|
||||||
block = (u8*)mmap(nullptr, size, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
//printf("block = %p, size= %zx\n", block, size);
|
|
||||||
ASSERT(block != nullptr);
|
|
||||||
}
|
|
||||||
~CodeBlock() noexcept {
|
|
||||||
if (block != nullptr)
|
|
||||||
munmap(block, size);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
T ptr() const noexcept {
|
|
||||||
static_assert(std::is_pointer_v<T> || std::is_same_v<T, uintptr_t> || std::is_same_v<T, intptr_t>);
|
|
||||||
return reinterpret_cast<T>(block);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
void* block = nullptr;
|
|
||||||
size_t size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
|
||||||
class Block;
|
|
||||||
} // namespace Dynarmic::IR
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct EmitConfig;
|
|
||||||
|
|
||||||
struct EmitContext {
|
|
||||||
IR::Block& block;
|
|
||||||
RegAlloc& reg_alloc;
|
|
||||||
const EmitConfig& emit_conf;
|
|
||||||
EmittedBlockInfo& ebi;
|
|
||||||
// label used when returning :)
|
|
||||||
powah::Label l_return;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,305 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <bit>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/backend/ppc64/stack_layout.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
#include "stack_layout.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Void>(powah::Context&, EmitContext&, IR::Inst*) {}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Identity>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.MR(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Breakpoint>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CallHostFunction>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PushRSB>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetCarryFromOp>(powah::Context&, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetOverflowFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetGEFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetNZCVFromOp>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (ctx.reg_alloc.IsValueLive(inst)) {
|
|
||||||
ASSERT(false && "unimp value live");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All logical operations whom set (RC) are going to compute as the following:
|
|
||||||
// 1. Rt <- logical_op (Ra, Rb)
|
|
||||||
// 2. Compare as Signed(Rt) against 0
|
|
||||||
// Basically, it's equivalent to say:
|
|
||||||
//
|
|
||||||
// add r0, r1, r2 -> add. r0, r1, r2
|
|
||||||
// cmpli r0, 0
|
|
||||||
//
|
|
||||||
// CR0:
|
|
||||||
// 0 - 0x08 - N/LT, result is negative
|
|
||||||
// 1 - 0x04 - P/GT, result is positive
|
|
||||||
// 2 - 0x02 - Z/EQ, result is zero
|
|
||||||
// 3 - 0x01 - S/SO, summary overflow (carry?)
|
|
||||||
// XER:
|
|
||||||
// 32 - SO
|
|
||||||
// 33 - Overflow
|
|
||||||
// 34 - Carry
|
|
||||||
// NZCV -> (CR0.0, CR0.2, XER.34, XER.33)
|
|
||||||
if (false) {
|
|
||||||
//code.MFSPR(powah::GPR{1}, tmp4, powah::R0); // From XER
|
|
||||||
/*uint64_t nzcv(uint64_t cr0, uint64_t xer) {
|
|
||||||
return ((xer >> 33) & 1)
|
|
||||||
| (((xer >> 34) & 1) << 1)
|
|
||||||
| (((cr0 >> (32 + 2)) & 1) << 2)
|
|
||||||
| (((cr0 >> (32 + 0)) & 1) << 3);
|
|
||||||
}*/
|
|
||||||
// auto const tmp9 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
// auto const tmp10 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
// code.SRDI(tmp9, tmp3, 34);
|
|
||||||
// code.RLDICL(tmp10, tmp4, 31, 63);
|
|
||||||
// code.SRDI(tmp3, tmp3, 32);
|
|
||||||
// code.RLDIC(tmp9, tmp9, 2, 61);
|
|
||||||
// code.OR(tmp9, tmp9, tmp10);
|
|
||||||
// code.RLDIC(tmp3, tmp3, 3, 60);
|
|
||||||
// code.SRDI(tmp4, tmp4, 34);
|
|
||||||
// code.OR(tmp3, tmp9, tmp3);
|
|
||||||
// code.RLDIC(tmp4, tmp4, 1, 62);
|
|
||||||
// code.OR(tmp3, tmp3, tmp4);
|
|
||||||
} else {
|
|
||||||
// MFCR Fills RT 32:63, RT 0:31 left blank
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.MR(tmp3, PPC64::RNZCV);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetNZFromOp>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetUpperFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetLowerFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::GetCFlagFromNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::NZCVFromPackedFlags>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void EmitLeafTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// r3 -> process
|
|
||||||
// r4 -> thread_ctx
|
|
||||||
// r5 -> halt_reason
|
|
||||||
// r6 -> test_thunk
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool) {
|
|
||||||
if (ctx.emit_conf.a64_variant) {
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LI(tmp, terminal.next.Value());
|
|
||||||
code.STD(tmp, PPC64::RJIT, offsetof(A64JitState, pc));
|
|
||||||
code.B(ctx.l_return);
|
|
||||||
} else {
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LI(tmp, terminal.next.Value());
|
|
||||||
code.STW(tmp, PPC64::RJIT, offsetof(A32JitState, regs) + sizeof(u32) * 15);
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
EmitTerminal(code, ctx, IR::Term::LinkBlock{terminal.next}, initial_location, is_single_step);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::PopRSBHint, IR::LocationDescriptor, bool) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
powah::Label const l_else = code.DefineLabel();
|
|
||||||
powah::Label const l_end = code.DefineLabel();
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LWZ(tmp, PPC64::RJIT, offsetof(A64JitState, check_bit));
|
|
||||||
code.CMPLDI(tmp, 0);
|
|
||||||
code.BEQ(powah::CR0, l_else);
|
|
||||||
// CheckBit == 1
|
|
||||||
EmitLeafTerminal(code, ctx, terminal.then_, initial_location, is_single_step);
|
|
||||||
code.B(l_end);
|
|
||||||
// CheckBit == 0
|
|
||||||
code.LABEL(l_else);
|
|
||||||
EmitLeafTerminal(code, ctx, terminal.else_, initial_location, is_single_step);
|
|
||||||
code.LABEL(l_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitLeafTerminal(powah::Context& code, EmitContext& ctx, IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitTerminal(powah::Context& code, EmitContext& ctx, IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
|
||||||
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal))
|
|
||||||
return EmitLeafTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::If>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal))
|
|
||||||
return EmitTerminal(code, ctx, *x, initial_location, is_single_step);
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmittedBlockInfo EmitPPC64(powah::Context& code, IR::Block block, const EmitConfig& emit_conf) {
|
|
||||||
EmittedBlockInfo ebi;
|
|
||||||
RegAlloc reg_alloc{code};
|
|
||||||
EmitContext ctx{block, reg_alloc, emit_conf, ebi, code.DefineLabel()};
|
|
||||||
size_t const stack_size = 112 + ABI_CALLEE_SAVED.size() * 8;
|
|
||||||
auto const start_offset = code.offset;
|
|
||||||
ebi.entry_point = &code.base[start_offset];
|
|
||||||
if (!block.instructions.empty()) {
|
|
||||||
code.MFLR(powah::R0);
|
|
||||||
code.STD(powah::R0, powah::R1, 16);
|
|
||||||
// Non-volatile saves
|
|
||||||
std::vector<powah::GPR> gp_regs{ABI_CALLEE_SAVED};
|
|
||||||
for (size_t i = 0; i < gp_regs.size(); ++i)
|
|
||||||
code.STD(gp_regs[i], powah::R1, -int32_t(gp_regs.size() - i) * 8);
|
|
||||||
code.STDU(powah::R1, powah::R1, uint32_t(-stack_size));
|
|
||||||
code.STD(powah::R2, powah::R1, 40);
|
|
||||||
|
|
||||||
for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) {
|
|
||||||
IR::Inst* inst = &*iter;
|
|
||||||
switch (inst->GetOpcode()) {
|
|
||||||
#define OPCODE(name, type, ...) \
|
|
||||||
case IR::Opcode::name: \
|
|
||||||
EmitIR<IR::Opcode::name>(code, ctx, inst); \
|
|
||||||
break;
|
|
||||||
#define A32OPC(name, type, ...) \
|
|
||||||
case IR::Opcode::A32##name: \
|
|
||||||
EmitIR<IR::Opcode::A32##name>(code, ctx, inst); \
|
|
||||||
break;
|
|
||||||
#define A64OPC(name, type, ...) \
|
|
||||||
case IR::Opcode::A64##name: \
|
|
||||||
EmitIR<IR::Opcode::A64##name>(code, ctx, inst); \
|
|
||||||
break;
|
|
||||||
#include "dynarmic/ir/opcodes.inc"
|
|
||||||
#undef OPCODE
|
|
||||||
#undef A32OPC
|
|
||||||
#undef A64OPC
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// auto const cycles_to_add = block.CycleCount();
|
|
||||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
|
||||||
code.LABEL(ctx.l_return);
|
|
||||||
code.ADDI(powah::R1, powah::R1, stack_size);
|
|
||||||
for (size_t i = 0; i < gp_regs.size(); ++i)
|
|
||||||
code.LD(gp_regs[i], powah::R1, -int32_t(gp_regs.size() - i) * 8);
|
|
||||||
code.LD(powah::R0, powah::R1, 16);
|
|
||||||
code.MTLR(powah::R0);
|
|
||||||
code.LI(powah::R3, 0);
|
|
||||||
} else {
|
|
||||||
EmitTerminal(code, ctx, ctx.block.GetTerminal(), ctx.block.Location(), false);
|
|
||||||
code.LABEL(ctx.l_return);
|
|
||||||
code.LI(powah::R3, 67); //non-zero ret
|
|
||||||
}
|
|
||||||
code.BLR();
|
|
||||||
code.ApplyRelocs();
|
|
||||||
|
|
||||||
/*
|
|
||||||
llvm-objcopy -I binary -O elf64-powerpc --rename-section=.data=.text,code test.bin test.elf && llvm-objdump -d test.elf
|
|
||||||
*/
|
|
||||||
static FILE* fp = fopen("test.bin", "wb");
|
|
||||||
fwrite(code.base, code.offset - start_offset, sizeof(uint32_t), fp);
|
|
||||||
fflush(fp);
|
|
||||||
|
|
||||||
ebi.size = code.offset - start_offset;
|
|
||||||
return ebi;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace biscuit {
|
|
||||||
class Assembler;
|
|
||||||
} // namespace biscuit
|
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
|
||||||
class Block;
|
|
||||||
class Inst;
|
|
||||||
enum class Cond;
|
|
||||||
enum class Opcode;
|
|
||||||
} // namespace Dynarmic::IR
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct EmittedBlockInfo {
|
|
||||||
std::uint32_t* entry_point;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EmitConfig {
|
|
||||||
bool enable_cycle_counting;
|
|
||||||
bool always_little_endian;
|
|
||||||
bool a64_variant;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EmitContext;
|
|
||||||
|
|
||||||
EmittedBlockInfo EmitPPC64(powah::Context& code, IR::Block block, const EmitConfig& emit_conf);
|
|
||||||
template<IR::Opcode op>
|
|
||||||
void EmitIR(powah::Context& code, EmitContext& ctx, IR::Inst* inst);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A32/a32_types.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCheckBit>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetRegister>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A32Reg) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.ADDI(result, PPC64::RJIT, A32::RegNumber(inst->GetArg(0).GetA32RegRef()) * sizeof(u32));
|
|
||||||
code.LWZ(result, result, offsetof(A32JitState, regs));
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetExtendedRegister32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetExtendedRegister64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetVector>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetRegister>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A32Reg) {
|
|
||||||
auto const addr = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.ADDI(addr, PPC64::RJIT, A32::RegNumber(inst->GetArg(0).GetA32RegRef()) * sizeof(u32));
|
|
||||||
code.STW(value, addr, offsetof(A32JitState, regs));
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetExtendedRegister32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetExtendedRegister64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetVector>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetCpsr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZCVRaw>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZCVQ>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZ>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetCpsrNZC>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetCFlag>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LD(result, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.RLWINM(result, result, 31, 31, 31);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32OrQFlag>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetGEFlags>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetGEFlags>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetGEFlagsCompressed>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32BXWritePC>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CallSupervisor>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExceptionRaised>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetFpscr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetFpscr>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32GetFpscrNZCV>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32SetFpscrNZCV>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memory
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ClearExclusive>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveReadMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32WriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Coprocesor
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocInternalOperation>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocSendOneWord>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocSendTwoWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocGetOneWord>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocGetTwoWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocLoadWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A32CoprocStoreWords>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,341 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A64/a64_types.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a64_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetCheckBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.STW(value, PPC64::RJIT, offsetof(A64JitState, check_bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCFlag>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetNZCVRaw>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetNZCVRaw>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.STW(value, PPC64::RJIT, offsetof(A64JitState, pstate));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetW>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
// Need to account for endianess here...
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.LWZ(result, PPC64::RJIT, offs);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetX>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.LD(result, PPC64::RJIT, offs);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetS>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetD>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetQ>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetSP>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetFPCR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetFPSR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetW>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.RLDICL(tmp, value, 0, 32);
|
|
||||||
code.STD(tmp, PPC64::RJIT, offs);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetX>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
if (inst->GetArg(0).GetType() == IR::Type::A64Reg) {
|
|
||||||
auto const offs = offsetof(A64JitState, regs)
|
|
||||||
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
|
|
||||||
code.STD(value, PPC64::RJIT, offs);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetS>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetD>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetQ>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetSP>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetFPCR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetFPSR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetPC>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64CallSupervisor>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExceptionRaised>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64DataCacheOperationRaised>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64InstructionCacheOperationRaised>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64DataSynchronizationBarrier>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64DataMemoryBarrier>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64InstructionSynchronizationBarrier>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCNTFRQ>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCNTPCT>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetCTR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetDCZID>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetTPIDR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64GetTPIDRRO>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64SetTPIDR>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memory
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ClearExclusive>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ReadMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveReadMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64WriteMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory8>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory16>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,933 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
// uint64_t pack2x1(uint32_t lo, uint32_t hi) { return (uint64_t)lo | ((uint64_t)hi << 32); }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Pack2x32To1x64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const lo = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const hi = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.SLDI(result, hi, 32);
|
|
||||||
code.OR(result, result, lo);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Pack2x64To1x128>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t lsw(uint64_t a) { return (uint32_t)a; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LeastSignificantWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLDICL(result, source, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t f(uint64_t a) { return (uint16_t)a; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LeastSignificantHalf>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xffff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t f(uint64_t a) { return (uint8_t)a; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LeastSignificantByte>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint64_t msw(uint64_t a) { return a >> 32; }
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MostSignificantWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRDI(result, source, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return ((uint32_t)a) >> 31; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MostSignificantBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 1, 31, 31);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return (uint32_t)a == 0; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::IsZero32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZW(result, source);
|
|
||||||
code.SRWI(result, result, 5);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return a == 0; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::IsZero64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZD(result, source);
|
|
||||||
code.SRDI(result, result, 6);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a) { return (a & 1) != 0; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::TestBit>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (inst->GetArg(1).IsImmediate()) {
|
|
||||||
auto const shift = inst->GetArg(1).GetImmediateAsU64();
|
|
||||||
if (shift > 0) {
|
|
||||||
code.RLDICL(result, source, (64 - shift - 1) & 0x3f, 63);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct jit {
|
|
||||||
uint64_t t;
|
|
||||||
uint64_t a;
|
|
||||||
};
|
|
||||||
uint64_t f(jit *p, uint64_t a, uint64_t b) {
|
|
||||||
bool n = (p->a & 0b1000) != 0;
|
|
||||||
bool z = (p->a & 0b0100) != 0;
|
|
||||||
bool c = (p->a & 0b0010) != 0;
|
|
||||||
bool v = (p->a & 0b0001) != 0;
|
|
||||||
return (p->a & 0b0001) == 0 ? a : b;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
static powah::GPR EmitConditionalSelectX(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const nzcv = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const then_ = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const else_ = ctx.reg_alloc.UseGpr(inst->GetArg(2));
|
|
||||||
switch (inst->GetArg(0).GetCond()) {
|
|
||||||
case IR::Cond::EQ: // Z == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 4);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::NE: // Z == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 4);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::CS: // C == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 2);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::CC: // C == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 2);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::MI: // N == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 8);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::PL: // N == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 8);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::VS: // V == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::VC: // V == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, else_, then_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::HI: // Z == 0 && C == 1
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.RLWINM(nzcv, nzcv, 0, 29, 30);
|
|
||||||
code.CMPLDI(nzcv, 2);
|
|
||||||
code.ISELEQ(nzcv, then_, else_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::LS: // Z == 1 || C == 0
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.RLWINM(nzcv, nzcv, 0, 29, 30);
|
|
||||||
code.CMPLDI(nzcv, 2);
|
|
||||||
code.ISELEQ(nzcv, else_, then_);
|
|
||||||
break;
|
|
||||||
case IR::Cond::GE: { // N == V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LWZ(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, else_, then_);
|
|
||||||
} break;
|
|
||||||
case IR::Cond::LT: { // N != V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.LWZ(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(nzcv, then_, else_);
|
|
||||||
} break;
|
|
||||||
case IR::Cond::GT: { // Z == 0 && N == V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
powah::Label const l_ne = code.DefineLabel();
|
|
||||||
powah::Label const l_cc = code.DefineLabel();
|
|
||||||
powah::Label const l_fi = code.DefineLabel();
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(tmp, nzcv, 4);
|
|
||||||
code.BNE(powah::CR0, l_ne);
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.CMPLDI(nzcv, 0);
|
|
||||||
code.BGT(powah::CR0, l_fi);
|
|
||||||
code.LABEL(l_ne);
|
|
||||||
code.MR(then_, else_);
|
|
||||||
code.LABEL(l_cc);
|
|
||||||
code.MR(nzcv, then_);
|
|
||||||
code.LABEL(l_fi);
|
|
||||||
} break;
|
|
||||||
case IR::Cond::LE: { // Z == 1 || N != V
|
|
||||||
auto const tmp = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp2 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
powah::Label const l_ne = code.DefineLabel();
|
|
||||||
code.MR(tmp2, then_);
|
|
||||||
code.LD(nzcv, PPC64::RJIT, offsetof(A32JitState, cpsr_nzcv));
|
|
||||||
code.ANDI_(tmp, nzcv, 4);
|
|
||||||
code.BNE(powah::CR0, l_ne);
|
|
||||||
code.SRWI(tmp, nzcv, 3);
|
|
||||||
code.XOR(nzcv, tmp, nzcv);
|
|
||||||
code.ANDI_(nzcv, nzcv, 1);
|
|
||||||
code.ISELGT(tmp2, then_, else_);
|
|
||||||
code.LABEL(l_ne);
|
|
||||||
code.MR(nzcv, tmp2);
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
return nzcv;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ConditionalSelect32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = EmitConditionalSelectX(code, ctx, inst);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ConditionalSelect64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = EmitConditionalSelectX(code, ctx, inst);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ConditionalSelectNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = EmitConditionalSelectX(code, ctx, inst);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeft32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SLW(result, source, shift);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeft64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SLD(result, source, shift);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRight32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRW(result, source, shift);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint64_t f(uint64_t a, uint64_t s) { return a >> s; }
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRight64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRD(result, source, shift);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRight32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRAW(result, source, shift);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRight64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const shift = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SRAD(result, source, shift);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_rotateright32
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::BitRotateRight32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLW(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::BitRotateRight64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::RotateRightExtended>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeftMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SLW(result, source, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftLeftMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SLD(result, source, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRightMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRW(result, source, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::LogicalShiftRightMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRD(result, source, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRightMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRAW(result, source, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ArithmeticShiftRightMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.SRAD(result, source, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::RotateRightMasked32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::RotateRightMasked64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NEG(result, src_a, powah::R0);
|
|
||||||
code.ROTLD(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Add32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.ADDC_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct jit {
|
|
||||||
uint32_t nzcv;
|
|
||||||
};
|
|
||||||
uint64_t addc(jit *p, uint64_t a, uint64_t b) {
|
|
||||||
long long unsigned int e;
|
|
||||||
uint64_t r = __builtin_addcll(a, b, p->nzcv & 0b0010, &e);
|
|
||||||
p->nzcv = (p->nzcv & 0b1101) | e;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Add64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.ADDC_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Sub32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SUBFC_(result, src_b, src_a);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Sub64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.SUBFC_(result, src_b, src_a);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Mul32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLWO_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Mul64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLDO_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedMultiplyHigh64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLDO_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedMultiplyHigh64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.MULLDO_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedDiv32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVWU_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedDiv64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVDU_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedDiv32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVW_(result, src_a, src_b);
|
|
||||||
code.EXTSW(result, result);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedDiv64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.DIVD_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::And32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp8 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp9 = PPC64::RNZCV;
|
|
||||||
code.RLDICL(tmp3, src_a, 0, 32); // Truncate
|
|
||||||
code.AND(tmp3, tmp3, src_b);
|
|
||||||
code.CNTLZD(tmp9, tmp3);
|
|
||||||
code.RLWINM(tmp8, tmp3, 0, 0, 0);
|
|
||||||
code.SRDI(tmp9, tmp9, 6);
|
|
||||||
code.SLDI(tmp9, tmp9, 30);
|
|
||||||
code.OR(tmp9, tmp9, tmp8);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::And64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp10 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp9 = PPC64::RNZCV;
|
|
||||||
code.AND(tmp3, src_a, src_b);
|
|
||||||
code.CNTLZD(tmp10, tmp3);
|
|
||||||
code.SRADI(tmp9, tmp3, 32);
|
|
||||||
code.SRDI(tmp10, tmp10, 6);
|
|
||||||
code.RLWINM(tmp9, tmp9, 0, 0, 0);
|
|
||||||
code.SLDI(tmp10, tmp10, 30);
|
|
||||||
code.OR(tmp9, tmp9, tmp10);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AndNot32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.NAND_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AndNot64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.NAND_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Eor32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.XOR_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Eor64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.XOR_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Or32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.OR_(result, src_a, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Or64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
|
|
||||||
code.OR_(result, src_a, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(lizzie): NZVC support for NOT
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Not32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NOT(result, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::Not64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.NOT(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendByteToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSB(result, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendHalfToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSH(result, source);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendByteToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSH(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendHalfToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSB(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignExtendWordToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.EXTSW(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendByteToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendHalfToWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xffff);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendByteToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendHalfToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLWINM(result, source, 0, 0xffff);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendWordToLong>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.RLDICL(result, source, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ZeroExtendLongToQuad>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_bswap32
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ByteReverseWord>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (false) {
|
|
||||||
//code.BRW(result, source);
|
|
||||||
//code.RLDICL(result, result, 0, 32);
|
|
||||||
} else {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.ROTLWI(result, source, 24);
|
|
||||||
code.RLWIMI(result, source, 8, 8, 15);
|
|
||||||
code.RLWIMI(result, source, 8, 24, 31);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_bswap64
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ByteReverseHalf>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (false) {
|
|
||||||
//code.BRH(result, source);
|
|
||||||
code.RLWINM(result, source, 0, 0xff);
|
|
||||||
} else {
|
|
||||||
code.ROTLWI(result, source, 24);
|
|
||||||
code.RLWIMI(result, source, 8, 0, 23);
|
|
||||||
code.CLRLDI(result, result, 48);
|
|
||||||
}
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ByteReverseDual>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
if (false) {
|
|
||||||
//code.BRD(result, source);
|
|
||||||
} else {
|
|
||||||
auto const tmp10 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp9 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
|
|
||||||
code.MR(tmp3, source);
|
|
||||||
code.ROTLWI(tmp10, tmp3, 24);
|
|
||||||
code.SRDI(tmp9, tmp3, 32);
|
|
||||||
code.RLWIMI(tmp10, tmp3, 8, 8, 15);
|
|
||||||
code.RLWIMI(tmp10, tmp3, 8, 24, 31);
|
|
||||||
code.ROTLWI(tmp3, tmp9, 24);
|
|
||||||
code.RLWIMI(tmp3, tmp9, 8, 8, 15);
|
|
||||||
code.RLWIMI(tmp3, tmp9, 8, 24, 31);
|
|
||||||
code.RLDIMI(tmp3, tmp10, 32, 0);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, tmp3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_clz
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CountLeadingZeros32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZW(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// __builtin_clz
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CountLeadingZeros64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CNTLZD(result, source);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ExtractRegister32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ExtractRegister64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ReplicateBit32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::ReplicateBit64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxSigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPD(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxSigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPD(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxUnsigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLW(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MaxUnsigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLD(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinSigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPW(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinSigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPD(powah::CR0, result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinUnsigned32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLW(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
code.RLDICL(result, result, 0, 32);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::MinUnsigned64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto const result = ctx.reg_alloc.ScratchGpr();
|
|
||||||
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(0));
|
|
||||||
code.CMPLD(result, src_a);
|
|
||||||
code.ISELGT(result, result, src_b);
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,458 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAbs16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAbs32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAbs64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPCompare32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPCompare64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDiv32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDiv64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMax32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMax64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMaxNumeric32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMaxNumeric64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMin32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMin64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMinNumeric32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMinNumeric64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMul32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMul64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulAdd16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulSub16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulX32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPMulX64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPNeg16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPNeg32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPNeg64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipEstimate16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipEstimate32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipEstimate64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipExponent16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipExponent32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipExponent64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipStepFused16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipStepFused32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRecipStepFused64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRoundInt16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRoundInt32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRoundInt64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtEstimate16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtEstimate32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtEstimate64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtStepFused16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtStepFused32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPRSqrtStepFused64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSqrt32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSqrt64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToHalf>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToHalf>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPDoubleToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPHalfToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedS32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedS64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedU32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPSingleToFixedU64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU16ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS16ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU16ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS16ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU32ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS32ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU32ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS32ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU64ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedU64ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS64ToDouble>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::FPFixedS64ToSingle>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,380 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/a32_core.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_context.h"
|
|
||||||
#include "dynarmic/backend/ppc64/emit_ppc64.h"
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAddWithFlag32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSubWithFlag32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturation>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturation>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SignedSaturatedSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedAdd64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::UnsignedSaturatedSub64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packed
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAddSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSubAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingAddSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedHalvingSubAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubS8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedAddS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubU16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSaturatedSubS16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedAbsDiffSumU8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::PackedSelect>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crypto
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32Castagnoli64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO8>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO16>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO32>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::CRC32ISO64>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESDecryptSingleRound>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESEncryptSingleRound>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESInverseMixColumns>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::AESMixColumns>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SM4AccessSubstitutionBox>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SHA256Hash>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SHA256MessageSchedule0>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void EmitIR<IR::Opcode::SHA256MessageSchedule1>(powah::Context&, EmitContext&, IR::Inst*) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "dynarmic/interface/exclusive_monitor.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
|
|
||||||
ExclusiveMonitor::ExclusiveMonitor(std::size_t processor_count)
|
|
||||||
: exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {}
|
|
||||||
|
|
||||||
size_t ExclusiveMonitor::GetProcessorCount() const {
|
|
||||||
return exclusive_addresses.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Lock() {
|
|
||||||
lock.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Unlock() {
|
|
||||||
lock.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExclusiveMonitor::CheckAndClear(std::size_t processor_id, VAddr address) {
|
|
||||||
const VAddr masked_address = address & RESERVATION_GRANULE_MASK;
|
|
||||||
Lock();
|
|
||||||
if (exclusive_addresses[processor_id] != masked_address) {
|
|
||||||
Unlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (VAddr& other_address : exclusive_addresses)
|
|
||||||
if (other_address == masked_address)
|
|
||||||
other_address = INVALID_EXCLUSIVE_ADDRESS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::Clear() {
|
|
||||||
Lock();
|
|
||||||
std::fill(exclusive_addresses.begin(), exclusive_addresses.end(), INVALID_EXCLUSIVE_ADDRESS);
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExclusiveMonitor::ClearProcessor(size_t processor_id) {
|
|
||||||
Lock();
|
|
||||||
exclusive_addresses[processor_id] = INVALID_EXCLUSIVE_ADDRESS;
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
enum class HostLoc : uint8_t {
|
|
||||||
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9,
|
|
||||||
R10, R11, R12, R13, R14, R15, R16, R17, R18, R19,
|
|
||||||
R20, R21, R22, R23, R24, R25, R26, R27, R28, R29,
|
|
||||||
R30, R31,
|
|
||||||
FR0, FR1, FR2, FR3, FR4, FR5, FR6, FR7, FR8, FR9,
|
|
||||||
FR10, FR11, FR12, FR13, FR14, FR15, FR16, FR17, FR18, FR19,
|
|
||||||
FR20, FR21, FR22, FR23, FR24, FR25, FR26, FR27, FR28, FR29,
|
|
||||||
FR30, FR31,
|
|
||||||
VR0, VR1, VR2, VR3, VR4, VR5, VR6, VR7, VR8, VR9,
|
|
||||||
VR10, VR11, VR12, VR13, VR14, VR15, VR16, VR17, VR18, VR19,
|
|
||||||
VR20, VR21, VR22, VR23, VR24, VR25, VR26, VR27, VR28, VR29,
|
|
||||||
VR30, VR31,
|
|
||||||
FirstSpill,
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::PPC64
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <ranges>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#include "dynarmic/backend/ppc64/reg_alloc.h"
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "dynarmic/common/always_false.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
constexpr size_t spill_offset = offsetof(StackLayout, spill);
|
|
||||||
constexpr size_t spill_slot_size = sizeof(decltype(StackLayout::spill)::value_type);
|
|
||||||
|
|
||||||
static bool IsValuelessType(IR::Type type) {
|
|
||||||
return type == IR::Type::Table;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HostLocInfo::UpdateUses() {
|
|
||||||
accumulated_uses += uses_this_inst;
|
|
||||||
uses_this_inst = 0;
|
|
||||||
if (accumulated_uses == expected_uses) {
|
|
||||||
values.clear();
|
|
||||||
accumulated_uses = 0;
|
|
||||||
expected_uses = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RegAlloc::IsValueLive(IR::Inst* inst) const {
|
|
||||||
return !!ValueLocation(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::UpdateAllUses() {
|
|
||||||
for (auto& gpr : gprs)
|
|
||||||
gpr.UpdateUses();
|
|
||||||
for (auto& fpr : fprs)
|
|
||||||
fpr.UpdateUses();
|
|
||||||
for (auto& spill : spills)
|
|
||||||
spill.UpdateUses();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::DefineAsExisting(IR::Inst* inst, IR::Value arg) {
|
|
||||||
ASSERT(!ValueLocation(inst));
|
|
||||||
if (arg.IsImmediate()) {
|
|
||||||
inst->ReplaceUsesWith(arg);
|
|
||||||
} else {
|
|
||||||
auto& info = ValueInfo(arg.GetInst());
|
|
||||||
info.values.emplace_back(inst);
|
|
||||||
info.expected_uses += inst->UseCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::AssertNoMoreUses() const {
|
|
||||||
const auto is_empty = [](const auto& i) { return i.IsCompletelyEmpty(); };
|
|
||||||
ASSERT(std::all_of(gprs.begin(), gprs.end(), is_empty));
|
|
||||||
ASSERT(std::all_of(fprs.begin(), fprs.end(), is_empty));
|
|
||||||
ASSERT(std::all_of(spills.begin(), spills.end(), is_empty));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<u32> RegAlloc::AllocateRegister(const std::array<HostLocInfo, 32>& regs) const {
|
|
||||||
auto const order = PPC64::GPR_ORDER;
|
|
||||||
if (auto const it = std::find_if(order.begin(), order.end(), [&](u32 i) {
|
|
||||||
return regs[i].values.empty() && !regs[i].locked;
|
|
||||||
}); it != order.end())
|
|
||||||
return *it;
|
|
||||||
// TODO: Actual proper LRU
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::SpillGpr(u32 index) {
|
|
||||||
ASSERT(!gprs[index].locked && !gprs[index].realized);
|
|
||||||
if (!gprs[index].values.empty()) {
|
|
||||||
const u32 new_location_index = FindFreeSpill();
|
|
||||||
code.STD(powah::GPR{index}, powah::R1, spill_offset + new_location_index * spill_slot_size);
|
|
||||||
spills[new_location_index] = std::exchange(gprs[index], {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::SpillFpr(u32 index) {
|
|
||||||
ASSERT(!fprs[index].locked && !fprs[index].realized);
|
|
||||||
if (!fprs[index].values.empty()) {
|
|
||||||
const u32 new_location_index = FindFreeSpill();
|
|
||||||
//code.FSD(powah::FPR{index}, spill_offset + new_location_index * spill_slot_size, powah::sp);
|
|
||||||
spills[new_location_index] = std::exchange(fprs[index], {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 RegAlloc::FindFreeSpill() const {
|
|
||||||
const auto iter = std::find_if(spills.begin(), spills.end(), [](const HostLocInfo& info) { return info.values.empty(); });
|
|
||||||
ASSERT(iter != spills.end() && "All spill locations are full");
|
|
||||||
return u32(iter - spills.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<HostLoc> RegAlloc::ValueLocation(const IR::Inst* value) const {
|
|
||||||
const auto fn = [value](const HostLocInfo& info) {
|
|
||||||
return info.Contains(value);
|
|
||||||
};
|
|
||||||
if (const auto iter = std::ranges::find_if(gprs, fn); iter != gprs.end())
|
|
||||||
return HostLoc(u32(HostLoc::R0) + u32(iter - gprs.begin()));
|
|
||||||
else if (const auto iter = std::ranges::find_if(fprs, fn); iter != fprs.end())
|
|
||||||
return HostLoc(u32(HostLoc::FR0) + u32(iter - fprs.begin()));
|
|
||||||
else if (const auto iter = std::ranges::find_if(vprs, fn); iter != vprs.end())
|
|
||||||
return HostLoc(u32(HostLoc::VR0) + u32(iter - vprs.begin()));
|
|
||||||
else if (const auto iter = std::ranges::find_if(spills, fn); iter != spills.end())
|
|
||||||
return HostLoc(u32(HostLoc::FirstSpill) + u32(iter - spills.begin()));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool HostLocIsGpr(HostLoc h) noexcept {
|
|
||||||
return u8(h) >= u8(HostLoc::R0) && u8(h) <= u8(HostLoc::R31);
|
|
||||||
}
|
|
||||||
inline bool HostLocIsFpr(HostLoc h) noexcept {
|
|
||||||
return u8(h) >= u8(HostLoc::FR0) && u8(h) <= u8(HostLoc::FR31);
|
|
||||||
}
|
|
||||||
inline bool HostLocIsVpr(HostLoc h) noexcept {
|
|
||||||
return u8(h) >= u8(HostLoc::VR0) && u8(h) <= u8(HostLoc::VR31);
|
|
||||||
}
|
|
||||||
inline std::variant<powah::GPR, powah::FPR> HostLocToReg(HostLoc h) noexcept {
|
|
||||||
if (HostLocIsGpr(h))
|
|
||||||
return powah::GPR{uint32_t(h)};
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
HostLocInfo& RegAlloc::ValueInfo(HostLoc h) {
|
|
||||||
if (u8(h) >= u8(HostLoc::R0) && u8(h) <= u8(HostLoc::R31))
|
|
||||||
return gprs[size_t(h)];
|
|
||||||
else if (u8(h) >= u8(HostLoc::FR0) && u8(h) <= u8(HostLoc::FR31))
|
|
||||||
return gprs[size_t(h) - size_t(HostLoc::FR0)];
|
|
||||||
else if (u8(h) >= u8(HostLoc::VR0) && u8(h) <= u8(HostLoc::VR31))
|
|
||||||
return vprs[size_t(h) - size_t(HostLoc::VR0)];
|
|
||||||
auto const index = size_t(h) - size_t(HostLoc::FirstSpill);
|
|
||||||
ASSERT(index <= spills.size());
|
|
||||||
return spills[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
HostLocInfo& RegAlloc::ValueInfo(const IR::Inst* value) {
|
|
||||||
const auto fn = [value](const HostLocInfo& info) {
|
|
||||||
return info.Contains(value);
|
|
||||||
};
|
|
||||||
if (const auto iter = std::find_if(gprs.begin(), gprs.end(), fn); iter != gprs.end())
|
|
||||||
return *iter;
|
|
||||||
else if (const auto iter = std::find_if(fprs.begin(), fprs.end(), fn); iter != fprs.end())
|
|
||||||
return *iter;
|
|
||||||
else if (const auto iter = std::find_if(spills.begin(), spills.end(), fn); iter != spills.end())
|
|
||||||
return *iter;
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Defines a register RegLock to use (and locks it)
|
|
||||||
RegLock<powah::GPR> RegAlloc::ScratchGpr() {
|
|
||||||
auto const r = AllocateRegister(gprs);
|
|
||||||
return RegLock(*this, powah::GPR{*r});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Uses the given GPR of the argument
|
|
||||||
RegLock<powah::GPR> RegAlloc::UseGpr(IR::Value arg) {
|
|
||||||
if (arg.IsImmediate()) {
|
|
||||||
// HOLY SHIT EVIL HAXX
|
|
||||||
auto const reg = ScratchGpr();
|
|
||||||
auto const imm = arg.GetImmediateAsU64();
|
|
||||||
if (imm >= 0xffffffff) {
|
|
||||||
auto const lo = uint32_t(imm >> 0), hi = uint32_t(imm >> 32);
|
|
||||||
if (lo == hi) {
|
|
||||||
code.LIS(reg, imm >> 16);
|
|
||||||
code.ORI(reg, reg, imm & 0xffff);
|
|
||||||
code.RLDIMI(reg, reg, 32, 0);
|
|
||||||
} else {
|
|
||||||
ASSERT(false && "larger >32bit imms");
|
|
||||||
}
|
|
||||||
} else if (imm > 0xffff && imm <= 0xffffffff) {
|
|
||||||
code.LIS(reg, imm >> 16);
|
|
||||||
code.ORI(reg, reg, imm & 0xffff);
|
|
||||||
} else if (imm <= 0xffff) {
|
|
||||||
code.LI(reg, imm);
|
|
||||||
}
|
|
||||||
return reg;
|
|
||||||
} else {
|
|
||||||
auto const loc = ValueLocation(arg.GetInst());
|
|
||||||
ASSERT(loc && HostLocIsGpr(*loc));
|
|
||||||
return RegLock(*this, std::get<powah::GPR>(HostLocToReg(*loc)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::DefineValue(IR::Inst* inst, powah::GPR const gpr) noexcept {
|
|
||||||
ASSERT(!ValueLocation(inst) && "inst has already been defined");
|
|
||||||
ValueInfo(HostLoc(gpr.index)).values.push_back(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegAlloc::DefineValue(IR::Inst* inst, IR::Value arg) noexcept {
|
|
||||||
ASSERT(!ValueLocation(inst) && "inst has already been defined");
|
|
||||||
if (arg.IsImmediate()) {
|
|
||||||
HostLoc const loc{u8(ScratchGpr().value.index)};
|
|
||||||
ValueInfo(loc).values.push_back(inst);
|
|
||||||
auto const value = arg.GetImmediateAsU64();
|
|
||||||
if (value >= 0x7fff) {
|
|
||||||
ASSERT(false && "unimp");
|
|
||||||
} else {
|
|
||||||
//code.LI(HostLocToReg(loc), value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ASSERT(ValueLocation(arg.GetInst()) && "arg must already be defined");
|
|
||||||
const HostLoc loc = *ValueLocation(arg.GetInst());
|
|
||||||
ValueInfo(loc).values.push_back(inst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <optional>
|
|
||||||
#include <random>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "dynarmic/backend/ppc64/stack_layout.h"
|
|
||||||
#include "dynarmic/backend/ppc64/hostloc.h"
|
|
||||||
#include "dynarmic/ir/cond.h"
|
|
||||||
#include "dynarmic/ir/microinstruction.h"
|
|
||||||
#include "dynarmic/ir/value.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
struct HostLocInfo final {
|
|
||||||
std::vector<const IR::Inst*> values;
|
|
||||||
size_t uses_this_inst = 0;
|
|
||||||
size_t accumulated_uses = 0;
|
|
||||||
size_t expected_uses = 0;
|
|
||||||
/// @brief Lock usage of this register UNTIL a DefineValue() is issued
|
|
||||||
bool locked = false;
|
|
||||||
bool realized = false;
|
|
||||||
bool Contains(const IR::Inst* value) const {
|
|
||||||
return std::find(values.begin(), values.end(), value) != values.end();
|
|
||||||
}
|
|
||||||
void SetupScratchLocation() {
|
|
||||||
ASSERT(IsCompletelyEmpty());
|
|
||||||
realized = true;
|
|
||||||
}
|
|
||||||
bool IsCompletelyEmpty() const {
|
|
||||||
return values.empty() && !locked && !realized && !accumulated_uses && !expected_uses && !uses_this_inst;
|
|
||||||
}
|
|
||||||
void UpdateUses();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RegAlloc;
|
|
||||||
|
|
||||||
/// @brief Allows to use RAII to denote liveness/locking of a given register
|
|
||||||
/// this basically means that we can use temporals and not need to go thru
|
|
||||||
/// any weird deallocation stuffs :)
|
|
||||||
template<typename T> struct RegLock {
|
|
||||||
constexpr RegLock(RegAlloc& reg_alloc, T const value) noexcept
|
|
||||||
: reg_alloc{reg_alloc}
|
|
||||||
, value{value}
|
|
||||||
{
|
|
||||||
SetLock(true);
|
|
||||||
}
|
|
||||||
inline ~RegLock() noexcept { SetLock(false); }
|
|
||||||
constexpr operator T const&() noexcept { return value; }
|
|
||||||
constexpr operator T() const noexcept { return value; }
|
|
||||||
inline void SetLock(bool v) noexcept;
|
|
||||||
RegAlloc& reg_alloc;
|
|
||||||
const T value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RegAlloc {
|
|
||||||
explicit RegAlloc(powah::Context& code) : code{code} {}
|
|
||||||
bool IsValueLive(IR::Inst* inst) const;
|
|
||||||
void DefineAsExisting(IR::Inst* inst, IR::Value arg);
|
|
||||||
|
|
||||||
void SpillAll();
|
|
||||||
void UpdateAllUses();
|
|
||||||
void AssertNoMoreUses() const;
|
|
||||||
|
|
||||||
RegLock<powah::GPR> ScratchGpr();
|
|
||||||
RegLock<powah::GPR> UseGpr(IR::Value arg);
|
|
||||||
void DefineValue(IR::Inst* inst, powah::GPR const gpr) noexcept;
|
|
||||||
void DefineValue(IR::Inst* inst, IR::Value arg) noexcept;
|
|
||||||
private:
|
|
||||||
template<typename T>
|
|
||||||
friend struct RegLock;
|
|
||||||
|
|
||||||
std::optional<u32> AllocateRegister(const std::array<HostLocInfo, 32>& regs) const;
|
|
||||||
void SpillGpr(u32 index);
|
|
||||||
void SpillFpr(u32 index);
|
|
||||||
u32 FindFreeSpill() const;
|
|
||||||
|
|
||||||
std::optional<HostLoc> ValueLocation(const IR::Inst* value) const;
|
|
||||||
HostLocInfo& ValueInfo(HostLoc host_loc);
|
|
||||||
HostLocInfo& ValueInfo(const IR::Inst* value);
|
|
||||||
|
|
||||||
powah::Context& code;
|
|
||||||
std::array<HostLocInfo, 32> gprs;
|
|
||||||
std::array<HostLocInfo, 32> fprs;
|
|
||||||
std::array<HostLocInfo, 32> vprs;
|
|
||||||
std::array<HostLocInfo, SpillCount> spills;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> inline void RegLock<powah::GPR>::SetLock(bool v) noexcept {
|
|
||||||
reg_alloc.gprs[value.index].locked = v;
|
|
||||||
}
|
|
||||||
template<> inline void RegLock<powah::FPR>::SetLock(bool v) noexcept {
|
|
||||||
reg_alloc.fprs[value.index].locked = v;
|
|
||||||
}
|
|
||||||
template<> inline void RegLock<powah::VPR>::SetLock(bool v) noexcept {
|
|
||||||
reg_alloc.vprs[value.index].locked = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::Backend::PPC64 {
|
|
||||||
|
|
||||||
constexpr size_t SpillCount = 16;
|
|
||||||
|
|
||||||
struct alignas(16) StackLayout {
|
|
||||||
std::array<u64, SpillCount> spill;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(StackLayout) % 16 == 0);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::RV64
|
|
||||||
@@ -67,8 +67,14 @@ public:
|
|||||||
const void* code_ptr = nullptr;
|
const void* code_ptr = nullptr;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
static constexpr u64 fast_dispatch_table_mask = 0xFF0;
|
||||||
|
static constexpr size_t fast_dispatch_table_size = 0x100;
|
||||||
|
#else
|
||||||
static constexpr u64 fast_dispatch_table_mask = 0xFFFF0;
|
static constexpr u64 fast_dispatch_table_mask = 0xFFFF0;
|
||||||
static constexpr size_t fast_dispatch_table_size = 0x10000;
|
static constexpr size_t fast_dispatch_table_size = 0x10000;
|
||||||
|
#endif
|
||||||
|
|
||||||
void ClearFastDispatchTable();
|
void ClearFastDispatchTable();
|
||||||
void GenFastmemFallbacks();
|
void GenFastmemFallbacks();
|
||||||
void GenTerminalHandlers();
|
void GenTerminalHandlers();
|
||||||
|
|||||||
@@ -60,8 +60,13 @@ public:
|
|||||||
const void* code_ptr = nullptr;
|
const void* code_ptr = nullptr;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
static constexpr u64 fast_dispatch_table_mask = 0xFF0;
|
||||||
|
static constexpr size_t fast_dispatch_table_size = 0x100;
|
||||||
|
#else
|
||||||
static constexpr u64 fast_dispatch_table_mask = 0xFFFFF0;
|
static constexpr u64 fast_dispatch_table_mask = 0xFFFFF0;
|
||||||
static constexpr size_t fast_dispatch_table_size = 0x100000;
|
static constexpr size_t fast_dispatch_table_size = 0x100000;
|
||||||
|
#endif
|
||||||
|
|
||||||
void ClearFastDispatchTable();
|
void ClearFastDispatchTable();
|
||||||
void GenMemory128Accessors();
|
void GenMemory128Accessors();
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block, boost::container
|
|||||||
|
|
||||||
EmitContext::~EmitContext() = default;
|
EmitContext::~EmitContext() = default;
|
||||||
|
|
||||||
EmitX64::EmitX64(BlockOfCode& code)
|
EmitX64::EmitX64(BlockOfCode& code) : code(code) {
|
||||||
: code(code) {
|
#ifndef __OPENORBIS__
|
||||||
exception_handler.Register(code);
|
exception_handler.Register(code);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitX64::~EmitX64() = default;
|
EmitX64::~EmitX64() = default;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
# define CTX_Q(i) (fpctx->vregs[i])
|
# define CTX_Q(i) (fpctx->vregs[i])
|
||||||
# define CTX_FPSR (fpctx->fpsr)
|
# define CTX_FPSR (fpctx->fpsr)
|
||||||
# define CTX_FPCR (fpctx->fpcr)
|
# define CTX_FPCR (fpctx->fpcr)
|
||||||
# elif defined(__FreeBSD__)
|
# elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
# define CTX_PC (mctx.mc_gpregs.gp_elr)
|
# define CTX_PC (mctx.mc_gpregs.gp_elr)
|
||||||
# define CTX_SP (mctx.mc_gpregs.gp_sp)
|
# define CTX_SP (mctx.mc_gpregs.gp_sp)
|
||||||
# define CTX_LR (mctx.mc_gpregs.gp_lr)
|
# define CTX_LR (mctx.mc_gpregs.gp_lr)
|
||||||
@@ -131,6 +131,9 @@
|
|||||||
# elif defined(__managarm__)
|
# elif defined(__managarm__)
|
||||||
# define CTX_PC (mctx.__pollution(gregs)[REG_RIP])
|
# define CTX_PC (mctx.__pollution(gregs)[REG_RIP])
|
||||||
# define CTX_SP (mctx.__pollution(gregs)[REG_RSP])
|
# define CTX_SP (mctx.__pollution(gregs)[REG_RSP])
|
||||||
|
# elif defined(__OPENORBIS__)
|
||||||
|
# define CTX_RIP (mctx.gregs[REG_RIP])
|
||||||
|
# define CTX_RSP (mctx.gregs[REG_RSP])
|
||||||
# else
|
# else
|
||||||
# error "unknown platform"
|
# error "unknown platform"
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
#include "dynarmic/backend/ppc64/abi.h"
|
|
||||||
#include "dynarmic/backend/ppc64/hostloc.h"
|
|
||||||
#include "dynarmic/common/spin_lock.h"
|
|
||||||
#include "common/assert.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
|
|
||||||
/*
|
|
||||||
void acquire(atomic_flag* lock) {
|
|
||||||
while(atomic_flag_test_and_set_explicit( lock, memory_order_acquire))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void EmitSpinLockLock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void release(atomic_flag* lock) {
|
|
||||||
atomic_flag_clear_explicit(lock, memory_order_release);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void EmitSpinLockUnlock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct SpinLockImpl {
|
|
||||||
void Initialize();
|
|
||||||
powah::Context code;
|
|
||||||
void* page = nullptr;
|
|
||||||
void (*lock)(volatile int*);
|
|
||||||
void (*unlock)(volatile int*);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::once_flag flag;
|
|
||||||
SpinLockImpl impl;
|
|
||||||
|
|
||||||
void SpinLockImpl::Initialize() {
|
|
||||||
page = mmap(nullptr, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
|
|
||||||
ASSERT(page != nullptr);
|
|
||||||
code = powah::Context(page, 4096);
|
|
||||||
lock = reinterpret_cast<void (*)(volatile int*)>(code.base);
|
|
||||||
EmitSpinLockLock(code, Backend::PPC64::ABI_PARAM1, Backend::PPC64::ABI_PARAM2);
|
|
||||||
code.BLR();
|
|
||||||
unlock = reinterpret_cast<void (*)(volatile int*)>(code.base);
|
|
||||||
EmitSpinLockUnlock(code, Backend::PPC64::ABI_PARAM1, Backend::PPC64::ABI_PARAM2);
|
|
||||||
code.BLR();
|
|
||||||
// TODO: free the page, rework the stupid spinlock API
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void SpinLock::Lock() noexcept {
|
|
||||||
std::call_once(flag, &SpinLockImpl::Initialize, impl);
|
|
||||||
impl.lock(&storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpinLock::Unlock() noexcept {
|
|
||||||
std::call_once(flag, &SpinLockImpl::Initialize, impl);
|
|
||||||
impl.unlock(&storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <powah_emit.hpp>
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
|
|
||||||
void EmitSpinLockLock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp);
|
|
||||||
void EmitSpinLockUnlock(powah::Context& code, powah::GPR const ptr, powah::GPR const tmp);
|
|
||||||
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "dynarmic/backend/x64/abi.h"
|
#include "dynarmic/backend/x64/abi.h"
|
||||||
#include "dynarmic/backend/x64/hostloc.h"
|
#include "dynarmic/backend/x64/hostloc.h"
|
||||||
#include "dynarmic/common/spin_lock.h"
|
#include "dynarmic/common/spin_lock.h"
|
||||||
|
#include "xbyak/xbyak.h"
|
||||||
|
|
||||||
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
|
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
|
||||||
static const auto default_cg_mode = Xbyak::DontSetProtectRWE;
|
static const auto default_cg_mode = Xbyak::DontSetProtectRWE;
|
||||||
@@ -78,7 +79,7 @@ namespace {
|
|||||||
struct SpinLockImpl {
|
struct SpinLockImpl {
|
||||||
void Initialize() noexcept;
|
void Initialize() noexcept;
|
||||||
static void GlobalInitialize() noexcept;
|
static void GlobalInitialize() noexcept;
|
||||||
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode);
|
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(Xbyak::inner::getPageSize(), default_cg_mode);
|
||||||
void (*lock)(volatile int*) = nullptr;
|
void (*lock)(volatile int*) = nullptr;
|
||||||
void (*unlock)(volatile int*) = nullptr;
|
void (*unlock)(volatile int*) = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,3 +134,8 @@ target_compile_options(dynarmic_tests PRIVATE ${DYNARMIC_CXX_FLAGS})
|
|||||||
target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
||||||
|
|
||||||
add_test(NAME dynarmic_tests COMMAND dynarmic_tests --durations yes)
|
add_test(NAME dynarmic_tests COMMAND dynarmic_tests --durations yes)
|
||||||
|
|
||||||
|
if (OPENORBIS)
|
||||||
|
target_link_libraries(dynarmic_tests PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService ps4sup)
|
||||||
|
create_ps4_eboot(dynarmic_tests dynarmic_tests IV0000-BREW00090_00-DYNARMICTS000000)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -1033,27 +1033,20 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonMapping SDLDriver::GetSingleControllerMapping(
|
ButtonMapping SDLDriver::GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button, const ZButtonBindings& switch_to_sdl_axis) const {
|
||||||
const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button,
|
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const {
|
|
||||||
ButtonMapping mapping;
|
ButtonMapping mapping;
|
||||||
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
||||||
auto* controller = joystick->GetSDLGameController();
|
if (auto* controller = joystick->GetSDLGameController(); controller) {
|
||||||
const auto bindings = GetBindings(controller);
|
const auto bindings = GetBindings(controller);
|
||||||
|
|
||||||
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
||||||
const auto binding = GetBindingForButton(bindings, sdl_button);
|
const auto binding = GetBindingForButton(bindings, sdl_button);
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(switch_button, BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
switch_button,
|
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
|
||||||
}
|
}
|
||||||
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
||||||
const auto binding = GetBindingForAxis(bindings, sdl_axis);
|
const auto binding = GetBindingForAxis(bindings, sdl_axis);
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(switch_button, BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
switch_button,
|
}
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,10 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
RegisterEngine("gcpad", gcadapter);
|
RegisterEngine("gcpad", gcadapter);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
|
// TODO: Issue in PS4, crash for UDP_client
|
||||||
RegisterEngine("cemuhookudp", udp_client);
|
RegisterEngine("cemuhookudp", udp_client);
|
||||||
|
#endif
|
||||||
RegisterEngine("tas", tas_input);
|
RegisterEngine("tas", tas_input);
|
||||||
RegisterEngine("camera", camera);
|
RegisterEngine("camera", camera);
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@@ -116,7 +119,9 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
UnregisterEngine(gcadapter);
|
UnregisterEngine(gcadapter);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
UnregisterEngine(udp_client);
|
UnregisterEngine(udp_client);
|
||||||
|
#endif
|
||||||
UnregisterEngine(tas_input);
|
UnregisterEngine(tas_input);
|
||||||
UnregisterEngine(camera);
|
UnregisterEngine(camera);
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@@ -152,8 +157,10 @@ struct InputSubsystem::Impl {
|
|||||||
auto gcadapter_devices = gcadapter->GetInputDevices();
|
auto gcadapter_devices = gcadapter->GetInputDevices();
|
||||||
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
auto udp_devices = udp_client->GetInputDevices();
|
auto udp_devices = udp_client->GetInputDevices();
|
||||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
auto joycon_devices = joycon->GetInputDevices();
|
auto joycon_devices = joycon->GetInputDevices();
|
||||||
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
||||||
@@ -186,9 +193,11 @@ struct InputSubsystem::Impl {
|
|||||||
return gcadapter;
|
return gcadapter;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
if (engine == udp_client->GetEngineName()) {
|
if (engine == udp_client->GetEngineName()) {
|
||||||
return udp_client;
|
return udp_client;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
if (engine == sdl->GetEngineName()) {
|
if (engine == sdl->GetEngineName()) {
|
||||||
return sdl;
|
return sdl;
|
||||||
@@ -271,9 +280,11 @@ struct InputSubsystem::Impl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
if (engine == udp_client->GetEngineName()) {
|
if (engine == udp_client->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (engine == tas_input->GetEngineName()) {
|
if (engine == tas_input->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -300,7 +311,9 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
gcadapter->BeginConfiguration();
|
gcadapter->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
udp_client->BeginConfiguration();
|
udp_client->BeginConfiguration();
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
sdl->BeginConfiguration();
|
sdl->BeginConfiguration();
|
||||||
joycon->BeginConfiguration();
|
joycon->BeginConfiguration();
|
||||||
@@ -316,7 +329,9 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
gcadapter->EndConfiguration();
|
gcadapter->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
udp_client->EndConfiguration();
|
udp_client->EndConfiguration();
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
sdl->EndConfiguration();
|
sdl->EndConfiguration();
|
||||||
joycon->EndConfiguration();
|
joycon->EndConfiguration();
|
||||||
@@ -341,7 +356,9 @@ struct InputSubsystem::Impl {
|
|||||||
std::shared_ptr<Mouse> mouse;
|
std::shared_ptr<Mouse> mouse;
|
||||||
std::shared_ptr<TouchScreen> touch_screen;
|
std::shared_ptr<TouchScreen> touch_screen;
|
||||||
std::shared_ptr<TasInput::Tas> tas_input;
|
std::shared_ptr<TasInput::Tas> tas_input;
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
||||||
|
#endif
|
||||||
std::shared_ptr<Camera> camera;
|
std::shared_ptr<Camera> camera;
|
||||||
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
||||||
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
||||||
@@ -470,7 +487,9 @@ bool InputSubsystem::IsStickInverted(const Common::ParamPackage& params) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InputSubsystem::ReloadInputDevices() {
|
void InputSubsystem::ReloadInputDevices() {
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
impl->udp_client.get()->ReloadSockets();
|
impl->udp_client.get()->ReloadSockets();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputSubsystem::BeginMapping(Polling::InputType type) {
|
void InputSubsystem::BeginMapping(Polling::InputType type) {
|
||||||
|
|||||||
@@ -160,7 +160,13 @@ struct Values {
|
|||||||
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
|
Setting<bool> show_console{linkage,
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
true,
|
||||||
|
#else
|
||||||
|
false,
|
||||||
|
#endif
|
||||||
|
"showConsole", Category::Ui};
|
||||||
|
|
||||||
// Screenshots
|
// Screenshots
|
||||||
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
|
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
|
||||||
|
|||||||
@@ -37,3 +37,8 @@ if (NOT MSVC)
|
|||||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
||||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (OPENORBIS)
|
||||||
|
target_link_libraries(tests PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService ps4sup)
|
||||||
|
create_ps4_eboot(tests tests IV0000-BREW00090_00-DYNARMICTS000000)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -209,3 +209,74 @@ TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common
|
|||||||
REQUIRE(ptr[0x0000] == 19);
|
REQUIRE(ptr[0x0000] == 19);
|
||||||
REQUIRE(ptr[0x3fff] == 12);
|
REQUIRE(ptr[0x3fff] == 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Nieche allocation", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x20000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x0000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x1000, 0, 0x2000, PERMS, HEAP);
|
||||||
|
mem.Map(0x3000, 0, 0x1000, PERMS, HEAP);
|
||||||
|
mem.Map(0, 0, 0x1000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Full unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x8000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x6000, 0, 0x16000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x2000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x2000, 0x80000, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x6000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x2000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x4000, 0, 0x1b000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x3000, 0x1c000, HEAP);
|
||||||
|
mem.Map(0x3000, 0, 0x20000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Unmap between placeholders", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x2000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x2000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Unmap to origin", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x4000, 0x4000, HEAP);
|
||||||
|
mem.Map(0, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Unmap to right", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x8000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
#include "input_common/drivers/udp_client.h"
|
#include "input_common/drivers/udp_client.h"
|
||||||
#include "input_common/helpers/udp_protocol.h"
|
#include "input_common/helpers/udp_protocol.h"
|
||||||
|
|
||||||
|
// PS4 doesn't support cemuhook
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
class FakeCemuhookServer {
|
class FakeCemuhookServer {
|
||||||
public:
|
public:
|
||||||
FakeCemuhookServer()
|
FakeCemuhookServer()
|
||||||
@@ -132,3 +133,4 @@ TEST_CASE("CalibrationConfigurationJob completed", "[input_common]") {
|
|||||||
REQUIRE(max_x == 200);
|
REQUIRE(max_x == 200);
|
||||||
REQUIRE(max_y == 200);
|
REQUIRE(max_y == 200);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -33,7 +33,11 @@ constexpr VkDeviceSize MAX_ALIGNMENT = 256;
|
|||||||
// Windows ones however, can intake bigger buffers and generally do not OOM.
|
// Windows ones however, can intake bigger buffers and generally do not OOM.
|
||||||
// - GTX 960 on Windows will not OOM with 256mib
|
// - GTX 960 on Windows will not OOM with 256mib
|
||||||
// - GT 1030 on ^NIX will OOM with 256mib
|
// - GT 1030 on ^NIX will OOM with 256mib
|
||||||
#if defined(__FreeBSD__)
|
// With Orbis we need to be insanely chary with our allocations
|
||||||
|
// anything over 64MB is prone to crash the GPU, I'm sorry.
|
||||||
|
#if defined(__OPENORBIS__)
|
||||||
|
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 32_MiB;
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
|
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
|
||||||
#else
|
#else
|
||||||
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 256_MiB;
|
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 256_MiB;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user