summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitmodules3
-rwxr-xr-x.travis/linux-mingw/docker.sh10
-rwxr-xr-x.travis/linux/docker.sh2
-rwxr-xr-x.travis/macos/build.sh3
-rw-r--r--CMakeLists.txt77
-rw-r--r--CMakeModules/CopyYuzuUnicornDeps.cmake9
m---------externals/unicorn0
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp1
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp29
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp295
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h63
-rw-r--r--src/core/hle/kernel/physical_core.cpp16
-rw-r--r--src/core/hle/kernel/thread.cpp17
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu_cmd/CMakeLists.txt2
-rw-r--r--src/yuzu_tester/CMakeLists.txt2
18 files changed, 18 insertions, 519 deletions
diff --git a/.gitmodules b/.gitmodules
index 6931a641d..41022615b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,9 +7,6 @@
7[submodule "dynarmic"] 7[submodule "dynarmic"]
8 path = externals/dynarmic 8 path = externals/dynarmic
9 url = https://github.com/MerryMage/dynarmic.git 9 url = https://github.com/MerryMage/dynarmic.git
10[submodule "unicorn"]
11 path = externals/unicorn
12 url = https://github.com/yuzu-emu/unicorn
13[submodule "soundtouch"] 10[submodule "soundtouch"]
14 path = externals/soundtouch 11 path = externals/soundtouch
15 url = https://github.com/citra-emu/ext-soundtouch.git 12 url = https://github.com/citra-emu/ext-soundtouch.git
diff --git a/.travis/linux-mingw/docker.sh b/.travis/linux-mingw/docker.sh
index 28033acfb..80d7dfe9b 100755
--- a/.travis/linux-mingw/docker.sh
+++ b/.travis/linux-mingw/docker.sh
@@ -4,16 +4,8 @@ cd /yuzu
4# override Travis CI unreasonable ccache size 4# override Travis CI unreasonable ccache size
5echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf" 5echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
6 6
7# Dirty hack to trick unicorn makefile into believing we are in a MINGW system
8mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname
9chmod +x /bin/uname
10
11# Dirty hack to trick unicorn makefile into believing we have cmd
12echo '' >> /bin/cmd
13chmod +x /bin/cmd
14
15mkdir build && cd build 7mkdir build && cd build
16cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release 8cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
17ninja 9ninja
18 10
19# Clean up the dirty hacks 11# Clean up the dirty hacks
diff --git a/.travis/linux/docker.sh b/.travis/linux/docker.sh
index 3a9970384..166fb6d4c 100755
--- a/.travis/linux/docker.sh
+++ b/.travis/linux/docker.sh
@@ -3,7 +3,7 @@
3cd /yuzu 3cd /yuzu
4 4
5mkdir build && cd build 5mkdir build && cd build
6cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON 6cmake .. -G Ninja -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
7ninja 7ninja
8 8
9ccache -s 9ccache -s
diff --git a/.travis/macos/build.sh b/.travis/macos/build.sh
index 0abd1a93a..db1c7cae7 100755
--- a/.travis/macos/build.sh
+++ b/.travis/macos/build.sh
@@ -4,13 +4,12 @@ set -o pipefail
4 4
5export MACOSX_DEPLOYMENT_TARGET=10.14 5export MACOSX_DEPLOYMENT_TARGET=10.14
6export Qt5_DIR=$(brew --prefix)/opt/qt5 6export Qt5_DIR=$(brew --prefix)/opt/qt5
7export UNICORNDIR=$(pwd)/externals/unicorn
8export PATH="/usr/local/opt/ccache/libexec:$PATH" 7export PATH="/usr/local/opt/ccache/libexec:$PATH"
9 8
10# TODO: Build using ninja instead of make 9# TODO: Build using ninja instead of make
11mkdir build && cd build 10mkdir build && cd build
12cmake --version 11cmake --version
13cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON 12cmake .. -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
14make -j4 13make -j4
15 14
16ccache -s 15ccache -s
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1bd9d2aa7..8fc2de042 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,8 +18,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
18 18
19option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) 19option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
20 20
21option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
22
23option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) 21option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
24 22
25option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON) 23option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
@@ -372,81 +370,6 @@ endif()
372set(THREADS_PREFER_PTHREAD_FLAG ON) 370set(THREADS_PREFER_PTHREAD_FLAG ON)
373find_package(Threads REQUIRED) 371find_package(Threads REQUIRED)
374 372
375# If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external
376if (YUZU_USE_BUNDLED_UNICORN)
377 if (MSVC)
378 message(STATUS "unicorn not found, falling back to bundled")
379 # Detect toolchain and platform
380 if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
381 set(UNICORN_VER "unicorn-yuzu")
382 else()
383 message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
384 endif()
385
386 if (DEFINED UNICORN_VER)
387 download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
388 endif()
389
390 if (DEFINED UNICORN_VER)
391 download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
392 endif()
393
394 set(UNICORN_FOUND YES)
395 set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
396 set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/lib/x64/unicorn_dynload.lib" CACHE PATH "Path to Unicorn library" FORCE)
397 set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/lib/x64/" CACHE PATH "Path to unicorn.dll" FORCE)
398 else()
399 message(STATUS "unicorn not found, falling back to externals")
400 if (MINGW)
401 set(UNICORN_LIB_NAME "unicorn.a")
402 else()
403 set(UNICORN_LIB_NAME "libunicorn.a")
404 endif()
405
406 set(UNICORN_FOUND YES)
407 set(UNICORN_PREFIX ${PROJECT_SOURCE_DIR}/externals/unicorn)
408 set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/${UNICORN_LIB_NAME}" CACHE PATH "Path to Unicorn library" FORCE)
409 set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
410 set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/" CACHE PATH "Path to unicorn dynamic library" FORCE)
411
412 find_package(PythonInterp 2.7 REQUIRED)
413
414 if (MINGW)
415 # Intentionally call the unicorn makefile directly instead of using make.sh so that we can override the
416 # UNAME_S makefile variable to MINGW. This way we don't have to hack at the uname binary to build
417 # Additionally, overriding DO_WINDOWS_EXPORT prevents unicorn from patching the static unicorn.a by using msvc and cmd,
418 # which are both things we don't have in a mingw cross compiling environment.
419 add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
420 COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-gcc-ar RANLIB=x86_64-w64-mingw32-gcc-ranlib make UNAME_S=MINGW DO_WINDOWS_EXPORT=0
421 WORKING_DIRECTORY ${UNICORN_PREFIX}
422 )
423 else()
424 add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
425 COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
426 WORKING_DIRECTORY ${UNICORN_PREFIX}
427 )
428 endif()
429
430 # ALL makes this custom target build every time
431 # but it won't actually build if LIBUNICORN_LIBRARY is up to date
432 add_custom_target(unicorn-build ALL
433 DEPENDS ${LIBUNICORN_LIBRARY}
434 )
435 unset(UNICORN_LIB_NAME)
436 endif()
437else()
438 find_package(Unicorn REQUIRED)
439endif()
440
441if (UNICORN_FOUND)
442 add_library(unicorn INTERFACE)
443 add_dependencies(unicorn unicorn-build)
444 target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
445 target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
446else()
447 message(FATAL_ERROR "Could not find or build unicorn which is required.")
448endif()
449
450# Platform-specific library requirements 373# Platform-specific library requirements
451# ====================================== 374# ======================================
452 375
diff --git a/CMakeModules/CopyYuzuUnicornDeps.cmake b/CMakeModules/CopyYuzuUnicornDeps.cmake
deleted file mode 100644
index 7af0ef023..000000000
--- a/CMakeModules/CopyYuzuUnicornDeps.cmake
+++ /dev/null
@@ -1,9 +0,0 @@
1function(copy_yuzu_unicorn_deps target_dir)
2 include(WindowsCopyFiles)
3 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
4 windows_copy_files(${target_dir} ${UNICORN_DLL_DIR} ${DLL_DEST}
5 libgcc_s_seh-1.dll
6 libwinpthread-1.dll
7 unicorn.dll
8 )
9endfunction(copy_yuzu_unicorn_deps)
diff --git a/externals/unicorn b/externals/unicorn
deleted file mode 160000
Subproject 73f45735354396766a4bfb26d0b96b06e5cf31b
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e0f207f3e..19c926662 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -13,8 +13,6 @@ add_library(core STATIC
13 arm/dynarmic/arm_exclusive_monitor.h 13 arm/dynarmic/arm_exclusive_monitor.h
14 arm/exclusive_monitor.cpp 14 arm/exclusive_monitor.cpp
15 arm/exclusive_monitor.h 15 arm/exclusive_monitor.h
16 arm/unicorn/arm_unicorn.cpp
17 arm/unicorn/arm_unicorn.h
18 constants.cpp 16 constants.cpp
19 constants.h 17 constants.h
20 core.cpp 18 core.cpp
@@ -644,7 +642,7 @@ endif()
644create_target_directory_groups(core) 642create_target_directory_groups(core)
645 643
646target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 644target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
647target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip) 645target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
648 646
649if (YUZU_ENABLE_BOXCAT) 647if (YUZU_ENABLE_BOXCAT)
650 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) 648 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index b5f28a86e..6dc03f3b1 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -7,6 +7,7 @@
7#include <dynarmic/A32/a32.h> 7#include <dynarmic/A32/a32.h>
8#include <dynarmic/A32/config.h> 8#include <dynarmic/A32/config.h>
9#include <dynarmic/A32/context.h> 9#include <dynarmic/A32/context.h>
10#include "common/assert.h"
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/page_table.h" 12#include "common/page_table.h"
12#include "core/arm/cpu_interrupt_handler.h" 13#include "core/arm/cpu_interrupt_handler.h"
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index ce9968724..9f170a224 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -6,6 +6,7 @@
6#include <memory> 6#include <memory>
7#include <dynarmic/A64/a64.h> 7#include <dynarmic/A64/a64.h>
8#include <dynarmic/A64/config.h> 8#include <dynarmic/A64/config.h>
9#include "common/assert.h"
9#include "common/logging/log.h" 10#include "common/logging/log.h"
10#include "common/page_table.h" 11#include "common/page_table.h"
11#include "core/arm/cpu_interrupt_handler.h" 12#include "core/arm/cpu_interrupt_handler.h"
@@ -13,7 +14,6 @@
13#include "core/arm/dynarmic/arm_exclusive_monitor.h" 14#include "core/arm/dynarmic/arm_exclusive_monitor.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/core_timing.h" 16#include "core/core_timing.h"
16#include "core/core_timing_util.h"
17#include "core/gdbstub/gdbstub.h" 17#include "core/gdbstub/gdbstub.h"
18#include "core/hardware_properties.h" 18#include "core/hardware_properties.h"
19#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
@@ -82,16 +82,9 @@ public:
82 } 82 }
83 83
84 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 84 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
85 LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, 85 LOG_ERROR(Core_ARM,
86 num_instructions, MemoryReadCode(pc)); 86 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
87 87 num_instructions, MemoryReadCode(pc));
88 ARM_Interface::ThreadContext64 ctx;
89 parent.SaveContext(ctx);
90 parent.inner_unicorn.LoadContext(ctx);
91 parent.inner_unicorn.ExecuteInstructions(num_instructions);
92 parent.inner_unicorn.SaveContext(ctx);
93 parent.LoadContext(ctx);
94 num_interpreted_instructions += num_instructions;
95 } 88 }
96 89
97 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { 90 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -127,18 +120,17 @@ public:
127 if (parent.uses_wall_clock) { 120 if (parent.uses_wall_clock) {
128 return; 121 return;
129 } 122 }
123
130 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 124 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
131 // rough approximation of the amount of executed ticks in the system, it may be thrown off 125 // rough approximation of the amount of executed ticks in the system, it may be thrown off
132 // if not all cores are doing a similar amount of work. Instead of doing this, we should 126 // if not all cores are doing a similar amount of work. Instead of doing this, we should
133 // device a way so that timing is consistent across all cores without increasing the ticks 4 127 // device a way so that timing is consistent across all cores without increasing the ticks 4
134 // times. 128 // times.
135 u64 amortized_ticks = 129 u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
136 (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
137 // Always execute at least one tick. 130 // Always execute at least one tick.
138 amortized_ticks = std::max<u64>(amortized_ticks, 1); 131 amortized_ticks = std::max<u64>(amortized_ticks, 1);
139 132
140 parent.system.CoreTiming().AddTicks(amortized_ticks); 133 parent.system.CoreTiming().AddTicks(amortized_ticks);
141 num_interpreted_instructions = 0;
142 } 134 }
143 135
144 u64 GetTicksRemaining() override { 136 u64 GetTicksRemaining() override {
@@ -156,7 +148,6 @@ public:
156 } 148 }
157 149
158 ARM_Dynarmic_64& parent; 150 ARM_Dynarmic_64& parent;
159 std::size_t num_interpreted_instructions = 0;
160 u64 tpidrro_el0 = 0; 151 u64 tpidrro_el0 = 0;
161 u64 tpidr_el0 = 0; 152 u64 tpidr_el0 = 0;
162 static constexpr u64 minimum_run_cycles = 1000U; 153 static constexpr u64 minimum_run_cycles = 1000U;
@@ -248,12 +239,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
248 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, 239 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
249 std::size_t core_index) 240 std::size_t core_index)
250 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 241 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
251 cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers, 242 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
252 uses_wall_clock, 243 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
253 ARM_Unicorn::Arch::AArch64,
254 core_index},
255 core_index{core_index}, exclusive_monitor{
256 dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
257 244
258ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; 245ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
259 246
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 403c55961..28e11a17d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -12,7 +12,6 @@
12#include "common/hash.h" 12#include "common/hash.h"
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/arm/exclusive_monitor.h" 14#include "core/arm/exclusive_monitor.h"
15#include "core/arm/unicorn/arm_unicorn.h"
16 15
17namespace Core::Memory { 16namespace Core::Memory {
18class Memory; 17class Memory;
@@ -71,7 +70,6 @@ private:
71 std::unique_ptr<DynarmicCallbacks64> cb; 70 std::unique_ptr<DynarmicCallbacks64> cb;
72 JitCacheType jit_cache; 71 JitCacheType jit_cache;
73 std::shared_ptr<Dynarmic::A64::Jit> jit; 72 std::shared_ptr<Dynarmic::A64::Jit> jit;
74 ARM_Unicorn inner_unicorn;
75 73
76 std::size_t core_index; 74 std::size_t core_index;
77 DynarmicExclusiveMonitor& exclusive_monitor; 75 DynarmicExclusiveMonitor& exclusive_monitor;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
deleted file mode 100644
index 1df3f3ed1..000000000
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <unicorn/arm64.h>
7#include "common/assert.h"
8#include "common/microprofile.h"
9#include "core/arm/cpu_interrupt_handler.h"
10#include "core/arm/unicorn/arm_unicorn.h"
11#include "core/core.h"
12#include "core/core_timing.h"
13#include "core/hle/kernel/scheduler.h"
14#include "core/hle/kernel/svc.h"
15#include "core/memory.h"
16
17namespace Core {
18
19// Load Unicorn DLL once on Windows using RAII
20#ifdef _MSC_VER
21#include <unicorn_dynload.h>
22struct LoadDll {
23private:
24 LoadDll() {
25 ASSERT(uc_dyn_load(NULL, 0));
26 }
27 ~LoadDll() {
28 ASSERT(uc_dyn_free());
29 }
30 static LoadDll g_load_dll;
31};
32LoadDll LoadDll::g_load_dll;
33#endif
34
35#define CHECKED(expr) \
36 do { \
37 if (auto _cerr = (expr)) { \
38 ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
39 uc_strerror(_cerr)); \
40 } \
41 } while (0)
42
43static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
44 GDBStub::BreakpointAddress bkpt =
45 GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
46 if (GDBStub::IsMemoryBreak() ||
47 (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
48 auto core = static_cast<ARM_Unicorn*>(user_data);
49 core->RecordBreak(bkpt);
50 uc_emu_stop(uc);
51 }
52}
53
54static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
55 void* user_data) {
56 auto* const system = static_cast<System*>(user_data);
57
58 ARM_Interface::ThreadContext64 ctx{};
59 system->CurrentArmInterface().SaveContext(ctx);
60 ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
61 ctx.pc, ctx.cpu_registers[30]);
62
63 return false;
64}
65
66ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
67 Arch architecture, std::size_t core_index)
68 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} {
69 const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
70 CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
71
72 auto fpv = 3 << 20;
73 CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv));
74
75 uc_hook hook{};
76 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX));
77 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0,
78 UINT64_MAX));
79 if (GDBStub::IsServerEnabled()) {
80 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX));
81 last_bkpt_hit = false;
82 }
83}
84
85ARM_Unicorn::~ARM_Unicorn() {
86 CHECKED(uc_close(uc));
87}
88
89void ARM_Unicorn::SetPC(u64 pc) {
90 CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
91}
92
93u64 ARM_Unicorn::GetPC() const {
94 u64 val{};
95 CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val));
96 return val;
97}
98
99u64 ARM_Unicorn::GetReg(int regn) const {
100 u64 val{};
101 auto treg = UC_ARM64_REG_SP;
102 if (regn <= 28) {
103 treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
104 } else if (regn < 31) {
105 treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
106 }
107 CHECKED(uc_reg_read(uc, treg, &val));
108 return val;
109}
110
111void ARM_Unicorn::SetReg(int regn, u64 val) {
112 auto treg = UC_ARM64_REG_SP;
113 if (regn <= 28) {
114 treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
115 } else if (regn < 31) {
116 treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
117 }
118 CHECKED(uc_reg_write(uc, treg, &val));
119}
120
121u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
122 UNIMPLEMENTED();
123 static constexpr u128 res{};
124 return res;
125}
126
127void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
128 UNIMPLEMENTED();
129}
130
131u32 ARM_Unicorn::GetPSTATE() const {
132 u64 nzcv{};
133 CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
134 return static_cast<u32>(nzcv);
135}
136
137void ARM_Unicorn::SetPSTATE(u32 pstate) {
138 u64 nzcv = pstate;
139 CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
140}
141
142VAddr ARM_Unicorn::GetTlsAddress() const {
143 u64 base{};
144 CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
145 return base;
146}
147
148void ARM_Unicorn::SetTlsAddress(VAddr base) {
149 CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
150}
151
152u64 ARM_Unicorn::GetTPIDR_EL0() const {
153 u64 value{};
154 CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
155 return value;
156}
157
158void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
159 CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
160}
161
162void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) {
163 core_index = new_core_id;
164}
165
166void ARM_Unicorn::Run() {
167 if (GDBStub::IsServerEnabled()) {
168 ExecuteInstructions(std::max(4000000U, 0U));
169 } else {
170 while (true) {
171 if (interrupt_handlers[core_index].IsInterrupted()) {
172 return;
173 }
174 ExecuteInstructions(10);
175 }
176 }
177}
178
179void ARM_Unicorn::Step() {
180 ExecuteInstructions(1);
181}
182
183MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
184
185void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
186 MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
187
188 // Temporarily map the code page for Unicorn
189 u64 map_addr{GetPC() & ~Memory::PAGE_MASK};
190 std::vector<u8> page_buffer(Memory::PAGE_SIZE);
191 system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size());
192
193 CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(),
194 UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data()));
195 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
196 CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size()));
197 if (GDBStub::IsServerEnabled()) {
198 if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
199 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
200 }
201
202 Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
203 SaveContext(thread->GetContext64());
204 if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
205 last_bkpt_hit = false;
206 GDBStub::Break();
207 GDBStub::SendTrap(thread, 5);
208 }
209 }
210}
211
212void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
213 int uregs[32];
214 void* tregs[32];
215
216 CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
217 CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
218 CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
219
220 for (auto i = 0; i < 29; ++i) {
221 uregs[i] = UC_ARM64_REG_X0 + i;
222 tregs[i] = &ctx.cpu_registers[i];
223 }
224 uregs[29] = UC_ARM64_REG_X29;
225 tregs[29] = (void*)&ctx.cpu_registers[29];
226 uregs[30] = UC_ARM64_REG_X30;
227 tregs[30] = (void*)&ctx.cpu_registers[30];
228
229 CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
230
231 for (int i = 0; i < 32; ++i) {
232 uregs[i] = UC_ARM64_REG_Q0 + i;
233 tregs[i] = &ctx.vector_registers[i];
234 }
235
236 CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
237}
238
239void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
240 int uregs[32];
241 void* tregs[32];
242
243 CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
244 CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
245 CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
246
247 for (int i = 0; i < 29; ++i) {
248 uregs[i] = UC_ARM64_REG_X0 + i;
249 tregs[i] = (void*)&ctx.cpu_registers[i];
250 }
251 uregs[29] = UC_ARM64_REG_X29;
252 tregs[29] = (void*)&ctx.cpu_registers[29];
253 uregs[30] = UC_ARM64_REG_X30;
254 tregs[30] = (void*)&ctx.cpu_registers[30];
255
256 CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
257
258 for (auto i = 0; i < 32; ++i) {
259 uregs[i] = UC_ARM64_REG_Q0 + i;
260 tregs[i] = (void*)&ctx.vector_registers[i];
261 }
262
263 CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
264}
265
266void ARM_Unicorn::PrepareReschedule() {
267 CHECKED(uc_emu_stop(uc));
268}
269
270void ARM_Unicorn::ClearExclusiveState() {}
271
272void ARM_Unicorn::ClearInstructionCache() {}
273
274void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
275 last_bkpt = bkpt;
276 last_bkpt_hit = true;
277}
278
279void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
280 u32 esr{};
281 CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
282
283 const auto ec = esr >> 26;
284 const auto iss = esr & 0xFFFFFF;
285
286 auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
287
288 switch (ec) {
289 case 0x15: // SVC
290 Kernel::Svc::Call(arm_instance->system, iss);
291 break;
292 }
293}
294
295} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
deleted file mode 100644
index 810aff311..000000000
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <unicorn/unicorn.h>
8#include "common/common_types.h"
9#include "core/arm/arm_interface.h"
10#include "core/gdbstub/gdbstub.h"
11
12namespace Core {
13
14class System;
15
16class ARM_Unicorn final : public ARM_Interface {
17public:
18 enum class Arch {
19 AArch32, // 32-bit ARM
20 AArch64, // 64-bit ARM
21 };
22
23 explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
24 Arch architecture, std::size_t core_index);
25 ~ARM_Unicorn() override;
26
27 void SetPC(u64 pc) override;
28 u64 GetPC() const override;
29 u64 GetReg(int index) const override;
30 void SetReg(int index, u64 value) override;
31 u128 GetVectorReg(int index) const override;
32 void SetVectorReg(int index, u128 value) override;
33 u32 GetPSTATE() const override;
34 void SetPSTATE(u32 pstate) override;
35 VAddr GetTlsAddress() const override;
36 void SetTlsAddress(VAddr address) override;
37 void SetTPIDR_EL0(u64 value) override;
38 u64 GetTPIDR_EL0() const override;
39 void ChangeProcessorID(std::size_t new_core_id) override;
40 void PrepareReschedule() override;
41 void ClearExclusiveState() override;
42 void ExecuteInstructions(std::size_t num_instructions);
43 void Run() override;
44 void Step() override;
45 void ClearInstructionCache() override;
46 void PageTableChanged(Common::PageTable&, std::size_t) override {}
47 void RecordBreak(GDBStub::BreakpointAddress bkpt);
48
49 void SaveContext(ThreadContext32& ctx) override {}
50 void SaveContext(ThreadContext64& ctx) override;
51 void LoadContext(const ThreadContext32& ctx) override {}
52 void LoadContext(const ThreadContext64& ctx) override;
53
54private:
55 static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
56
57 uc_engine* uc{};
58 GDBStub::BreakpointAddress last_bkpt{};
59 bool last_bkpt_hit = false;
60 std::size_t core_index;
61};
62
63} // namespace Core
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index c6bbdb080..6e04d025f 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -2,30 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
6#include "common/logging/log.h"
7#include "common/spin_lock.h" 5#include "common/spin_lock.h"
8#include "core/arm/arm_interface.h"
9#ifdef ARCHITECTURE_x86_64
10#include "core/arm/dynarmic/arm_dynarmic_32.h"
11#include "core/arm/dynarmic/arm_dynarmic_64.h"
12#endif
13#include "core/arm/cpu_interrupt_handler.h" 6#include "core/arm/cpu_interrupt_handler.h"
14#include "core/arm/exclusive_monitor.h"
15#include "core/arm/unicorn/arm_unicorn.h"
16#include "core/core.h" 7#include "core/core.h"
17#include "core/hle/kernel/physical_core.h" 8#include "core/hle/kernel/physical_core.h"
18#include "core/hle/kernel/scheduler.h" 9#include "core/hle/kernel/scheduler.h"
19#include "core/hle/kernel/thread.h"
20 10
21namespace Kernel { 11namespace Kernel {
22 12
23PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, 13PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler,
24 Core::CPUInterruptHandler& interrupt_handler) 14 Core::CPUInterruptHandler& interrupt_handler)
25 : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { 15 : interrupt_handler{interrupt_handler},
26 16 core_index{id}, scheduler{scheduler}, guard{std::make_unique<Common::SpinLock>()} {}
27 guard = std::make_unique<Common::SpinLock>();
28}
29 17
30PhysicalCore::~PhysicalCore() = default; 18PhysicalCore::~PhysicalCore() = default;
31 19
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index d132aba34..da0cb26b6 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,7 +13,6 @@
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/thread_queue_list.h" 14#include "common/thread_queue_list.h"
15#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/arm/unicorn/arm_unicorn.h"
17#include "core/core.h" 16#include "core/core.h"
18#include "core/cpu_manager.h" 17#include "core/cpu_manager.h"
19#include "core/hardware_properties.h" 18#include "core/hardware_properties.h"
@@ -217,8 +216,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
217 } else { 216 } else {
218 thread->tls_address = 0; 217 thread->tls_address = 0;
219 } 218 }
220 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used 219
221 // to initialize the context
222 thread->arm_interface.reset(); 220 thread->arm_interface.reset();
223 if ((type_flags & THREADTYPE_HLE) == 0) { 221 if ((type_flags & THREADTYPE_HLE) == 0) {
224#ifdef ARCHITECTURE_x86_64 222#ifdef ARCHITECTURE_x86_64
@@ -231,19 +229,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
231 system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), 229 system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
232 processor_id); 230 processor_id);
233 } 231 }
234
235#else 232#else
236 if (owner_process && !owner_process->Is64BitProcess()) { 233#error Platform not supported yet.
237 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
238 system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32,
239 processor_id);
240 } else {
241 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
242 system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64,
243 processor_id);
244 }
245 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
246#endif 234#endif
235
247 ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), 236 ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
248 static_cast<u32>(entry_point), static_cast<u32>(arg)); 237 static_cast<u32>(entry_point), static_cast<u32>(arg));
249 ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); 238 ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 4659e1f89..8abb74d56 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -264,11 +264,9 @@ endif()
264if (MSVC) 264if (MSVC)
265 include(CopyYuzuQt5Deps) 265 include(CopyYuzuQt5Deps)
266 include(CopyYuzuSDLDeps) 266 include(CopyYuzuSDLDeps)
267 include(CopyYuzuUnicornDeps)
268 include(CopyYuzuFFmpegDeps) 267 include(CopyYuzuFFmpegDeps)
269 copy_yuzu_Qt5_deps(yuzu) 268 copy_yuzu_Qt5_deps(yuzu)
270 copy_yuzu_SDL_deps(yuzu) 269 copy_yuzu_SDL_deps(yuzu)
271 copy_yuzu_unicorn_deps(yuzu)
272 copy_yuzu_FFmpeg_deps(yuzu) 270 copy_yuzu_FFmpeg_deps(yuzu)
273endif() 271endif()
274 272
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index a15719a0f..57f9916f6 100644
--- a/src/yuzu_cmd/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -39,7 +39,5 @@ endif()
39 39
40if (MSVC) 40if (MSVC)
41 include(CopyYuzuSDLDeps) 41 include(CopyYuzuSDLDeps)
42 include(CopyYuzuUnicornDeps)
43 copy_yuzu_SDL_deps(yuzu-cmd) 42 copy_yuzu_SDL_deps(yuzu-cmd)
44 copy_yuzu_unicorn_deps(yuzu-cmd)
45endif() 43endif()
diff --git a/src/yuzu_tester/CMakeLists.txt b/src/yuzu_tester/CMakeLists.txt
index 06c2ee011..d8a2a1511 100644
--- a/src/yuzu_tester/CMakeLists.txt
+++ b/src/yuzu_tester/CMakeLists.txt
@@ -28,7 +28,5 @@ endif()
28 28
29if (MSVC) 29if (MSVC)
30 include(CopyYuzuSDLDeps) 30 include(CopyYuzuSDLDeps)
31 include(CopyYuzuUnicornDeps)
32 copy_yuzu_SDL_deps(yuzu-tester) 31 copy_yuzu_SDL_deps(yuzu-tester)
33 copy_yuzu_unicorn_deps(yuzu-tester)
34endif() 32endif()