diff options
| -rwxr-xr-x | .travis-deps.sh | 4 | ||||
| -rwxr-xr-x | .travis-upload.sh | 2 | ||||
| -rw-r--r-- | .travis.yml | 1 | ||||
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | dist/citra.xml | 24 | ||||
| -rw-r--r-- | src/audio_core/sdl2_sink.cpp | 4 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/applets/erreula.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/applets/mii_selector.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/applets/swkbd.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.h | 34 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt_a.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt_u.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/cfg/cfg.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/service/err_f.cpp | 316 | ||||
| -rw-r--r-- | src/core/memory.cpp | 14 | ||||
| -rw-r--r-- | src/core/memory.h | 9 | ||||
| -rw-r--r-- | src/video_core/command_processor.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/pica.h | 2 |
23 files changed, 317 insertions, 181 deletions
diff --git a/.travis-deps.sh b/.travis-deps.sh index ab3a32382..9fd21cc57 100755 --- a/.travis-deps.sh +++ b/.travis-deps.sh | |||
| @@ -19,8 +19,8 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then | |||
| 19 | 19 | ||
| 20 | if [ ! -e $HOME/.local/lib/libSDL2.la ]; then | 20 | if [ ! -e $HOME/.local/lib/libSDL2.la ]; then |
| 21 | echo "SDL2 not found in cache, get and build it..." | 21 | echo "SDL2 not found in cache, get and build it..." |
| 22 | wget http://libsdl.org/release/SDL2-2.0.4.tar.gz -O - | tar xz | 22 | wget http://libsdl.org/release/SDL2-2.0.5.tar.gz -O - | tar xz |
| 23 | cd SDL2-2.0.4 | 23 | cd SDL2-2.0.5 |
| 24 | ./configure --prefix=$HOME/.local | 24 | ./configure --prefix=$HOME/.local |
| 25 | make -j4 && make install | 25 | make -j4 && make install |
| 26 | else | 26 | else |
diff --git a/.travis-upload.sh b/.travis-upload.sh index 1bec74b3d..2eeda4c50 100755 --- a/.travis-upload.sh +++ b/.travis-upload.sh | |||
| @@ -14,7 +14,6 @@ if [ "$TRAVIS_EVENT_TYPE" = "push" ]&&[ "$TRAVIS_BRANCH" = "master" ]; then | |||
| 14 | UPLOAD_DIR="/citra/nightly/osx-amd64" | 14 | UPLOAD_DIR="/citra/nightly/osx-amd64" |
| 15 | mkdir "$REV_NAME" | 15 | mkdir "$REV_NAME" |
| 16 | 16 | ||
| 17 | brew install lftp | ||
| 18 | cp build/src/citra/Release/citra "$REV_NAME" | 17 | cp build/src/citra/Release/citra "$REV_NAME" |
| 19 | cp -r build/src/citra_qt/Release/citra-qt.app "$REV_NAME" | 18 | cp -r build/src/citra_qt/Release/citra-qt.app "$REV_NAME" |
| 20 | 19 | ||
| @@ -122,5 +121,4 @@ EOL | |||
| 122 | 121 | ||
| 123 | ARCHIVE_NAME="${REV_NAME}.tar.xz" | 122 | ARCHIVE_NAME="${REV_NAME}.tar.xz" |
| 124 | tar -cJvf "$ARCHIVE_NAME" "$REV_NAME" | 123 | tar -cJvf "$ARCHIVE_NAME" "$REV_NAME" |
| 125 | lftp -c "open -u citra-builds,$BUILD_PASSWORD sftp://builds.citra-emu.org; set sftp:auto-confirm yes; put -O '$UPLOAD_DIR' '$ARCHIVE_NAME'" | ||
| 126 | fi | 124 | fi |
diff --git a/.travis.yml b/.travis.yml index ea99be2c4..a9e7aadd2 100644 --- a/.travis.yml +++ b/.travis.yml | |||
| @@ -25,7 +25,6 @@ addons: | |||
| 25 | - libqt5opengl5-dev | 25 | - libqt5opengl5-dev |
| 26 | - xorg-dev | 26 | - xorg-dev |
| 27 | - lib32stdc++6 # For CMake | 27 | - lib32stdc++6 # For CMake |
| 28 | - lftp # To upload builds | ||
| 29 | - clang-format-4.0 | 28 | - clang-format-4.0 |
| 30 | 29 | ||
| 31 | cache: | 30 | cache: |
diff --git a/CMakeLists.txt b/CMakeLists.txt index 56503f1ad..5c9b7f86a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -156,7 +156,7 @@ if (ENABLE_SDL2) | |||
| 156 | if (CITRA_USE_BUNDLED_SDL2) | 156 | if (CITRA_USE_BUNDLED_SDL2) |
| 157 | # Detect toolchain and platform | 157 | # Detect toolchain and platform |
| 158 | if (MSVC14 AND ARCHITECTURE_x86_64) | 158 | if (MSVC14 AND ARCHITECTURE_x86_64) |
| 159 | set(SDL2_VER "SDL2-2.0.4") | 159 | set(SDL2_VER "SDL2-2.0.5") |
| 160 | else() | 160 | else() |
| 161 | message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRA_USE_BUNDLED_SDL2 and provide your own.") | 161 | message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRA_USE_BUNDLED_SDL2 and provide your own.") |
| 162 | endif() | 162 | endif() |
| @@ -5,7 +5,7 @@ Citra Emulator | |||
| 5 | [](https://travis-ci.org/citra-emu/citra) | 5 | [](https://travis-ci.org/citra-emu/citra) |
| 6 | [](https://ci.appveyor.com/project/bunnei/citra) | 6 | [](https://ci.appveyor.com/project/bunnei/citra) |
| 7 | 7 | ||
| 8 | Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and OS X. Citra only emulates a subset of 3DS hardware, and therefore is generally only useful for running/debugging homebrew applications. At this time, Citra is even able to boot several commercial games! Most of these do not run to a playable state, but we are working every day to advance the project forward. | 8 | Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and macOS. Citra only emulates a subset of 3DS hardware, and therefore is generally only useful for running/debugging homebrew applications. At this time, Citra is even able to boot several commercial games! Most of these do not run to a playable state, but we are working every day to advance the project forward. |
| 9 | 9 | ||
| 10 | Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project. | 10 | Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project. |
| 11 | 11 | ||
| @@ -23,7 +23,7 @@ If you want to contribute please take a look at the [Contributor's Guide](CONTRI | |||
| 23 | 23 | ||
| 24 | * __Windows__: [Windows Build](https://github.com/citra-emu/citra/wiki/Building-For-Windows) | 24 | * __Windows__: [Windows Build](https://github.com/citra-emu/citra/wiki/Building-For-Windows) |
| 25 | * __Linux__: [Linux Build](https://github.com/citra-emu/citra/wiki/Building-For-Linux) | 25 | * __Linux__: [Linux Build](https://github.com/citra-emu/citra/wiki/Building-For-Linux) |
| 26 | * __OSX__: [OS X Build](https://github.com/citra-emu/citra/wiki/Building-For-OS-X) | 26 | * __macOS__: [macOS Build](https://github.com/citra-emu/citra/wiki/Building-for-macOS) |
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | ### Support | 29 | ### Support |
diff --git a/dist/citra.xml b/dist/citra.xml index bcb9acd87..6d47c8760 100644 --- a/dist/citra.xml +++ b/dist/citra.xml | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> | 2 | <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> |
| 3 | <mime-type type="application/x-ctr-3dsx"> | 3 | <mime-type type="application/x-ctr-3dsx"> |
| 4 | <comment>3DS homebrew executable</comment> | 4 | <comment>Nintendo 3DS homebrew executable</comment> |
| 5 | <comment xml:lang="fr">Exécutable 3DS homebrew</comment> | 5 | <comment xml:lang="fr">Exécutable non-officiel pour Nintendo 3DS </comment> |
| 6 | <acronym>3DSX</acronym> | 6 | <acronym>3DSX</acronym> |
| 7 | <icon name="citra"/> | 7 | <icon name="citra"/> |
| 8 | <glob pattern="*.3dsx"/> | 8 | <glob pattern="*.3dsx"/> |
| @@ -10,8 +10,8 @@ | |||
| 10 | </mime-type> | 10 | </mime-type> |
| 11 | 11 | ||
| 12 | <mime-type type="application/x-ctr-cci"> | 12 | <mime-type type="application/x-ctr-cci"> |
| 13 | <comment>3DS cartridge image</comment> | 13 | <comment>Nintendo 3DS cartridge image</comment> |
| 14 | <comment xml:lang="fr">Image de cartouche 3DS</comment> | 14 | <comment xml:lang="fr">Image de cartouche Nintendo 3DS</comment> |
| 15 | <acronym>CCI</acronym> | 15 | <acronym>CCI</acronym> |
| 16 | <expanded-acronym>CTR Cart Image</expanded-acronym> | 16 | <expanded-acronym>CTR Cart Image</expanded-acronym> |
| 17 | <icon name="citra"/> | 17 | <icon name="citra"/> |
| @@ -21,8 +21,8 @@ | |||
| 21 | </mime-type> | 21 | </mime-type> |
| 22 | 22 | ||
| 23 | <mime-type type="application/x-ctr-cxi"> | 23 | <mime-type type="application/x-ctr-cxi"> |
| 24 | <comment>3DS executable</comment> | 24 | <comment>Nintendo 3DS executable</comment> |
| 25 | <comment xml:lang="fr">Exécutable 3DS</comment> | 25 | <comment xml:lang="fr">Exécutable Nintendo 3DS</comment> |
| 26 | <acronym>CXI</acronym> | 26 | <acronym>CXI</acronym> |
| 27 | <expanded-acronym>CTR eXecutable Image</expanded-acronym> | 27 | <expanded-acronym>CTR eXecutable Image</expanded-acronym> |
| 28 | <icon name="citra"/> | 28 | <icon name="citra"/> |
| @@ -31,8 +31,8 @@ | |||
| 31 | </mime-type> | 31 | </mime-type> |
| 32 | 32 | ||
| 33 | <mime-type type="application/x-ctr-cia"> | 33 | <mime-type type="application/x-ctr-cia"> |
| 34 | <comment>3DS importable archive</comment> | 34 | <comment>Nintendo 3DS importable archive</comment> |
| 35 | <comment xml:lang="fr">Archive importable 3DS</comment> | 35 | <comment xml:lang="fr">Archive installable Nintendo 3DS</comment> |
| 36 | <acronym>CIA</acronym> | 36 | <acronym>CIA</acronym> |
| 37 | <expanded-acronym>CTR Importable Archive</expanded-acronym> | 37 | <expanded-acronym>CTR Importable Archive</expanded-acronym> |
| 38 | <icon name="citra"/> | 38 | <icon name="citra"/> |
| @@ -40,8 +40,8 @@ | |||
| 40 | </mime-type> | 40 | </mime-type> |
| 41 | 41 | ||
| 42 | <mime-type type="application/x-ctr-smdh"> | 42 | <mime-type type="application/x-ctr-smdh"> |
| 43 | <comment>3DS icon</comment> | 43 | <comment>Nintendo 3DS icon and metadata</comment> |
| 44 | <comment xml:lang="fr">Icône 3DS</comment> | 44 | <comment xml:lang="fr">Icône et métadonnées Nintendo 3DS</comment> |
| 45 | <acronym>SMDH</acronym> | 45 | <acronym>SMDH</acronym> |
| 46 | <expanded-acronym>System Menu Data Header</expanded-acronym> | 46 | <expanded-acronym>System Menu Data Header</expanded-acronym> |
| 47 | <glob pattern="*.smdh"/> | 47 | <glob pattern="*.smdh"/> |
| @@ -49,8 +49,8 @@ | |||
| 49 | </mime-type> | 49 | </mime-type> |
| 50 | 50 | ||
| 51 | <mime-type type="application/x-ctr-cbmd"> | 51 | <mime-type type="application/x-ctr-cbmd"> |
| 52 | <comment>3DS banner</comment> | 52 | <comment>Nintendo 3DS banner</comment> |
| 53 | <comment xml:lang="fr">Bannière 3DS</comment> | 53 | <comment xml:lang="fr">Bannière Nintendo 3DS</comment> |
| 54 | <acronym>CBMD</acronym> | 54 | <acronym>CBMD</acronym> |
| 55 | <expanded-acronym>CTR Banner Model Data</expanded-acronym> | 55 | <expanded-acronym>CTR Banner Model Data</expanded-acronym> |
| 56 | <glob pattern="*.cbmd"/> | 56 | <glob pattern="*.cbmd"/> |
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp index 75cc0d6dd..4b66cd826 100644 --- a/src/audio_core/sdl2_sink.cpp +++ b/src/audio_core/sdl2_sink.cpp | |||
| @@ -25,7 +25,7 @@ struct SDL2Sink::Impl { | |||
| 25 | 25 | ||
| 26 | SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) { | 26 | SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) { |
| 27 | if (SDL_Init(SDL_INIT_AUDIO) < 0) { | 27 | if (SDL_Init(SDL_INIT_AUDIO) < 0) { |
| 28 | LOG_CRITICAL(Audio_Sink, "SDL_Init(SDL_INIT_AUDIO) failed"); | 28 | LOG_CRITICAL(Audio_Sink, "SDL_Init(SDL_INIT_AUDIO) failed with: %s", SDL_GetError()); |
| 29 | impl->audio_device_id = 0; | 29 | impl->audio_device_id = 0; |
| 30 | return; | 30 | return; |
| 31 | } | 31 | } |
| @@ -45,7 +45,7 @@ SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) { | |||
| 45 | impl->audio_device_id = | 45 | impl->audio_device_id = |
| 46 | SDL_OpenAudioDevice(nullptr, false, &desired_audiospec, &obtained_audiospec, 0); | 46 | SDL_OpenAudioDevice(nullptr, false, &desired_audiospec, &obtained_audiospec, 0); |
| 47 | if (impl->audio_device_id <= 0) { | 47 | if (impl->audio_device_id <= 0) { |
| 48 | LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed"); | 48 | LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with: %s", SDL_GetError()); |
| 49 | return; | 49 | return; |
| 50 | } | 50 | } |
| 51 | 51 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index b4444c869..ca8a94ee9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -52,6 +52,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks(ARMul_State* interpeter_state) { | |||
| 52 | user_callbacks.MemoryWrite16 = &Memory::Write16; | 52 | user_callbacks.MemoryWrite16 = &Memory::Write16; |
| 53 | user_callbacks.MemoryWrite32 = &Memory::Write32; | 53 | user_callbacks.MemoryWrite32 = &Memory::Write32; |
| 54 | user_callbacks.MemoryWrite64 = &Memory::Write64; | 54 | user_callbacks.MemoryWrite64 = &Memory::Write64; |
| 55 | user_callbacks.page_table = Memory::GetCurrentPageTablePointers(); | ||
| 55 | return user_callbacks; | 56 | return user_callbacks; |
| 56 | } | 57 | } |
| 57 | 58 | ||
| @@ -130,9 +131,9 @@ MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); | |||
| 130 | void ARM_Dynarmic::ExecuteInstructions(int num_instructions) { | 131 | void ARM_Dynarmic::ExecuteInstructions(int num_instructions) { |
| 131 | MICROPROFILE_SCOPE(ARM_Jit); | 132 | MICROPROFILE_SCOPE(ARM_Jit); |
| 132 | 133 | ||
| 133 | jit->Run(static_cast<unsigned>(num_instructions)); | 134 | unsigned ticks_executed = jit->Run(static_cast<unsigned>(num_instructions)); |
| 134 | 135 | ||
| 135 | AddTicks(num_instructions); | 136 | AddTicks(ticks_executed); |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) { | 139 | void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) { |
diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index 14964427b..e1379ac4d 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp | |||
| @@ -10,7 +10,7 @@ namespace HLE { | |||
| 10 | namespace Applets { | 10 | namespace Applets { |
| 11 | 11 | ||
| 12 | ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | 12 | ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { |
| 13 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) { | 13 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |
| 14 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | 14 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |
| 15 | UNIMPLEMENTED(); | 15 | UNIMPLEMENTED(); |
| 16 | // TODO(Subv): Find the right error code | 16 | // TODO(Subv): Find the right error code |
| @@ -36,7 +36,7 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param | |||
| 36 | 36 | ||
| 37 | // Send the response message with the newly created SharedMemory | 37 | // Send the response message with the newly created SharedMemory |
| 38 | Service::APT::MessageParameter result; | 38 | Service::APT::MessageParameter result; |
| 39 | result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished); | 39 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); |
| 40 | result.buffer.clear(); | 40 | result.buffer.clear(); |
| 41 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | 41 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
| 42 | result.sender_id = static_cast<u32>(id); | 42 | result.sender_id = static_cast<u32>(id); |
| @@ -57,7 +57,7 @@ ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parame | |||
| 57 | Service::APT::MessageParameter message; | 57 | Service::APT::MessageParameter message; |
| 58 | message.buffer.resize(parameter.buffer.size()); | 58 | message.buffer.resize(parameter.buffer.size()); |
| 59 | std::fill(message.buffer.begin(), message.buffer.end(), 0); | 59 | std::fill(message.buffer.begin(), message.buffer.end(), 0); |
| 60 | message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed); | 60 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |
| 61 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | 61 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
| 62 | message.sender_id = static_cast<u32>(id); | 62 | message.sender_id = static_cast<u32>(id); |
| 63 | Service::APT::SendParameter(message); | 63 | Service::APT::SendParameter(message); |
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index 53a8683a4..3455b9201 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp | |||
| @@ -19,7 +19,7 @@ namespace HLE { | |||
| 19 | namespace Applets { | 19 | namespace Applets { |
| 20 | 20 | ||
| 21 | ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | 21 | ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { |
| 22 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) { | 22 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |
| 23 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | 23 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |
| 24 | UNIMPLEMENTED(); | 24 | UNIMPLEMENTED(); |
| 25 | // TODO(Subv): Find the right error code | 25 | // TODO(Subv): Find the right error code |
| @@ -44,7 +44,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p | |||
| 44 | 44 | ||
| 45 | // Send the response message with the newly created SharedMemory | 45 | // Send the response message with the newly created SharedMemory |
| 46 | Service::APT::MessageParameter result; | 46 | Service::APT::MessageParameter result; |
| 47 | result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished); | 47 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); |
| 48 | result.buffer.clear(); | 48 | result.buffer.clear(); |
| 49 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | 49 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
| 50 | result.sender_id = static_cast<u32>(id); | 50 | result.sender_id = static_cast<u32>(id); |
| @@ -73,7 +73,7 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa | |||
| 73 | Service::APT::MessageParameter message; | 73 | Service::APT::MessageParameter message; |
| 74 | message.buffer.resize(sizeof(MiiResult)); | 74 | message.buffer.resize(sizeof(MiiResult)); |
| 75 | std::memcpy(message.buffer.data(), &result, message.buffer.size()); | 75 | std::memcpy(message.buffer.data(), &result, message.buffer.size()); |
| 76 | message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed); | 76 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |
| 77 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | 77 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
| 78 | message.sender_id = static_cast<u32>(id); | 78 | message.sender_id = static_cast<u32>(id); |
| 79 | Service::APT::SendParameter(message); | 79 | Service::APT::SendParameter(message); |
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index 06ddf538b..1e21337f5 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp | |||
| @@ -22,7 +22,7 @@ namespace HLE { | |||
| 22 | namespace Applets { | 22 | namespace Applets { |
| 23 | 23 | ||
| 24 | ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { | 24 | ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { |
| 25 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) { | 25 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { |
| 26 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | 26 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |
| 27 | UNIMPLEMENTED(); | 27 | UNIMPLEMENTED(); |
| 28 | // TODO(Subv): Find the right error code | 28 | // TODO(Subv): Find the right error code |
| @@ -47,7 +47,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con | |||
| 47 | 47 | ||
| 48 | // Send the response message with the newly created SharedMemory | 48 | // Send the response message with the newly created SharedMemory |
| 49 | Service::APT::MessageParameter result; | 49 | Service::APT::MessageParameter result; |
| 50 | result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished); | 50 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); |
| 51 | result.buffer.clear(); | 51 | result.buffer.clear(); |
| 52 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | 52 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
| 53 | result.sender_id = static_cast<u32>(id); | 53 | result.sender_id = static_cast<u32>(id); |
| @@ -108,7 +108,7 @@ void SoftwareKeyboard::Finalize() { | |||
| 108 | Service::APT::MessageParameter message; | 108 | Service::APT::MessageParameter message; |
| 109 | message.buffer.resize(sizeof(SoftwareKeyboardConfig)); | 109 | message.buffer.resize(sizeof(SoftwareKeyboardConfig)); |
| 110 | std::memcpy(message.buffer.data(), &config, message.buffer.size()); | 110 | std::memcpy(message.buffer.data(), &config, message.buffer.size()); |
| 111 | message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed); | 111 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); |
| 112 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | 112 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
| 113 | message.sender_id = static_cast<u32>(id); | 113 | message.sender_id = static_cast<u32>(id); |
| 114 | Service::APT::SendParameter(message); | 114 | Service::APT::SendParameter(message); |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 1489c7002..3e116e3df 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -22,6 +22,11 @@ SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { | |||
| 22 | evt->reset_type = reset_type; | 22 | evt->reset_type = reset_type; |
| 23 | evt->name = std::move(name); | 23 | evt->name = std::move(name); |
| 24 | 24 | ||
| 25 | if (reset_type == ResetType::Pulse) { | ||
| 26 | LOG_ERROR(Kernel, "Unimplemented event reset type Pulse"); | ||
| 27 | UNIMPLEMENTED(); | ||
| 28 | } | ||
| 29 | |||
| 25 | return evt; | 30 | return evt; |
| 26 | } | 31 | } |
| 27 | 32 | ||
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index a9f98223c..eac181f4e 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -31,6 +31,11 @@ SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) { | |||
| 31 | timer->interval_delay = 0; | 31 | timer->interval_delay = 0; |
| 32 | timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom(); | 32 | timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom(); |
| 33 | 33 | ||
| 34 | if (reset_type == ResetType::Pulse) { | ||
| 35 | LOG_ERROR(Kernel, "Unimplemented timer reset type Pulse"); | ||
| 36 | UNIMPLEMENTED(); | ||
| 37 | } | ||
| 38 | |||
| 34 | return timer; | 39 | return timer; |
| 35 | } | 40 | } |
| 36 | 41 | ||
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index c4bd65986..31e5e07b2 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -396,6 +396,15 @@ void StartLibraryApplet(Service::Interface* self) { | |||
| 396 | cmd_buff[1] = applet->Start(parameter).raw; | 396 | cmd_buff[1] = applet->Start(parameter).raw; |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | void CancelLibraryApplet(Service::Interface* self) { | ||
| 400 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 401 | u32 exiting = cmd_buff[1] & 0xFF; | ||
| 402 | |||
| 403 | cmd_buff[1] = 1; // TODO: Find the return code meaning | ||
| 404 | |||
| 405 | LOG_WARNING(Service_APT, "(STUBBED) called exiting=%u", exiting); | ||
| 406 | } | ||
| 407 | |||
| 399 | void SetScreenCapPostPermission(Service::Interface* self) { | 408 | void SetScreenCapPostPermission(Service::Interface* self) { |
| 400 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 409 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 401 | 410 | ||
| @@ -523,7 +532,7 @@ void Init() { | |||
| 523 | notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); | 532 | notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); |
| 524 | parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start"); | 533 | parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start"); |
| 525 | 534 | ||
| 526 | next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted); | 535 | next_parameter.signal = static_cast<u32>(SignalType::Wakeup); |
| 527 | next_parameter.destination_id = 0x300; | 536 | next_parameter.destination_id = 0x300; |
| 528 | } | 537 | } |
| 529 | 538 | ||
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index a118cda1f..44dbd8757 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h | |||
| @@ -46,12 +46,23 @@ static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has i | |||
| 46 | /// Signals used by APT functions | 46 | /// Signals used by APT functions |
| 47 | enum class SignalType : u32 { | 47 | enum class SignalType : u32 { |
| 48 | None = 0x0, | 48 | None = 0x0, |
| 49 | AppJustStarted = 0x1, | 49 | Wakeup = 0x1, |
| 50 | LibAppJustStarted = 0x2, | 50 | Request = 0x2, |
| 51 | LibAppFinished = 0x3, | 51 | Response = 0x3, |
| 52 | LibAppClosed = 0xA, | 52 | Exit = 0x4, |
| 53 | ReturningToApp = 0xB, | 53 | Message = 0x5, |
| 54 | ExitingApp = 0xC, | 54 | HomeButtonSingle = 0x6, |
| 55 | HomeButtonDouble = 0x7, | ||
| 56 | DspSleep = 0x8, | ||
| 57 | DspWakeup = 0x9, | ||
| 58 | WakeupByExit = 0xA, | ||
| 59 | WakeupByPause = 0xB, | ||
| 60 | WakeupByCancel = 0xC, | ||
| 61 | WakeupByCancelAll = 0xD, | ||
| 62 | WakeupByPowerButtonClick = 0xE, | ||
| 63 | WakeupToJumpHome = 0xF, | ||
| 64 | RequestForSysApplet = 0x10, | ||
| 65 | WakeupToLaunchApplication = 0x11, | ||
| 55 | }; | 66 | }; |
| 56 | 67 | ||
| 57 | /// App Id's used by APT functions | 68 | /// App Id's used by APT functions |
| @@ -381,6 +392,17 @@ void PreloadLibraryApplet(Service::Interface* self); | |||
| 381 | void StartLibraryApplet(Service::Interface* self); | 392 | void StartLibraryApplet(Service::Interface* self); |
| 382 | 393 | ||
| 383 | /** | 394 | /** |
| 395 | * APT::CancelLibraryApplet service function | ||
| 396 | * Inputs: | ||
| 397 | * 0 : Command header [0x003B0040] | ||
| 398 | * 1 : u8, Application exiting (0 = not exiting, 1 = exiting) | ||
| 399 | * Outputs: | ||
| 400 | * 0 : Header code | ||
| 401 | * 1 : Result code | ||
| 402 | */ | ||
| 403 | void CancelLibraryApplet(Service::Interface* self); | ||
| 404 | |||
| 405 | /** | ||
| 384 | * APT::GetStartupArgument service function | 406 | * APT::GetStartupArgument service function |
| 385 | * Inputs: | 407 | * Inputs: |
| 386 | * 1 : Parameter Size (capped to 0x300) | 408 | * 1 : Parameter Size (capped to 0x300) |
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index f27ad91b7..a7a0c8a41 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp | |||
| @@ -25,7 +25,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 25 | {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, | 25 | {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, |
| 26 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, | 26 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, |
| 27 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, | 27 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, |
| 28 | {0x003B0040, nullptr, "CancelLibraryApplet?"}, | 28 | {0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"}, |
| 29 | {0x003E0080, nullptr, "ReplySleepQuery"}, | 29 | {0x003E0080, nullptr, "ReplySleepQuery"}, |
| 30 | {0x00430040, NotifyToWait, "NotifyToWait?"}, | 30 | {0x00430040, NotifyToWait, "NotifyToWait?"}, |
| 31 | {0x00440000, GetSharedFont, "GetSharedFont?"}, | 31 | {0x00440000, GetSharedFont, "GetSharedFont?"}, |
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index d6ad42e21..a731c39f6 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp | |||
| @@ -67,7 +67,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 67 | {0x00380040, nullptr, "PreloadResidentApplet"}, | 67 | {0x00380040, nullptr, "PreloadResidentApplet"}, |
| 68 | {0x00390040, nullptr, "PrepareToStartResidentApplet"}, | 68 | {0x00390040, nullptr, "PrepareToStartResidentApplet"}, |
| 69 | {0x003A0044, nullptr, "StartResidentApplet"}, | 69 | {0x003A0044, nullptr, "StartResidentApplet"}, |
| 70 | {0x003B0040, nullptr, "CancelLibraryApplet"}, | 70 | {0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"}, |
| 71 | {0x003C0042, nullptr, "SendDspSleep"}, | 71 | {0x003C0042, nullptr, "SendDspSleep"}, |
| 72 | {0x003D0042, nullptr, "SendDspWakeUp"}, | 72 | {0x003D0042, nullptr, "SendDspWakeUp"}, |
| 73 | {0x003E0080, nullptr, "ReplySleepQuery"}, | 73 | {0x003E0080, nullptr, "ReplySleepQuery"}, |
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 24eee6903..d3d0f3b55 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp | |||
| @@ -45,7 +45,8 @@ static_assert(sizeof(SaveFileConfig) == 0x455C, | |||
| 45 | enum ConfigBlockID { | 45 | enum ConfigBlockID { |
| 46 | StereoCameraSettingsBlockID = 0x00050005, | 46 | StereoCameraSettingsBlockID = 0x00050005, |
| 47 | SoundOutputModeBlockID = 0x00070001, | 47 | SoundOutputModeBlockID = 0x00070001, |
| 48 | ConsoleUniqueIDBlockID = 0x00090001, | 48 | ConsoleUniqueID1BlockID = 0x00090000, |
| 49 | ConsoleUniqueID2BlockID = 0x00090001, | ||
| 49 | UsernameBlockID = 0x000A0000, | 50 | UsernameBlockID = 0x000A0000, |
| 50 | BirthdayBlockID = 0x000A0001, | 51 | BirthdayBlockID = 0x000A0001, |
| 51 | LanguageBlockID = 0x000A0002, | 52 | LanguageBlockID = 0x000A0002, |
| @@ -409,7 +410,12 @@ ResultCode FormatConfig() { | |||
| 409 | if (!res.IsSuccess()) | 410 | if (!res.IsSuccess()) |
| 410 | return res; | 411 | return res; |
| 411 | 412 | ||
| 412 | res = CreateConfigInfoBlk(ConsoleUniqueIDBlockID, sizeof(CONSOLE_UNIQUE_ID), 0xE, | 413 | res = CreateConfigInfoBlk(ConsoleUniqueID1BlockID, sizeof(CONSOLE_UNIQUE_ID), 0xE, |
| 414 | &CONSOLE_UNIQUE_ID); | ||
| 415 | if (!res.IsSuccess()) | ||
| 416 | return res; | ||
| 417 | |||
| 418 | res = CreateConfigInfoBlk(ConsoleUniqueID2BlockID, sizeof(CONSOLE_UNIQUE_ID), 0xE, | ||
| 413 | &CONSOLE_UNIQUE_ID); | 419 | &CONSOLE_UNIQUE_ID); |
| 414 | if (!res.IsSuccess()) | 420 | if (!res.IsSuccess()) |
| 415 | return res; | 421 | return res; |
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 3ca4f98de..9905757c7 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp | |||
| @@ -2,9 +2,15 @@ | |||
| 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 <array> | ||
| 6 | #include <chrono> | ||
| 7 | #include <iomanip> | ||
| 8 | #include <sstream> | ||
| 9 | |||
| 5 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 6 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 7 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "core/hle/result.h" | ||
| 8 | #include "core/hle/service/err_f.h" | 14 | #include "core/hle/service/err_f.h" |
| 9 | 15 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -12,12 +18,45 @@ | |||
| 12 | 18 | ||
| 13 | namespace ERR_F { | 19 | namespace ERR_F { |
| 14 | 20 | ||
| 15 | enum { | 21 | enum class FatalErrType : u32 { |
| 16 | ErrSpecifier0 = 0, | 22 | Generic = 0, |
| 17 | ErrSpecifier1 = 1, | 23 | Corrupted = 1, |
| 18 | ErrSpecifier3 = 3, | 24 | CardRemoved = 2, |
| 19 | ErrSpecifier4 = 4, | 25 | Exception = 3, |
| 26 | ResultFailure = 4, | ||
| 27 | Logged = 5, | ||
| 28 | }; | ||
| 29 | |||
| 30 | enum class ExceptionType : u32 { | ||
| 31 | PrefetchAbort = 0, | ||
| 32 | DataAbort = 1, | ||
| 33 | Undefined = 2, | ||
| 34 | VectorFP = 3, | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct ExceptionInfo { | ||
| 38 | u8 exception_type; | ||
| 39 | INSERT_PADDING_BYTES(3); | ||
| 40 | u32 sr; | ||
| 41 | u32 ar; | ||
| 42 | u32 fpexc; | ||
| 43 | u32 fpinst; | ||
| 44 | u32 fpinst2; | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(ExceptionInfo) == 0x18, "ExceptionInfo struct has incorrect size"); | ||
| 47 | |||
| 48 | struct ExceptionContext final { | ||
| 49 | std::array<u32, 16> arm_regs; | ||
| 50 | u32 cpsr; | ||
| 20 | }; | 51 | }; |
| 52 | static_assert(sizeof(ExceptionContext) == 0x44, "ExceptionContext struct has incorrect size"); | ||
| 53 | |||
| 54 | struct ExceptionData { | ||
| 55 | ExceptionInfo exception_info; | ||
| 56 | ExceptionContext exception_context; | ||
| 57 | INSERT_PADDING_WORDS(1); | ||
| 58 | }; | ||
| 59 | static_assert(sizeof(ExceptionData) == 0x60, "ExceptionData struct has incorrect size"); | ||
| 21 | 60 | ||
| 22 | // This is used instead of ResultCode from result.h | 61 | // This is used instead of ResultCode from result.h |
| 23 | // because we can't have non-trivial data members in unions. | 62 | // because we can't have non-trivial data members in unions. |
| @@ -30,150 +69,191 @@ union RSL { | |||
| 30 | BitField<27, 5, u32> level; | 69 | BitField<27, 5, u32> level; |
| 31 | }; | 70 | }; |
| 32 | 71 | ||
| 33 | union ErrInfo { | 72 | struct ErrInfo { |
| 34 | u8 specifier; | 73 | struct ErrInfoCommon { |
| 35 | 74 | u8 specifier; // 0x0 | |
| 36 | struct { | 75 | u8 rev_high; // 0x1 |
| 37 | u8 specifier; // 0x0 | 76 | u16 rev_low; // 0x2 |
| 38 | u8 rev_high; // 0x1 | 77 | RSL result_code; // 0x4 |
| 39 | u16 rev_low; // 0x2 | 78 | u32 pc_address; // 0x8 |
| 40 | RSL result_code; // 0x4 | 79 | u32 pid; // 0xC |
| 41 | u32 address; // 0x8 | 80 | u32 title_id_low; // 0x10 |
| 42 | INSERT_PADDING_BYTES(4); // 0xC | 81 | u32 title_id_high; // 0x14 |
| 43 | u32 pid_low; // 0x10 | 82 | u32 app_title_id_low; // 0x18 |
| 44 | u32 pid_high; // 0x14 | 83 | u32 app_title_id_high; // 0x1C |
| 45 | u32 aid_low; // 0x18 | 84 | } errinfo_common; |
| 46 | u32 aid_high; // 0x1C | 85 | static_assert(sizeof(ErrInfoCommon) == 0x20, "ErrInfoCommon struct has incorrect size"); |
| 47 | } errtype1; | 86 | |
| 48 | 87 | union { | |
| 49 | struct { | 88 | struct { |
| 50 | u8 specifier; // 0x0 | 89 | char data[0x60]; // 0x20 |
| 51 | u8 rev_high; // 0x1 | 90 | } generic; |
| 52 | u16 rev_low; // 0x2 | 91 | |
| 53 | INSERT_PADDING_BYTES(0xC); // 0x4 | 92 | struct { |
| 54 | u32 pid_low; // 0x10 | 93 | ExceptionData exception_data; // 0x20 |
| 55 | u32 pid_high; // 0x14 | 94 | } exception; |
| 56 | u32 aid_low; // 0x18 | 95 | |
| 57 | u32 aid_high; // 0x1C | 96 | struct { |
| 58 | u8 error_type; // 0x20 | 97 | char message[0x60]; // 0x20 |
| 59 | INSERT_PADDING_BYTES(3); // 0x21 | 98 | } result_failure; |
| 60 | u32 fault_status_reg; // 0x24 | 99 | }; |
| 61 | u32 fault_addr; // 0x28 | ||
| 62 | u32 fpexc; // 0x2C | ||
| 63 | u32 finst; // 0x30 | ||
| 64 | u32 finst2; // 0x34 | ||
| 65 | INSERT_PADDING_BYTES(0x34); // 0x38 | ||
| 66 | u32 sp; // 0x6C | ||
| 67 | u32 pc; // 0x70 | ||
| 68 | u32 lr; // 0x74 | ||
| 69 | u32 cpsr; // 0x78 | ||
| 70 | } errtype3; | ||
| 71 | |||
| 72 | struct { | ||
| 73 | u8 specifier; // 0x0 | ||
| 74 | u8 rev_high; // 0x1 | ||
| 75 | u16 rev_low; // 0x2 | ||
| 76 | RSL result_code; // 0x4 | ||
| 77 | INSERT_PADDING_BYTES(8); // 0x8 | ||
| 78 | u32 pid_low; // 0x10 | ||
| 79 | u32 pid_high; // 0x14 | ||
| 80 | u32 aid_low; // 0x18 | ||
| 81 | u32 aid_high; // 0x1C | ||
| 82 | char debug_string1[0x2E]; // 0x20 | ||
| 83 | char debug_string2[0x2E]; // 0x4E | ||
| 84 | } errtype4; | ||
| 85 | }; | 100 | }; |
| 86 | 101 | ||
| 87 | enum { PrefetchAbort = 0, DataAbort = 1, UndefInstr = 2, VectorFP = 3 }; | 102 | static std::string GetErrType(u8 type_code) { |
| 103 | switch (static_cast<FatalErrType>(type_code)) { | ||
| 104 | case FatalErrType::Generic: | ||
| 105 | return "Generic"; | ||
| 106 | case FatalErrType::Corrupted: | ||
| 107 | return "Corrupted"; | ||
| 108 | case FatalErrType::CardRemoved: | ||
| 109 | return "CardRemoved"; | ||
| 110 | case FatalErrType::Exception: | ||
| 111 | return "Exception"; | ||
| 112 | case FatalErrType::ResultFailure: | ||
| 113 | return "ResultFailure"; | ||
| 114 | case FatalErrType::Logged: | ||
| 115 | return "Logged"; | ||
| 116 | default: | ||
| 117 | return "Unknown Error Type"; | ||
| 118 | } | ||
| 119 | } | ||
| 88 | 120 | ||
| 89 | static std::string GetErrInfo3Type(u8 type_code) { | 121 | static std::string GetExceptionType(u8 type_code) { |
| 90 | switch (type_code) { | 122 | switch (static_cast<ExceptionType>(type_code)) { |
| 91 | case PrefetchAbort: | 123 | case ExceptionType::PrefetchAbort: |
| 92 | return "Prefetch Abort"; | 124 | return "Prefetch Abort"; |
| 93 | case DataAbort: | 125 | case ExceptionType::DataAbort: |
| 94 | return "Data Abort"; | 126 | return "Data Abort"; |
| 95 | case UndefInstr: | 127 | case ExceptionType::Undefined: |
| 96 | return "Undefined Instruction"; | 128 | return "Undefined Exception"; |
| 97 | case VectorFP: | 129 | case ExceptionType::VectorFP: |
| 98 | return "Vector Floating Point"; | 130 | return "Vector Floating Point Exception"; |
| 99 | default: | 131 | default: |
| 100 | return "unknown"; | 132 | return "Unknown Exception Type"; |
| 101 | } | 133 | } |
| 102 | } | 134 | } |
| 103 | 135 | ||
| 136 | static std::string GetCurrentSystemTime() { | ||
| 137 | auto now = std::chrono::system_clock::now(); | ||
| 138 | auto time = std::chrono::system_clock::to_time_t(now); | ||
| 139 | |||
| 140 | std::stringstream time_stream; | ||
| 141 | time_stream << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S"); | ||
| 142 | return time_stream.str(); | ||
| 143 | } | ||
| 144 | |||
| 145 | static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) { | ||
| 146 | LOG_CRITICAL(Service_ERR, "PID: 0x%08X", errinfo_common.pid); | ||
| 147 | LOG_CRITICAL(Service_ERR, "REV: 0x%08X_0x%08X", errinfo_common.rev_high, | ||
| 148 | errinfo_common.rev_low); | ||
| 149 | LOG_CRITICAL(Service_ERR, "TID: 0x%08X_0x%08X", errinfo_common.title_id_high, | ||
| 150 | errinfo_common.title_id_low); | ||
| 151 | LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errinfo_common.app_title_id_high, | ||
| 152 | errinfo_common.app_title_id_low); | ||
| 153 | LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errinfo_common.pc_address); | ||
| 154 | |||
| 155 | LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errinfo_common.result_code.raw); | ||
| 156 | LOG_CRITICAL(Service_ERR, " Level: %u", errinfo_common.result_code.level.Value()); | ||
| 157 | LOG_CRITICAL(Service_ERR, " Summary: %u", errinfo_common.result_code.summary.Value()); | ||
| 158 | LOG_CRITICAL(Service_ERR, " Module: %u", errinfo_common.result_code.module.Value()); | ||
| 159 | LOG_CRITICAL(Service_ERR, " Desc: %u", errinfo_common.result_code.description.Value()); | ||
| 160 | } | ||
| 161 | |||
| 162 | /* ThrowFatalError function | ||
| 163 | * Inputs: | ||
| 164 | * 0 : Header code [0x00010800] | ||
| 165 | * 1-32 : FatalErrInfo | ||
| 166 | * Outputs: | ||
| 167 | * 0 : Header code | ||
| 168 | * 1 : Result code | ||
| 169 | */ | ||
| 104 | static void ThrowFatalError(Service::Interface* self) { | 170 | static void ThrowFatalError(Service::Interface* self) { |
| 105 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 171 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 106 | 172 | ||
| 107 | LOG_CRITICAL(Service_ERR, "Fatal error!"); | 173 | LOG_CRITICAL(Service_ERR, "Fatal error"); |
| 108 | const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); | 174 | const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); |
| 175 | LOG_CRITICAL(Service_ERR, "Fatal error type: %s", | ||
| 176 | GetErrType(errinfo->errinfo_common.specifier).c_str()); | ||
| 109 | 177 | ||
| 110 | switch (errinfo->specifier) { | 178 | // Generic Info |
| 111 | case ErrSpecifier0: | 179 | LogGenericInfo(errinfo->errinfo_common); |
| 112 | case ErrSpecifier1: { | 180 | |
| 113 | const auto& errtype = errinfo->errtype1; | 181 | switch (static_cast<FatalErrType>(errinfo->errinfo_common.specifier)) { |
| 114 | LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); | 182 | case FatalErrType::Generic: |
| 115 | LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); | 183 | case FatalErrType::Corrupted: |
| 116 | LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); | 184 | case FatalErrType::CardRemoved: |
| 117 | LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errtype.address); | 185 | case FatalErrType::Logged: { |
| 118 | 186 | LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | |
| 119 | LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); | ||
| 120 | LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value()); | ||
| 121 | LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value()); | ||
| 122 | LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value()); | ||
| 123 | LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value()); | ||
| 124 | break; | 187 | break; |
| 125 | } | 188 | } |
| 189 | case FatalErrType::Exception: { | ||
| 190 | const auto& errtype = errinfo->exception; | ||
| 191 | |||
| 192 | // Register Info | ||
| 193 | LOG_CRITICAL(Service_ERR, "ARM Registers:"); | ||
| 194 | for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size(); | ||
| 195 | ++index) { | ||
| 196 | if (index < 13) { | ||
| 197 | LOG_DEBUG(Service_ERR, "r%u=0x%08X", index, | ||
| 198 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 199 | } else if (index == 13) { | ||
| 200 | LOG_CRITICAL(Service_ERR, "SP=0x%08X", | ||
| 201 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 202 | } else if (index == 14) { | ||
| 203 | LOG_CRITICAL(Service_ERR, "LR=0x%08X", | ||
| 204 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 205 | } else if (index == 15) { | ||
| 206 | LOG_CRITICAL(Service_ERR, "PC=0x%08X", | ||
| 207 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | LOG_CRITICAL(Service_ERR, "CPSR=0x%08X", errtype.exception_data.exception_context.cpsr); | ||
| 126 | 211 | ||
| 127 | case ErrSpecifier3: { | 212 | // Exception Info |
| 128 | const auto& errtype = errinfo->errtype3; | 213 | LOG_CRITICAL( |
| 129 | LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); | 214 | Service_ERR, "EXCEPTION TYPE: %s", |
| 130 | LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); | 215 | GetExceptionType(errtype.exception_data.exception_info.exception_type).c_str()); |
| 131 | LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); | 216 | switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) { |
| 132 | LOG_CRITICAL(Service_ERR, "TYPE: %s", GetErrInfo3Type(errtype.error_type).c_str()); | 217 | case ExceptionType::PrefetchAbort: |
| 133 | 218 | LOG_CRITICAL(Service_ERR, "IFSR: 0x%08X", errtype.exception_data.exception_info.sr); | |
| 134 | LOG_CRITICAL(Service_ERR, "PC: 0x%08X", errtype.pc); | 219 | LOG_CRITICAL(Service_ERR, "r15: 0x%08X", errtype.exception_data.exception_info.ar); |
| 135 | LOG_CRITICAL(Service_ERR, "LR: 0x%08X", errtype.lr); | 220 | case ExceptionType::DataAbort: |
| 136 | LOG_CRITICAL(Service_ERR, "SP: 0x%08X", errtype.sp); | 221 | LOG_CRITICAL(Service_ERR, "DFSR: 0x%08X", errtype.exception_data.exception_info.sr); |
| 137 | LOG_CRITICAL(Service_ERR, "CPSR: 0x%08X", errtype.cpsr); | 222 | LOG_CRITICAL(Service_ERR, "DFAR: 0x%08X", errtype.exception_data.exception_info.ar); |
| 138 | |||
| 139 | switch (errtype.error_type) { | ||
| 140 | case PrefetchAbort: | ||
| 141 | case DataAbort: | ||
| 142 | LOG_CRITICAL(Service_ERR, "Fault Address: 0x%08X", errtype.fault_addr); | ||
| 143 | LOG_CRITICAL(Service_ERR, "Fault Status Register: 0x%08X", errtype.fault_status_reg); | ||
| 144 | break; | 223 | break; |
| 145 | case VectorFP: | 224 | case ExceptionType::VectorFP: |
| 146 | LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", errtype.fpexc); | 225 | LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", |
| 147 | LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", errtype.finst); | 226 | errtype.exception_data.exception_info.fpinst); |
| 148 | LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", errtype.finst2); | 227 | LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", |
| 228 | errtype.exception_data.exception_info.fpinst); | ||
| 229 | LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", | ||
| 230 | errtype.exception_data.exception_info.fpinst2); | ||
| 149 | break; | 231 | break; |
| 150 | } | 232 | } |
| 233 | LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||
| 151 | break; | 234 | break; |
| 152 | } | 235 | } |
| 153 | 236 | ||
| 154 | case ErrSpecifier4: { | 237 | case FatalErrType::ResultFailure: { |
| 155 | const auto& errtype = errinfo->errtype4; | 238 | const auto& errtype = errinfo->result_failure; |
| 156 | LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); | ||
| 157 | LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); | ||
| 158 | LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); | ||
| 159 | 239 | ||
| 160 | LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); | 240 | // Failure Message |
| 161 | LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value()); | 241 | LOG_CRITICAL(Service_ERR, "Failure Message: %s", errtype.message); |
| 162 | LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value()); | 242 | LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); |
| 163 | LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value()); | ||
| 164 | LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value()); | ||
| 165 | |||
| 166 | LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string1); | ||
| 167 | LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string2); | ||
| 168 | break; | 243 | break; |
| 169 | } | 244 | } |
| 170 | } | ||
| 171 | 245 | ||
| 172 | cmd_buff[1] = 0; // No error | 246 | } // switch FatalErrType |
| 247 | |||
| 248 | cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); | ||
| 249 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 173 | } | 250 | } |
| 174 | 251 | ||
| 175 | const Interface::FunctionInfo FunctionTable[] = { | 252 | const Interface::FunctionInfo FunctionTable[] = { |
| 253 | // clang-format off | ||
| 176 | {0x00010800, ThrowFatalError, "ThrowFatalError"}, | 254 | {0x00010800, ThrowFatalError, "ThrowFatalError"}, |
| 255 | {0x00020042, nullptr, "SetUserString"}, | ||
| 256 | // clang-format on | ||
| 177 | }; | 257 | }; |
| 178 | 258 | ||
| 179 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 259 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 64c388374..65e4bba85 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -45,13 +45,11 @@ struct SpecialRegion { | |||
| 45 | * requires an indexed fetch and a check for NULL. | 45 | * requires an indexed fetch and a check for NULL. |
| 46 | */ | 46 | */ |
| 47 | struct PageTable { | 47 | struct PageTable { |
| 48 | static const size_t NUM_ENTRIES = 1 << (32 - PAGE_BITS); | ||
| 49 | |||
| 50 | /** | 48 | /** |
| 51 | * Array of memory pointers backing each page. An entry can only be non-null if the | 49 | * Array of memory pointers backing each page. An entry can only be non-null if the |
| 52 | * corresponding entry in the `attributes` array is of type `Memory`. | 50 | * corresponding entry in the `attributes` array is of type `Memory`. |
| 53 | */ | 51 | */ |
| 54 | std::array<u8*, NUM_ENTRIES> pointers; | 52 | std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers; |
| 55 | 53 | ||
| 56 | /** | 54 | /** |
| 57 | * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of | 55 | * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of |
| @@ -63,13 +61,13 @@ struct PageTable { | |||
| 63 | * Array of fine grained page attributes. If it is set to any value other than `Memory`, then | 61 | * Array of fine grained page attributes. If it is set to any value other than `Memory`, then |
| 64 | * the corresponding entry in `pointers` MUST be set to null. | 62 | * the corresponding entry in `pointers` MUST be set to null. |
| 65 | */ | 63 | */ |
| 66 | std::array<PageType, NUM_ENTRIES> attributes; | 64 | std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; |
| 67 | 65 | ||
| 68 | /** | 66 | /** |
| 69 | * Indicates the number of externally cached resources touching a page that should be | 67 | * Indicates the number of externally cached resources touching a page that should be |
| 70 | * flushed before the memory is accessed | 68 | * flushed before the memory is accessed |
| 71 | */ | 69 | */ |
| 72 | std::array<u8, NUM_ENTRIES> cached_res_count; | 70 | std::array<u8, PAGE_TABLE_NUM_ENTRIES> cached_res_count; |
| 73 | }; | 71 | }; |
| 74 | 72 | ||
| 75 | /// Singular page table used for the singleton process | 73 | /// Singular page table used for the singleton process |
| @@ -77,6 +75,10 @@ static PageTable main_page_table; | |||
| 77 | /// Currently active page table | 75 | /// Currently active page table |
| 78 | static PageTable* current_page_table = &main_page_table; | 76 | static PageTable* current_page_table = &main_page_table; |
| 79 | 77 | ||
| 78 | std::array<u8*, PAGE_TABLE_NUM_ENTRIES>* GetCurrentPageTablePointers() { | ||
| 79 | return ¤t_page_table->pointers; | ||
| 80 | } | ||
| 81 | |||
| 80 | static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | 82 | static void MapPages(u32 base, u32 size, u8* memory, PageType type) { |
| 81 | LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, | 83 | LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, |
| 82 | (base + size) * PAGE_SIZE); | 84 | (base + size) * PAGE_SIZE); |
| @@ -84,7 +86,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | |||
| 84 | u32 end = base + size; | 86 | u32 end = base + size; |
| 85 | 87 | ||
| 86 | while (base != end) { | 88 | while (base != end) { |
| 87 | ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); | 89 | ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); |
| 88 | 90 | ||
| 89 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | 91 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be |
| 90 | // null here | 92 | // null here |
diff --git a/src/core/memory.h b/src/core/memory.h index 8fd3080ff..903b58a22 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <cstddef> | 8 | #include <cstddef> |
| 8 | #include <string> | 9 | #include <string> |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -17,6 +18,7 @@ namespace Memory { | |||
| 17 | const u32 PAGE_SIZE = 0x1000; | 18 | const u32 PAGE_SIZE = 0x1000; |
| 18 | const u32 PAGE_MASK = PAGE_SIZE - 1; | 19 | const u32 PAGE_MASK = PAGE_SIZE - 1; |
| 19 | const int PAGE_BITS = 12; | 20 | const int PAGE_BITS = 12; |
| 21 | const size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS); | ||
| 20 | 22 | ||
| 21 | /// Physical memory regions as seen from the ARM11 | 23 | /// Physical memory regions as seen from the ARM11 |
| 22 | enum : PAddr { | 24 | enum : PAddr { |
| @@ -166,4 +168,11 @@ void RasterizerFlushRegion(PAddr start, u32 size); | |||
| 166 | * Flushes and invalidates any externally cached rasterizer resources touching the given region. | 168 | * Flushes and invalidates any externally cached rasterizer resources touching the given region. |
| 167 | */ | 169 | */ |
| 168 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size); | 170 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size); |
| 171 | |||
| 172 | /** | ||
| 173 | * Dynarmic has an optimization to memory accesses when the pointer to the page exists that | ||
| 174 | * can be used by setting up the current page table as a callback. This function is used to | ||
| 175 | * retrieve the current page table for that purpose. | ||
| 176 | */ | ||
| 177 | std::array<u8*, PAGE_TABLE_NUM_ENTRIES>* GetCurrentPageTablePointers(); | ||
| 169 | } | 178 | } |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index fda91e29c..b7c32035e 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -215,18 +215,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 215 | 215 | ||
| 216 | PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler; | 216 | PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler; |
| 217 | 217 | ||
| 218 | if (g_debug_context) { | 218 | if (g_debug_context && g_debug_context->recorder) { |
| 219 | for (int i = 0; i < 3; ++i) { | 219 | for (int i = 0; i < 3; ++i) { |
| 220 | const auto texture = regs.GetTextures()[i]; | 220 | const auto texture = regs.GetTextures()[i]; |
| 221 | if (!texture.enabled) | 221 | if (!texture.enabled) |
| 222 | continue; | 222 | continue; |
| 223 | 223 | ||
| 224 | u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); | 224 | u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); |
| 225 | if (g_debug_context && Pica::g_debug_context->recorder) | 225 | g_debug_context->recorder->MemoryAccessed( |
| 226 | g_debug_context->recorder->MemoryAccessed( | 226 | texture_data, Pica::Regs::NibblesPerPixel(texture.format) * |
| 227 | texture_data, Pica::Regs::NibblesPerPixel(texture.format) * | 227 | texture.config.width / 2 * texture.config.height, |
| 228 | texture.config.width / 2 * texture.config.height, | 228 | texture.config.GetPhysicalAddress()); |
| 229 | texture.config.GetPhysicalAddress()); | ||
| 230 | } | 229 | } |
| 231 | } | 230 | } |
| 232 | 231 | ||
| @@ -236,7 +235,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 236 | // The size has been tuned for optimal balance between hit-rate and the cost of lookup | 235 | // The size has been tuned for optimal balance between hit-rate and the cost of lookup |
| 237 | const size_t VERTEX_CACHE_SIZE = 32; | 236 | const size_t VERTEX_CACHE_SIZE = 32; |
| 238 | std::array<u16, VERTEX_CACHE_SIZE> vertex_cache_ids; | 237 | std::array<u16, VERTEX_CACHE_SIZE> vertex_cache_ids; |
| 239 | std::array<Shader::OutputRegisters, VERTEX_CACHE_SIZE> vertex_cache; | 238 | std::array<Shader::OutputVertex, VERTEX_CACHE_SIZE> vertex_cache; |
| 239 | Shader::OutputVertex output_vertex; | ||
| 240 | 240 | ||
| 241 | unsigned int vertex_cache_pos = 0; | 241 | unsigned int vertex_cache_pos = 0; |
| 242 | vertex_cache_ids.fill(-1); | 242 | vertex_cache_ids.fill(-1); |
| @@ -266,7 +266,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 266 | 266 | ||
| 267 | for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) { | 267 | for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) { |
| 268 | if (vertex == vertex_cache_ids[i]) { | 268 | if (vertex == vertex_cache_ids[i]) { |
| 269 | output_registers = vertex_cache[i]; | 269 | output_vertex = vertex_cache[i]; |
| 270 | vertex_cache_hit = true; | 270 | vertex_cache_hit = true; |
| 271 | break; | 271 | break; |
| 272 | } | 272 | } |
| @@ -285,16 +285,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 285 | g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes()); | 285 | g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes()); |
| 286 | output_registers = shader_unit.output_registers; | 286 | output_registers = shader_unit.output_registers; |
| 287 | 287 | ||
| 288 | // Retrieve vertex from register data | ||
| 289 | output_vertex = output_registers.ToVertex(regs.vs); | ||
| 290 | |||
| 288 | if (is_indexed) { | 291 | if (is_indexed) { |
| 289 | vertex_cache[vertex_cache_pos] = output_registers; | 292 | vertex_cache[vertex_cache_pos] = output_vertex; |
| 290 | vertex_cache_ids[vertex_cache_pos] = vertex; | 293 | vertex_cache_ids[vertex_cache_pos] = vertex; |
| 291 | vertex_cache_pos = (vertex_cache_pos + 1) % VERTEX_CACHE_SIZE; | 294 | vertex_cache_pos = (vertex_cache_pos + 1) % VERTEX_CACHE_SIZE; |
| 292 | } | 295 | } |
| 293 | } | 296 | } |
| 294 | 297 | ||
| 295 | // Retrieve vertex from register data | ||
| 296 | Shader::OutputVertex output_vertex = output_registers.ToVertex(regs.vs); | ||
| 297 | |||
| 298 | // Send to renderer | 298 | // Send to renderer |
| 299 | using Pica::Shader::OutputVertex; | 299 | using Pica::Shader::OutputVertex; |
| 300 | auto AddTriangle = [](const OutputVertex& v0, const OutputVertex& v1, | 300 | auto AddTriangle = [](const OutputVertex& v0, const OutputVertex& v1, |
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index b2db609ec..99bd59a69 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -40,7 +40,7 @@ namespace Pica { | |||
| 40 | // field offset. Otherwise, the compiler will fail to compile this code. | 40 | // field offset. Otherwise, the compiler will fail to compile this code. |
| 41 | #define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \ | 41 | #define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \ |
| 42 | ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \ | 42 | ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \ |
| 43 | size_t>::type)PICA_REG_INDEX(field_name)) | 43 | size_t>::type) PICA_REG_INDEX(field_name)) |
| 44 | #endif // _MSC_VER | 44 | #endif // _MSC_VER |
| 45 | 45 | ||
| 46 | struct Regs { | 46 | struct Regs { |