diff options
212 files changed, 6161 insertions, 3440 deletions
diff --git a/.travis-build.sh b/.travis-build.sh index 8ec2ed70c..22a3a9fd6 100755 --- a/.travis-build.sh +++ b/.travis-build.sh | |||
| @@ -11,8 +11,12 @@ fi | |||
| 11 | 11 | ||
| 12 | #if OS is linux or is not set | 12 | #if OS is linux or is not set |
| 13 | if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then | 13 | if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then |
| 14 | export CC=gcc-4.9 | ||
| 15 | export CXX=g++-4.9 | ||
| 16 | export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH | ||
| 17 | |||
| 14 | mkdir build && cd build | 18 | mkdir build && cd build |
| 15 | cmake -DUSE_QT5=OFF .. | 19 | cmake -DCITRA_FORCE_QT4=ON .. |
| 16 | make -j4 | 20 | make -j4 |
| 17 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; then | 21 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; then |
| 18 | export Qt5_DIR=$(brew --prefix)/opt/qt5 | 22 | export Qt5_DIR=$(brew --prefix)/opt/qt5 |
diff --git a/.travis-deps.sh b/.travis-deps.sh index b9561bb66..5c530dcb9 100755 --- a/.travis-deps.sh +++ b/.travis-deps.sh | |||
| @@ -5,26 +5,26 @@ set -x | |||
| 5 | 5 | ||
| 6 | #if OS is linux or is not set | 6 | #if OS is linux or is not set |
| 7 | if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then | 7 | if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then |
| 8 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y | 8 | export CC=gcc-4.9 |
| 9 | sudo apt-get -qq update | 9 | export CXX=g++-4.9 |
| 10 | sudo apt-get -qq install g++-4.9 xorg-dev libglu1-mesa-dev libxcursor-dev | 10 | mkdir -p $HOME/.local |
| 11 | sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 | 11 | |
| 12 | curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \ | ||
| 13 | | tar -xz -C $HOME/.local --strip-components=1 | ||
| 14 | |||
| 12 | ( | 15 | ( |
| 13 | git clone https://github.com/glfw/glfw.git --branch 3.0.4 --depth 1 | 16 | git clone https://github.com/glfw/glfw.git --branch 3.1.1 --depth 1 |
| 14 | mkdir glfw/build && cd glfw/build | 17 | mkdir glfw/build && cd glfw/build |
| 15 | cmake -DBUILD_SHARED_LIBS=ON \ | 18 | cmake -DBUILD_SHARED_LIBS=ON \ |
| 16 | -DGLFW_BUILD_EXAMPLES=OFF \ | 19 | -DGLFW_BUILD_EXAMPLES=OFF \ |
| 17 | -DGLFW_BUILD_TESTS=OFF \ | 20 | -DGLFW_BUILD_TESTS=OFF \ |
| 21 | -DCMAKE_INSTALL_PREFIX=$HOME/.local \ | ||
| 18 | .. | 22 | .. |
| 19 | make -j4 && sudo make install | 23 | make -j4 && make install |
| 20 | ) | 24 | ) |
| 21 | 25 | ||
| 22 | sudo apt-get install lib32stdc++6 | ||
| 23 | sudo mkdir -p /usr/local | ||
| 24 | curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \ | ||
| 25 | | sudo tar -xz -C /usr/local --strip-components=1 | ||
| 26 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; then | 26 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; then |
| 27 | brew tap homebrew/versions | 27 | brew update > /dev/null # silence the very verbose output |
| 28 | brew install qt5 glfw3 pkgconfig | 28 | brew install qt5 glfw3 pkgconfig |
| 29 | gem install xcpretty | 29 | gem install xcpretty |
| 30 | fi | 30 | fi |
diff --git a/.travis-upload.sh b/.travis-upload.sh index 0904b646a..3a15e8f6a 100644..100755 --- a/.travis-upload.sh +++ b/.travis-upload.sh | |||
| @@ -7,7 +7,6 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then | |||
| 7 | UPLOAD_DIR="/citra/nightly/linux-amd64" | 7 | UPLOAD_DIR="/citra/nightly/linux-amd64" |
| 8 | mkdir "$REV_NAME" | 8 | mkdir "$REV_NAME" |
| 9 | 9 | ||
| 10 | sudo apt-get -qq install lftp | ||
| 11 | cp build/src/citra/citra "$REV_NAME" | 10 | cp build/src/citra/citra "$REV_NAME" |
| 12 | cp build/src/citra_qt/citra-qt "$REV_NAME" | 11 | cp build/src/citra_qt/citra-qt "$REV_NAME" |
| 13 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; then | 12 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; then |
diff --git a/.travis.yml b/.travis.yml index 5c882a574..4d21257bc 100644 --- a/.travis.yml +++ b/.travis.yml | |||
| @@ -8,11 +8,21 @@ env: | |||
| 8 | global: | 8 | global: |
| 9 | - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" | 9 | - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" |
| 10 | 10 | ||
| 11 | before_install: | 11 | sudo: false |
| 12 | - sh .travis-deps.sh | ||
| 13 | 12 | ||
| 14 | script: | 13 | addons: |
| 15 | - sh .travis-build.sh | 14 | apt: |
| 15 | sources: | ||
| 16 | - ubuntu-toolchain-r-test | ||
| 17 | packages: | ||
| 18 | - gcc-4.9 | ||
| 19 | - g++-4.9 | ||
| 20 | - xorg-dev | ||
| 21 | - libglu1-mesa-dev | ||
| 22 | - libxcursor-dev | ||
| 23 | - lib32stdc++6 # For CMake | ||
| 24 | - lftp # To upload builds | ||
| 16 | 25 | ||
| 17 | after_success: | 26 | install: ./.travis-deps.sh |
| 18 | - sh .travis-upload.sh | 27 | script: ./.travis-build.sh |
| 28 | after_success: ./.travis-upload.sh | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6805ebed8..e945a6679 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -7,8 +7,7 @@ project(citra) | |||
| 7 | if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit) | 7 | if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit) |
| 8 | message(STATUS "Copying pre-commit hook") | 8 | message(STATUS "Copying pre-commit hook") |
| 9 | file(COPY hooks/pre-commit | 9 | file(COPY hooks/pre-commit |
| 10 | DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks | 10 | DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks) |
| 11 | FILE_PERMISSIONS WORLD_EXECUTE ) | ||
| 12 | endif() | 11 | endif() |
| 13 | 12 | ||
| 14 | if (NOT MSVC) | 13 | if (NOT MSVC) |
| @@ -22,32 +21,34 @@ else() | |||
| 22 | 21 | ||
| 23 | # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms) | 22 | # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms) |
| 24 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) | 23 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) |
| 25 | set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE STRING "" FORCE) | 24 | set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE) |
| 26 | 25 | ||
| 27 | # Tweak optimization settings | 26 | # Tweak optimization settings |
| 28 | # As far as I can tell, there's no way to override the CMake defaults while leaving user | 27 | # As far as I can tell, there's no way to override the CMake defaults while leaving user |
| 29 | # changes intact, so we'll just clobber everything and say sorry. | 28 | # changes intact, so we'll just clobber everything and say sorry. |
| 30 | message(STATUS "Cache compiler flags ignored, please edit CMakeLists.txt to change the flags.") | 29 | message(STATUS "Cache compiler flags ignored, please edit CMakeLists.txt to change the flags.") |
| 31 | # /O2 - Optimization level 2 | 30 | |
| 32 | # /Oy- - Don't omit frame pointer | 31 | # /W3 - Level 3 warnings |
| 33 | # /GR- - Disable RTTI | ||
| 34 | # /GS- - No stack buffer overflow checks | ||
| 35 | # /EHsc - C++-only exception handling semantics | ||
| 36 | set(optimization_flags "/O2 /Oy- /GR- /GS- /EHsc") | ||
| 37 | # /MP - Multi-threaded compilation | 32 | # /MP - Multi-threaded compilation |
| 38 | # /Zi - Output debugging information | 33 | # /Zi - Output debugging information |
| 39 | # /Zo - enahnced debug info for optimized builds | 34 | # /Zo - enahnced debug info for optimized builds |
| 35 | set(CMAKE_C_FLAGS "/W3 /MP /Zi /Zo" CACHE STRING "" FORCE) | ||
| 36 | # /GR- - Disable RTTI | ||
| 37 | # /EHsc - C++-only exception handling semantics | ||
| 38 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} /GR- /EHsc" CACHE STRING "" FORCE) | ||
| 39 | |||
| 40 | # /MDd - Multi-threaded Debug Runtime DLL | 40 | # /MDd - Multi-threaded Debug Runtime DLL |
| 41 | set(CMAKE_C_FLAGS_DEBUG "/MP /MDd /Zi" CACHE STRING "" FORCE) | 41 | set(CMAKE_C_FLAGS_DEBUG "/Od /MDd" CACHE STRING "" FORCE) |
| 42 | set(CMAKE_CXX_FLAGS_DEBUG "/MP /MDd /Zi" CACHE STRING "" FORCE) | 42 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE) |
| 43 | |||
| 44 | # /O2 - Optimization level 2 | ||
| 45 | # /GS- - No stack buffer overflow checks | ||
| 43 | # /MD - Multi-threaded runtime DLL | 46 | # /MD - Multi-threaded runtime DLL |
| 44 | set(CMAKE_C_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) | 47 | set(CMAKE_C_FLAGS_RELEASE "/O2 /GS- /MD" CACHE STRING "" FORCE) |
| 45 | set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) | 48 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "" FORCE) |
| 46 | set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) | ||
| 47 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) | ||
| 48 | 49 | ||
| 49 | set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) | 50 | set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) |
| 50 | set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG" CACHE STRING "" FORCE) | 51 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG" CACHE STRING "" FORCE) |
| 51 | endif() | 52 | endif() |
| 52 | 53 | ||
| 53 | add_definitions(-DSINGLETHREADED) | 54 | add_definitions(-DSINGLETHREADED) |
| @@ -201,6 +202,10 @@ add_subdirectory(${INI_PREFIX}) | |||
| 201 | 202 | ||
| 202 | include_directories(externals/nihstro/include) | 203 | include_directories(externals/nihstro/include) |
| 203 | 204 | ||
| 205 | if (MSVC) | ||
| 206 | add_subdirectory(externals/getopt) | ||
| 207 | endif() | ||
| 208 | |||
| 204 | # process subdirectories | 209 | # process subdirectories |
| 205 | if(ENABLE_QT) | 210 | if(ENABLE_QT) |
| 206 | include_directories(externals/qhexedit) | 211 | include_directories(externals/qhexedit) |
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 906a4bc7d..f2dbdf1a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md | |||
| @@ -7,19 +7,14 @@ Citra is a brand new project, so we have a great opportunity to keep things clea | |||
| 7 | * Don't ever introduce new external dependencies into Core | 7 | * Don't ever introduce new external dependencies into Core |
| 8 | * Don't use any platform specific code in Core | 8 | * Don't use any platform specific code in Core |
| 9 | * Use namespaces often | 9 | * Use namespaces often |
| 10 | * Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Never use `const_cast` or `dynamic_cast` (we build with RTTI disabled). The only exception to this rule is for casting between two numeric types, where C-style casts are encouraged for brevity and readability. | ||
| 10 | 11 | ||
| 11 | ### Naming Rules | 12 | ### Naming Rules |
| 12 | * Functions | 13 | * Functions: `PascalCase` |
| 13 | * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore) | 14 | * Variables: `lower_case_underscored`. Prefix with `g_` if global. |
| 14 | * Variables | 15 | * Classes: `PascalCase` |
| 15 | * lower_case_underscored | 16 | * Files and Directories: `lower_case_underscored` |
| 16 | * Prefix "g_" if global | 17 | * Namespaces: `PascalCase`, `_` may also be used for clarity (e.g. `ARM_InitCore`) |
| 17 | * Classes | ||
| 18 | * PascalCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) | ||
| 19 | * Files/Folders | ||
| 20 | * lower_case_underscored | ||
| 21 | * Namespaces | ||
| 22 | * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore) | ||
| 23 | 18 | ||
| 24 | ### Indentation/Whitespace Style | 19 | ### Indentation/Whitespace Style |
| 25 | Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. | 20 | Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. |
| @@ -36,25 +31,25 @@ namespace Example { | |||
| 36 | 31 | ||
| 37 | // Declare globals at the top | 32 | // Declare globals at the top |
| 38 | int g_foo = 0; | 33 | int g_foo = 0; |
| 39 | char* g_some_pointer; // Notice the position of the * | 34 | char* g_some_pointer; // Pointer * and reference & stick to the type name |
| 40 | 35 | ||
| 41 | /// A colorful enum. | 36 | /// A colorful enum. |
| 42 | enum SomeEnum { | 37 | enum SomeEnum { |
| 43 | COLOR_RED, ///< The color of fire. | 38 | COLOR_RED, ///< The color of fire. |
| 44 | COLOR_GREEN, ///< The color of grass. | 39 | COLOR_GREEN, ///< The color of grass. |
| 45 | COLOR_BLUE ///< Not actually the color of water. | 40 | COLOR_BLUE, ///< Not actually the color of water. |
| 46 | }; | 41 | }; |
| 47 | 42 | ||
| 48 | /** | 43 | /** |
| 49 | * Very important struct that does a lot of stuff. | 44 | * Very important struct that does a lot of stuff. |
| 50 | * Note that the asterisks are indented by one space. | 45 | * Note that the asterisks are indented by one space to align to the first line. |
| 51 | */ | 46 | */ |
| 52 | struct Position { | 47 | struct Position { |
| 53 | int x, y; | 48 | int x, y; |
| 54 | }; | 49 | }; |
| 55 | 50 | ||
| 56 | // Use "typename" rather than "class" here, just to be consistent | 51 | // Use "typename" rather than "class" here |
| 57 | template | 52 | template <typename T> |
| 58 | void FooBar() { | 53 | void FooBar() { |
| 59 | int some_array[] = { | 54 | int some_array[] = { |
| 60 | 5, | 55 | 5, |
| @@ -72,7 +67,7 @@ void FooBar() { | |||
| 72 | // Comment directly above code when possible | 67 | // Comment directly above code when possible |
| 73 | if (some_condition) single_statement(); | 68 | if (some_condition) single_statement(); |
| 74 | 69 | ||
| 75 | // Place a single space after the for loop semicolons | 70 | // Place a single space after the for loop semicolons, prefer pre-increment |
| 76 | for (int i = 0; i != 25; ++i) { | 71 | for (int i = 0; i != 25; ++i) { |
| 77 | // This is how we write loops | 72 | // This is how we write loops |
| 78 | } | 73 | } |
| @@ -83,6 +78,9 @@ void FooBar() { | |||
| 83 | if (this || condition_takes_up_multiple && | 78 | if (this || condition_takes_up_multiple && |
| 84 | lines && like && this || everything || | 79 | lines && like && this || everything || |
| 85 | alright || then) { | 80 | alright || then) { |
| 81 | |||
| 82 | // Leave a blank space before the if block body if the condition was continued across | ||
| 83 | // several lines. | ||
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | switch (var) { | 86 | switch (var) { |
| @@ -101,11 +99,7 @@ void FooBar() { | |||
| 101 | break; | 99 | break; |
| 102 | } | 100 | } |
| 103 | 101 | ||
| 104 | std::vector | 102 | std::vector<T> you_can_declare, a_few, variables, like_this; |
| 105 | you_can_declare, | ||
| 106 | a_few, | ||
| 107 | variables, | ||
| 108 | like_this; | ||
| 109 | } | 103 | } |
| 110 | 104 | ||
| 111 | } | 105 | } |
| @@ -7,7 +7,7 @@ Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C | |||
| 7 | 7 | ||
| 8 | 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. | 8 | 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. |
| 9 | 9 | ||
| 10 | For development discussion, please join us @ #citra on [freenode](http://webchat.freenode.net/?channels=citra). | 10 | For development discussion, please join us @ #citra on freenode. |
| 11 | 11 | ||
| 12 | ### Development | 12 | ### Development |
| 13 | 13 | ||
diff --git a/appveyor.yml b/appveyor.yml index 7e9155e6d..5dc147639 100644 --- a/appveyor.yml +++ b/appveyor.yml | |||
| @@ -13,7 +13,7 @@ configuration: | |||
| 13 | - Release | 13 | - Release |
| 14 | 14 | ||
| 15 | install: | 15 | install: |
| 16 | - git submodule update --init --recursive --depth 20 | 16 | - git submodule update --init --recursive |
| 17 | 17 | ||
| 18 | before_build: | 18 | before_build: |
| 19 | - mkdir build | 19 | - mkdir build |
diff --git a/externals/getopt/CMakeLists.txt b/externals/getopt/CMakeLists.txt new file mode 100644 index 000000000..c8b745d55 --- /dev/null +++ b/externals/getopt/CMakeLists.txt | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | set(SRCS | ||
| 2 | getopt.c | ||
| 3 | ) | ||
| 4 | set(HEADERS | ||
| 5 | getopt.h | ||
| 6 | ) | ||
| 7 | |||
| 8 | create_directory_groups(${SRCS} ${HEADERS}) | ||
| 9 | add_library(getopt ${SRCS} ${HEADERS}) | ||
| 10 | target_compile_definitions(getopt PUBLIC STATIC_GETOPT) | ||
| 11 | target_include_directories(getopt INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) | ||
diff --git a/externals/getopt/getopt.c b/externals/getopt/getopt.c new file mode 100644 index 000000000..948d42683 --- /dev/null +++ b/externals/getopt/getopt.c | |||
| @@ -0,0 +1,962 @@ | |||
| 1 | /* Getopt for Microsoft C | ||
| 2 | This code is a modification of the Free Software Foundation, Inc. | ||
| 3 | Getopt library for parsing command line argument the purpose was | ||
| 4 | to provide a Microsoft Visual C friendly derivative. This code | ||
| 5 | provides functionality for both Unicode and Multibyte builds. | ||
| 6 | |||
| 7 | Date: 02/03/2011 - Ludvik Jerabek - Initial Release | ||
| 8 | Version: 1.0 | ||
| 9 | Comment: Supports getopt, getopt_long, and getopt_long_only | ||
| 10 | and POSIXLY_CORRECT environment flag | ||
| 11 | License: LGPL | ||
| 12 | |||
| 13 | Revisions: | ||
| 14 | |||
| 15 | 02/03/2011 - Ludvik Jerabek - Initial Release | ||
| 16 | 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 | ||
| 17 | 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs | ||
| 18 | 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception | ||
| 19 | 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB | ||
| 20 | 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file | ||
| 21 | 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi | ||
| 22 | 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features | ||
| 23 | 06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable | ||
| 24 | |||
| 25 | **DISCLAIMER** | ||
| 26 | THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, | ||
| 27 | EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE | ||
| 28 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
| 29 | PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE | ||
| 30 | EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT | ||
| 31 | APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY | ||
| 32 | DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY | ||
| 33 | USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST | ||
| 34 | PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON | ||
| 35 | YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE | ||
| 36 | EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | ||
| 37 | */ | ||
| 38 | #include <stdlib.h> | ||
| 39 | #include <stdio.h> | ||
| 40 | #ifdef _MSC_VER | ||
| 41 | #include <malloc.h> | ||
| 42 | #endif | ||
| 43 | #include "getopt.h" | ||
| 44 | |||
| 45 | #ifdef __cplusplus | ||
| 46 | #define _GETOPT_THROW throw() | ||
| 47 | #else | ||
| 48 | #define _GETOPT_THROW | ||
| 49 | #endif | ||
| 50 | |||
| 51 | int optind = 1; | ||
| 52 | int opterr = 1; | ||
| 53 | int optopt = '?'; | ||
| 54 | enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER }; | ||
| 55 | |||
| 56 | |||
| 57 | static struct _getopt_data_a | ||
| 58 | { | ||
| 59 | int optind; | ||
| 60 | int opterr; | ||
| 61 | int optopt; | ||
| 62 | char *optarg; | ||
| 63 | int __initialized; | ||
| 64 | char *__nextchar; | ||
| 65 | enum ENUM_ORDERING __ordering; | ||
| 66 | int __posixly_correct; | ||
| 67 | int __first_nonopt; | ||
| 68 | int __last_nonopt; | ||
| 69 | } getopt_data_a; | ||
| 70 | char *optarg_a; | ||
| 71 | |||
| 72 | static void exchange_a(char **argv, struct _getopt_data_a *d) | ||
| 73 | { | ||
| 74 | int bottom = d->__first_nonopt; | ||
| 75 | int middle = d->__last_nonopt; | ||
| 76 | int top = d->optind; | ||
| 77 | char *tem; | ||
| 78 | while (top > middle && middle > bottom) | ||
| 79 | { | ||
| 80 | if (top - middle > middle - bottom) | ||
| 81 | { | ||
| 82 | int len = middle - bottom; | ||
| 83 | register int i; | ||
| 84 | for (i = 0; i < len; i++) | ||
| 85 | { | ||
| 86 | tem = argv[bottom + i]; | ||
| 87 | argv[bottom + i] = argv[top - (middle - bottom) + i]; | ||
| 88 | argv[top - (middle - bottom) + i] = tem; | ||
| 89 | } | ||
| 90 | top -= len; | ||
| 91 | } | ||
| 92 | else | ||
| 93 | { | ||
| 94 | int len = top - middle; | ||
| 95 | register int i; | ||
| 96 | for (i = 0; i < len; i++) | ||
| 97 | { | ||
| 98 | tem = argv[bottom + i]; | ||
| 99 | argv[bottom + i] = argv[middle + i]; | ||
| 100 | argv[middle + i] = tem; | ||
| 101 | } | ||
| 102 | bottom += len; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | d->__first_nonopt += (d->optind - d->__last_nonopt); | ||
| 106 | d->__last_nonopt = d->optind; | ||
| 107 | } | ||
| 108 | static const char *_getopt_initialize_a(const char *optstring, struct _getopt_data_a *d, int posixly_correct) | ||
| 109 | { | ||
| 110 | d->__first_nonopt = d->__last_nonopt = d->optind; | ||
| 111 | d->__nextchar = NULL; | ||
| 112 | d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT"); | ||
| 113 | if (optstring[0] == '-') | ||
| 114 | { | ||
| 115 | d->__ordering = RETURN_IN_ORDER; | ||
| 116 | ++optstring; | ||
| 117 | } | ||
| 118 | else if (optstring[0] == '+') | ||
| 119 | { | ||
| 120 | d->__ordering = REQUIRE_ORDER; | ||
| 121 | ++optstring; | ||
| 122 | } | ||
| 123 | else if (d->__posixly_correct) | ||
| 124 | d->__ordering = REQUIRE_ORDER; | ||
| 125 | else | ||
| 126 | d->__ordering = PERMUTE; | ||
| 127 | return optstring; | ||
| 128 | } | ||
| 129 | int _getopt_internal_r_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct) | ||
| 130 | { | ||
| 131 | int print_errors = d->opterr; | ||
| 132 | if (argc < 1) | ||
| 133 | return -1; | ||
| 134 | d->optarg = NULL; | ||
| 135 | if (d->optind == 0 || !d->__initialized) | ||
| 136 | { | ||
| 137 | if (d->optind == 0) | ||
| 138 | d->optind = 1; | ||
| 139 | optstring = _getopt_initialize_a(optstring, d, posixly_correct); | ||
| 140 | d->__initialized = 1; | ||
| 141 | } | ||
| 142 | else if (optstring[0] == '-' || optstring[0] == '+') | ||
| 143 | optstring++; | ||
| 144 | if (optstring[0] == ':') | ||
| 145 | print_errors = 0; | ||
| 146 | if (d->__nextchar == NULL || *d->__nextchar == '\0') | ||
| 147 | { | ||
| 148 | if (d->__last_nonopt > d->optind) | ||
| 149 | d->__last_nonopt = d->optind; | ||
| 150 | if (d->__first_nonopt > d->optind) | ||
| 151 | d->__first_nonopt = d->optind; | ||
| 152 | if (d->__ordering == PERMUTE) | ||
| 153 | { | ||
| 154 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) | ||
| 155 | exchange_a((char **)argv, d); | ||
| 156 | else if (d->__last_nonopt != d->optind) | ||
| 157 | d->__first_nonopt = d->optind; | ||
| 158 | while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) | ||
| 159 | d->optind++; | ||
| 160 | d->__last_nonopt = d->optind; | ||
| 161 | } | ||
| 162 | if (d->optind != argc && !strcmp(argv[d->optind], "--")) | ||
| 163 | { | ||
| 164 | d->optind++; | ||
| 165 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) | ||
| 166 | exchange_a((char **)argv, d); | ||
| 167 | else if (d->__first_nonopt == d->__last_nonopt) | ||
| 168 | d->__first_nonopt = d->optind; | ||
| 169 | d->__last_nonopt = argc; | ||
| 170 | d->optind = argc; | ||
| 171 | } | ||
| 172 | if (d->optind == argc) | ||
| 173 | { | ||
| 174 | if (d->__first_nonopt != d->__last_nonopt) | ||
| 175 | d->optind = d->__first_nonopt; | ||
| 176 | return -1; | ||
| 177 | } | ||
| 178 | if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) | ||
| 179 | { | ||
| 180 | if (d->__ordering == REQUIRE_ORDER) | ||
| 181 | return -1; | ||
| 182 | d->optarg = argv[d->optind++]; | ||
| 183 | return 1; | ||
| 184 | } | ||
| 185 | d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-')); | ||
| 186 | } | ||
| 187 | if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1]))))) | ||
| 188 | { | ||
| 189 | char *nameend; | ||
| 190 | unsigned int namelen; | ||
| 191 | const struct option_a *p; | ||
| 192 | const struct option_a *pfound = NULL; | ||
| 193 | struct option_list | ||
| 194 | { | ||
| 195 | const struct option_a *p; | ||
| 196 | struct option_list *next; | ||
| 197 | } *ambig_list = NULL; | ||
| 198 | int exact = 0; | ||
| 199 | int indfound = -1; | ||
| 200 | int option_index; | ||
| 201 | for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++); | ||
| 202 | namelen = (unsigned int)(nameend - d->__nextchar); | ||
| 203 | for (p = longopts, option_index = 0; p->name; p++, option_index++) | ||
| 204 | if (!strncmp(p->name, d->__nextchar, namelen)) | ||
| 205 | { | ||
| 206 | if (namelen == (unsigned int)strlen(p->name)) | ||
| 207 | { | ||
| 208 | pfound = p; | ||
| 209 | indfound = option_index; | ||
| 210 | exact = 1; | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | else if (pfound == NULL) | ||
| 214 | { | ||
| 215 | pfound = p; | ||
| 216 | indfound = option_index; | ||
| 217 | } | ||
| 218 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) | ||
| 219 | { | ||
| 220 | struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); | ||
| 221 | newp->p = p; | ||
| 222 | newp->next = ambig_list; | ||
| 223 | ambig_list = newp; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | if (ambig_list != NULL && !exact) | ||
| 227 | { | ||
| 228 | if (print_errors) | ||
| 229 | { | ||
| 230 | struct option_list first; | ||
| 231 | first.p = pfound; | ||
| 232 | first.next = ambig_list; | ||
| 233 | ambig_list = &first; | ||
| 234 | fprintf(stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); | ||
| 235 | do | ||
| 236 | { | ||
| 237 | fprintf(stderr, " '--%s'", ambig_list->p->name); | ||
| 238 | ambig_list = ambig_list->next; | ||
| 239 | } while (ambig_list != NULL); | ||
| 240 | fputc('\n', stderr); | ||
| 241 | } | ||
| 242 | d->__nextchar += strlen(d->__nextchar); | ||
| 243 | d->optind++; | ||
| 244 | d->optopt = 0; | ||
| 245 | return '?'; | ||
| 246 | } | ||
| 247 | if (pfound != NULL) | ||
| 248 | { | ||
| 249 | option_index = indfound; | ||
| 250 | d->optind++; | ||
| 251 | if (*nameend) | ||
| 252 | { | ||
| 253 | if (pfound->has_arg) | ||
| 254 | d->optarg = nameend + 1; | ||
| 255 | else | ||
| 256 | { | ||
| 257 | if (print_errors) | ||
| 258 | { | ||
| 259 | if (argv[d->optind - 1][1] == '-') | ||
| 260 | { | ||
| 261 | fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n", argv[0], pfound->name); | ||
| 262 | } | ||
| 263 | else | ||
| 264 | { | ||
| 265 | fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n", argv[0], argv[d->optind - 1][0], pfound->name); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | d->__nextchar += strlen(d->__nextchar); | ||
| 269 | d->optopt = pfound->val; | ||
| 270 | return '?'; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | else if (pfound->has_arg == 1) | ||
| 274 | { | ||
| 275 | if (d->optind < argc) | ||
| 276 | d->optarg = argv[d->optind++]; | ||
| 277 | else | ||
| 278 | { | ||
| 279 | if (print_errors) | ||
| 280 | { | ||
| 281 | fprintf(stderr, "%s: option '--%s' requires an argument\n", argv[0], pfound->name); | ||
| 282 | } | ||
| 283 | d->__nextchar += strlen(d->__nextchar); | ||
| 284 | d->optopt = pfound->val; | ||
| 285 | return optstring[0] == ':' ? ':' : '?'; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | d->__nextchar += strlen(d->__nextchar); | ||
| 289 | if (longind != NULL) | ||
| 290 | *longind = option_index; | ||
| 291 | if (pfound->flag) | ||
| 292 | { | ||
| 293 | *(pfound->flag) = pfound->val; | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | return pfound->val; | ||
| 297 | } | ||
| 298 | if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL) | ||
| 299 | { | ||
| 300 | if (print_errors) | ||
| 301 | { | ||
| 302 | if (argv[d->optind][1] == '-') | ||
| 303 | { | ||
| 304 | fprintf(stderr, "%s: unrecognized option '--%s'\n", argv[0], d->__nextchar); | ||
| 305 | } | ||
| 306 | else | ||
| 307 | { | ||
| 308 | fprintf(stderr, "%s: unrecognized option '%c%s'\n", argv[0], argv[d->optind][0], d->__nextchar); | ||
| 309 | } | ||
| 310 | } | ||
| 311 | d->__nextchar = (char *)""; | ||
| 312 | d->optind++; | ||
| 313 | d->optopt = 0; | ||
| 314 | return '?'; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | { | ||
| 318 | char c = *d->__nextchar++; | ||
| 319 | char *temp = (char*)strchr(optstring, c); | ||
| 320 | if (*d->__nextchar == '\0') | ||
| 321 | ++d->optind; | ||
| 322 | if (temp == NULL || c == ':' || c == ';') | ||
| 323 | { | ||
| 324 | if (print_errors) | ||
| 325 | { | ||
| 326 | fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c); | ||
| 327 | } | ||
| 328 | d->optopt = c; | ||
| 329 | return '?'; | ||
| 330 | } | ||
| 331 | if (temp[0] == 'W' && temp[1] == ';') | ||
| 332 | { | ||
| 333 | char *nameend; | ||
| 334 | const struct option_a *p; | ||
| 335 | const struct option_a *pfound = NULL; | ||
| 336 | int exact = 0; | ||
| 337 | int ambig = 0; | ||
| 338 | int indfound = 0; | ||
| 339 | int option_index; | ||
| 340 | if (longopts == NULL) | ||
| 341 | goto no_longs; | ||
| 342 | if (*d->__nextchar != '\0') | ||
| 343 | { | ||
| 344 | d->optarg = d->__nextchar; | ||
| 345 | d->optind++; | ||
| 346 | } | ||
| 347 | else if (d->optind == argc) | ||
| 348 | { | ||
| 349 | if (print_errors) | ||
| 350 | { | ||
| 351 | fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c); | ||
| 352 | } | ||
| 353 | d->optopt = c; | ||
| 354 | if (optstring[0] == ':') | ||
| 355 | c = ':'; | ||
| 356 | else | ||
| 357 | c = '?'; | ||
| 358 | return c; | ||
| 359 | } | ||
| 360 | else | ||
| 361 | d->optarg = argv[d->optind++]; | ||
| 362 | for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++); | ||
| 363 | for (p = longopts, option_index = 0; p->name; p++, option_index++) | ||
| 364 | if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar)) | ||
| 365 | { | ||
| 366 | if ((unsigned int)(nameend - d->__nextchar) == strlen(p->name)) | ||
| 367 | { | ||
| 368 | pfound = p; | ||
| 369 | indfound = option_index; | ||
| 370 | exact = 1; | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | else if (pfound == NULL) | ||
| 374 | { | ||
| 375 | pfound = p; | ||
| 376 | indfound = option_index; | ||
| 377 | } | ||
| 378 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) | ||
| 379 | ambig = 1; | ||
| 380 | } | ||
| 381 | if (ambig && !exact) | ||
| 382 | { | ||
| 383 | if (print_errors) | ||
| 384 | { | ||
| 385 | fprintf(stderr, "%s: option '-W %s' is ambiguous\n", argv[0], d->optarg); | ||
| 386 | } | ||
| 387 | d->__nextchar += strlen(d->__nextchar); | ||
| 388 | d->optind++; | ||
| 389 | return '?'; | ||
| 390 | } | ||
| 391 | if (pfound != NULL) | ||
| 392 | { | ||
| 393 | option_index = indfound; | ||
| 394 | if (*nameend) | ||
| 395 | { | ||
| 396 | if (pfound->has_arg) | ||
| 397 | d->optarg = nameend + 1; | ||
| 398 | else | ||
| 399 | { | ||
| 400 | if (print_errors) | ||
| 401 | { | ||
| 402 | fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n", argv[0], pfound->name); | ||
| 403 | } | ||
| 404 | d->__nextchar += strlen(d->__nextchar); | ||
| 405 | return '?'; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | else if (pfound->has_arg == 1) | ||
| 409 | { | ||
| 410 | if (d->optind < argc) | ||
| 411 | d->optarg = argv[d->optind++]; | ||
| 412 | else | ||
| 413 | { | ||
| 414 | if (print_errors) | ||
| 415 | { | ||
| 416 | fprintf(stderr, "%s: option '-W %s' requires an argument\n", argv[0], pfound->name); | ||
| 417 | } | ||
| 418 | d->__nextchar += strlen(d->__nextchar); | ||
| 419 | return optstring[0] == ':' ? ':' : '?'; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | else | ||
| 423 | d->optarg = NULL; | ||
| 424 | d->__nextchar += strlen(d->__nextchar); | ||
| 425 | if (longind != NULL) | ||
| 426 | *longind = option_index; | ||
| 427 | if (pfound->flag) | ||
| 428 | { | ||
| 429 | *(pfound->flag) = pfound->val; | ||
| 430 | return 0; | ||
| 431 | } | ||
| 432 | return pfound->val; | ||
| 433 | } | ||
| 434 | no_longs: | ||
| 435 | d->__nextchar = NULL; | ||
| 436 | return 'W'; | ||
| 437 | } | ||
| 438 | if (temp[1] == ':') | ||
| 439 | { | ||
| 440 | if (temp[2] == ':') | ||
| 441 | { | ||
| 442 | if (*d->__nextchar != '\0') | ||
| 443 | { | ||
| 444 | d->optarg = d->__nextchar; | ||
| 445 | d->optind++; | ||
| 446 | } | ||
| 447 | else | ||
| 448 | d->optarg = NULL; | ||
| 449 | d->__nextchar = NULL; | ||
| 450 | } | ||
| 451 | else | ||
| 452 | { | ||
| 453 | if (*d->__nextchar != '\0') | ||
| 454 | { | ||
| 455 | d->optarg = d->__nextchar; | ||
| 456 | d->optind++; | ||
| 457 | } | ||
| 458 | else if (d->optind == argc) | ||
| 459 | { | ||
| 460 | if (print_errors) | ||
| 461 | { | ||
| 462 | fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c); | ||
| 463 | } | ||
| 464 | d->optopt = c; | ||
| 465 | if (optstring[0] == ':') | ||
| 466 | c = ':'; | ||
| 467 | else | ||
| 468 | c = '?'; | ||
| 469 | } | ||
| 470 | else | ||
| 471 | d->optarg = argv[d->optind++]; | ||
| 472 | d->__nextchar = NULL; | ||
| 473 | } | ||
| 474 | } | ||
| 475 | return c; | ||
| 476 | } | ||
| 477 | } | ||
| 478 | int _getopt_internal_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct) | ||
| 479 | { | ||
| 480 | int result; | ||
| 481 | getopt_data_a.optind = optind; | ||
| 482 | getopt_data_a.opterr = opterr; | ||
| 483 | result = _getopt_internal_r_a(argc, argv, optstring, longopts, longind, long_only, &getopt_data_a, posixly_correct); | ||
| 484 | optind = getopt_data_a.optind; | ||
| 485 | optarg_a = getopt_data_a.optarg; | ||
| 486 | optopt = getopt_data_a.optopt; | ||
| 487 | return result; | ||
| 488 | } | ||
| 489 | int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW | ||
| 490 | { | ||
| 491 | return _getopt_internal_a(argc, argv, optstring, (const struct option_a *) 0, (int *)0, 0, 0); | ||
| 492 | } | ||
| 493 | int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW | ||
| 494 | { | ||
| 495 | return _getopt_internal_a(argc, argv, options, long_options, opt_index, 0, 0); | ||
| 496 | } | ||
| 497 | int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW | ||
| 498 | { | ||
| 499 | return _getopt_internal_a(argc, argv, options, long_options, opt_index, 1, 0); | ||
| 500 | } | ||
| 501 | int _getopt_long_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) | ||
| 502 | { | ||
| 503 | return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 0, d, 0); | ||
| 504 | } | ||
| 505 | int _getopt_long_only_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) | ||
| 506 | { | ||
| 507 | return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 1, d, 0); | ||
| 508 | } | ||
| 509 | |||
| 510 | |||
| 511 | static struct _getopt_data_w | ||
| 512 | { | ||
| 513 | int optind; | ||
| 514 | int opterr; | ||
| 515 | int optopt; | ||
| 516 | wchar_t *optarg; | ||
| 517 | int __initialized; | ||
| 518 | wchar_t *__nextchar; | ||
| 519 | enum ENUM_ORDERING __ordering; | ||
| 520 | int __posixly_correct; | ||
| 521 | int __first_nonopt; | ||
| 522 | int __last_nonopt; | ||
| 523 | } getopt_data_w; | ||
| 524 | wchar_t *optarg_w; | ||
| 525 | |||
| 526 | static void exchange_w(wchar_t **argv, struct _getopt_data_w *d) | ||
| 527 | { | ||
| 528 | int bottom = d->__first_nonopt; | ||
| 529 | int middle = d->__last_nonopt; | ||
| 530 | int top = d->optind; | ||
| 531 | wchar_t *tem; | ||
| 532 | while (top > middle && middle > bottom) | ||
| 533 | { | ||
| 534 | if (top - middle > middle - bottom) | ||
| 535 | { | ||
| 536 | int len = middle - bottom; | ||
| 537 | register int i; | ||
| 538 | for (i = 0; i < len; i++) | ||
| 539 | { | ||
| 540 | tem = argv[bottom + i]; | ||
| 541 | argv[bottom + i] = argv[top - (middle - bottom) + i]; | ||
| 542 | argv[top - (middle - bottom) + i] = tem; | ||
| 543 | } | ||
| 544 | top -= len; | ||
| 545 | } | ||
| 546 | else | ||
| 547 | { | ||
| 548 | int len = top - middle; | ||
| 549 | register int i; | ||
| 550 | for (i = 0; i < len; i++) | ||
| 551 | { | ||
| 552 | tem = argv[bottom + i]; | ||
| 553 | argv[bottom + i] = argv[middle + i]; | ||
| 554 | argv[middle + i] = tem; | ||
| 555 | } | ||
| 556 | bottom += len; | ||
| 557 | } | ||
| 558 | } | ||
| 559 | d->__first_nonopt += (d->optind - d->__last_nonopt); | ||
| 560 | d->__last_nonopt = d->optind; | ||
| 561 | } | ||
| 562 | static const wchar_t *_getopt_initialize_w(const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct) | ||
| 563 | { | ||
| 564 | d->__first_nonopt = d->__last_nonopt = d->optind; | ||
| 565 | d->__nextchar = NULL; | ||
| 566 | d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT"); | ||
| 567 | if (optstring[0] == L'-') | ||
| 568 | { | ||
| 569 | d->__ordering = RETURN_IN_ORDER; | ||
| 570 | ++optstring; | ||
| 571 | } | ||
| 572 | else if (optstring[0] == L'+') | ||
| 573 | { | ||
| 574 | d->__ordering = REQUIRE_ORDER; | ||
| 575 | ++optstring; | ||
| 576 | } | ||
| 577 | else if (d->__posixly_correct) | ||
| 578 | d->__ordering = REQUIRE_ORDER; | ||
| 579 | else | ||
| 580 | d->__ordering = PERMUTE; | ||
| 581 | return optstring; | ||
| 582 | } | ||
| 583 | int _getopt_internal_r_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct) | ||
| 584 | { | ||
| 585 | int print_errors = d->opterr; | ||
| 586 | if (argc < 1) | ||
| 587 | return -1; | ||
| 588 | d->optarg = NULL; | ||
| 589 | if (d->optind == 0 || !d->__initialized) | ||
| 590 | { | ||
| 591 | if (d->optind == 0) | ||
| 592 | d->optind = 1; | ||
| 593 | optstring = _getopt_initialize_w(optstring, d, posixly_correct); | ||
| 594 | d->__initialized = 1; | ||
| 595 | } | ||
| 596 | else if (optstring[0] == L'-' || optstring[0] == L'+') | ||
| 597 | optstring++; | ||
| 598 | if (optstring[0] == L':') | ||
| 599 | print_errors = 0; | ||
| 600 | if (d->__nextchar == NULL || *d->__nextchar == L'\0') | ||
| 601 | { | ||
| 602 | if (d->__last_nonopt > d->optind) | ||
| 603 | d->__last_nonopt = d->optind; | ||
| 604 | if (d->__first_nonopt > d->optind) | ||
| 605 | d->__first_nonopt = d->optind; | ||
| 606 | if (d->__ordering == PERMUTE) | ||
| 607 | { | ||
| 608 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) | ||
| 609 | exchange_w((wchar_t **)argv, d); | ||
| 610 | else if (d->__last_nonopt != d->optind) | ||
| 611 | d->__first_nonopt = d->optind; | ||
| 612 | while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) | ||
| 613 | d->optind++; | ||
| 614 | d->__last_nonopt = d->optind; | ||
| 615 | } | ||
| 616 | if (d->optind != argc && !wcscmp(argv[d->optind], L"--")) | ||
| 617 | { | ||
| 618 | d->optind++; | ||
| 619 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) | ||
| 620 | exchange_w((wchar_t **)argv, d); | ||
| 621 | else if (d->__first_nonopt == d->__last_nonopt) | ||
| 622 | d->__first_nonopt = d->optind; | ||
| 623 | d->__last_nonopt = argc; | ||
| 624 | d->optind = argc; | ||
| 625 | } | ||
| 626 | if (d->optind == argc) | ||
| 627 | { | ||
| 628 | if (d->__first_nonopt != d->__last_nonopt) | ||
| 629 | d->optind = d->__first_nonopt; | ||
| 630 | return -1; | ||
| 631 | } | ||
| 632 | if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) | ||
| 633 | { | ||
| 634 | if (d->__ordering == REQUIRE_ORDER) | ||
| 635 | return -1; | ||
| 636 | d->optarg = argv[d->optind++]; | ||
| 637 | return 1; | ||
| 638 | } | ||
| 639 | d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-')); | ||
| 640 | } | ||
| 641 | if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1]))))) | ||
| 642 | { | ||
| 643 | wchar_t *nameend; | ||
| 644 | unsigned int namelen; | ||
| 645 | const struct option_w *p; | ||
| 646 | const struct option_w *pfound = NULL; | ||
| 647 | struct option_list | ||
| 648 | { | ||
| 649 | const struct option_w *p; | ||
| 650 | struct option_list *next; | ||
| 651 | } *ambig_list = NULL; | ||
| 652 | int exact = 0; | ||
| 653 | int indfound = -1; | ||
| 654 | int option_index; | ||
| 655 | for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++); | ||
| 656 | namelen = (unsigned int)(nameend - d->__nextchar); | ||
| 657 | for (p = longopts, option_index = 0; p->name; p++, option_index++) | ||
| 658 | if (!wcsncmp(p->name, d->__nextchar, namelen)) | ||
| 659 | { | ||
| 660 | if (namelen == (unsigned int)wcslen(p->name)) | ||
| 661 | { | ||
| 662 | pfound = p; | ||
| 663 | indfound = option_index; | ||
| 664 | exact = 1; | ||
| 665 | break; | ||
| 666 | } | ||
| 667 | else if (pfound == NULL) | ||
| 668 | { | ||
| 669 | pfound = p; | ||
| 670 | indfound = option_index; | ||
| 671 | } | ||
| 672 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) | ||
| 673 | { | ||
| 674 | struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); | ||
| 675 | newp->p = p; | ||
| 676 | newp->next = ambig_list; | ||
| 677 | ambig_list = newp; | ||
| 678 | } | ||
| 679 | } | ||
| 680 | if (ambig_list != NULL && !exact) | ||
| 681 | { | ||
| 682 | if (print_errors) | ||
| 683 | { | ||
| 684 | struct option_list first; | ||
| 685 | first.p = pfound; | ||
| 686 | first.next = ambig_list; | ||
| 687 | ambig_list = &first; | ||
| 688 | fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); | ||
| 689 | do | ||
| 690 | { | ||
| 691 | fwprintf(stderr, L" '--%s'", ambig_list->p->name); | ||
| 692 | ambig_list = ambig_list->next; | ||
| 693 | } while (ambig_list != NULL); | ||
| 694 | fputwc(L'\n', stderr); | ||
| 695 | } | ||
| 696 | d->__nextchar += wcslen(d->__nextchar); | ||
| 697 | d->optind++; | ||
| 698 | d->optopt = 0; | ||
| 699 | return L'?'; | ||
| 700 | } | ||
| 701 | if (pfound != NULL) | ||
| 702 | { | ||
| 703 | option_index = indfound; | ||
| 704 | d->optind++; | ||
| 705 | if (*nameend) | ||
| 706 | { | ||
| 707 | if (pfound->has_arg) | ||
| 708 | d->optarg = nameend + 1; | ||
| 709 | else | ||
| 710 | { | ||
| 711 | if (print_errors) | ||
| 712 | { | ||
| 713 | if (argv[d->optind - 1][1] == L'-') | ||
| 714 | { | ||
| 715 | fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n", argv[0], pfound->name); | ||
| 716 | } | ||
| 717 | else | ||
| 718 | { | ||
| 719 | fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n", argv[0], argv[d->optind - 1][0], pfound->name); | ||
| 720 | } | ||
| 721 | } | ||
| 722 | d->__nextchar += wcslen(d->__nextchar); | ||
| 723 | d->optopt = pfound->val; | ||
| 724 | return L'?'; | ||
| 725 | } | ||
| 726 | } | ||
| 727 | else if (pfound->has_arg == 1) | ||
| 728 | { | ||
| 729 | if (d->optind < argc) | ||
| 730 | d->optarg = argv[d->optind++]; | ||
| 731 | else | ||
| 732 | { | ||
| 733 | if (print_errors) | ||
| 734 | { | ||
| 735 | fwprintf(stderr, L"%s: option '--%s' requires an argument\n", argv[0], pfound->name); | ||
| 736 | } | ||
| 737 | d->__nextchar += wcslen(d->__nextchar); | ||
| 738 | d->optopt = pfound->val; | ||
| 739 | return optstring[0] == L':' ? L':' : L'?'; | ||
| 740 | } | ||
| 741 | } | ||
| 742 | d->__nextchar += wcslen(d->__nextchar); | ||
| 743 | if (longind != NULL) | ||
| 744 | *longind = option_index; | ||
| 745 | if (pfound->flag) | ||
| 746 | { | ||
| 747 | *(pfound->flag) = pfound->val; | ||
| 748 | return 0; | ||
| 749 | } | ||
| 750 | return pfound->val; | ||
| 751 | } | ||
| 752 | if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL) | ||
| 753 | { | ||
| 754 | if (print_errors) | ||
| 755 | { | ||
| 756 | if (argv[d->optind][1] == L'-') | ||
| 757 | { | ||
| 758 | fwprintf(stderr, L"%s: unrecognized option '--%s'\n", argv[0], d->__nextchar); | ||
| 759 | } | ||
| 760 | else | ||
| 761 | { | ||
| 762 | fwprintf(stderr, L"%s: unrecognized option '%c%s'\n", argv[0], argv[d->optind][0], d->__nextchar); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | d->__nextchar = (wchar_t *)L""; | ||
| 766 | d->optind++; | ||
| 767 | d->optopt = 0; | ||
| 768 | return L'?'; | ||
| 769 | } | ||
| 770 | } | ||
| 771 | { | ||
| 772 | wchar_t c = *d->__nextchar++; | ||
| 773 | wchar_t *temp = (wchar_t*)wcschr(optstring, c); | ||
| 774 | if (*d->__nextchar == L'\0') | ||
| 775 | ++d->optind; | ||
| 776 | if (temp == NULL || c == L':' || c == L';') | ||
| 777 | { | ||
| 778 | if (print_errors) | ||
| 779 | { | ||
| 780 | fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c); | ||
| 781 | } | ||
| 782 | d->optopt = c; | ||
| 783 | return L'?'; | ||
| 784 | } | ||
| 785 | if (temp[0] == L'W' && temp[1] == L';') | ||
| 786 | { | ||
| 787 | wchar_t *nameend; | ||
| 788 | const struct option_w *p; | ||
| 789 | const struct option_w *pfound = NULL; | ||
| 790 | int exact = 0; | ||
| 791 | int ambig = 0; | ||
| 792 | int indfound = 0; | ||
| 793 | int option_index; | ||
| 794 | if (longopts == NULL) | ||
| 795 | goto no_longs; | ||
| 796 | if (*d->__nextchar != L'\0') | ||
| 797 | { | ||
| 798 | d->optarg = d->__nextchar; | ||
| 799 | d->optind++; | ||
| 800 | } | ||
| 801 | else if (d->optind == argc) | ||
| 802 | { | ||
| 803 | if (print_errors) | ||
| 804 | { | ||
| 805 | fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c); | ||
| 806 | } | ||
| 807 | d->optopt = c; | ||
| 808 | if (optstring[0] == L':') | ||
| 809 | c = L':'; | ||
| 810 | else | ||
| 811 | c = L'?'; | ||
| 812 | return c; | ||
| 813 | } | ||
| 814 | else | ||
| 815 | d->optarg = argv[d->optind++]; | ||
| 816 | for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++); | ||
| 817 | for (p = longopts, option_index = 0; p->name; p++, option_index++) | ||
| 818 | if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar)) | ||
| 819 | { | ||
| 820 | if ((unsigned int)(nameend - d->__nextchar) == wcslen(p->name)) | ||
| 821 | { | ||
| 822 | pfound = p; | ||
| 823 | indfound = option_index; | ||
| 824 | exact = 1; | ||
| 825 | break; | ||
| 826 | } | ||
| 827 | else if (pfound == NULL) | ||
| 828 | { | ||
| 829 | pfound = p; | ||
| 830 | indfound = option_index; | ||
| 831 | } | ||
| 832 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) | ||
| 833 | ambig = 1; | ||
| 834 | } | ||
| 835 | if (ambig && !exact) | ||
| 836 | { | ||
| 837 | if (print_errors) | ||
| 838 | { | ||
| 839 | fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n", argv[0], d->optarg); | ||
| 840 | } | ||
| 841 | d->__nextchar += wcslen(d->__nextchar); | ||
| 842 | d->optind++; | ||
| 843 | return L'?'; | ||
| 844 | } | ||
| 845 | if (pfound != NULL) | ||
| 846 | { | ||
| 847 | option_index = indfound; | ||
| 848 | if (*nameend) | ||
| 849 | { | ||
| 850 | if (pfound->has_arg) | ||
| 851 | d->optarg = nameend + 1; | ||
| 852 | else | ||
| 853 | { | ||
| 854 | if (print_errors) | ||
| 855 | { | ||
| 856 | fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n", argv[0], pfound->name); | ||
| 857 | } | ||
| 858 | d->__nextchar += wcslen(d->__nextchar); | ||
| 859 | return L'?'; | ||
| 860 | } | ||
| 861 | } | ||
| 862 | else if (pfound->has_arg == 1) | ||
| 863 | { | ||
| 864 | if (d->optind < argc) | ||
| 865 | d->optarg = argv[d->optind++]; | ||
| 866 | else | ||
| 867 | { | ||
| 868 | if (print_errors) | ||
| 869 | { | ||
| 870 | fwprintf(stderr, L"%s: option '-W %s' requires an argument\n", argv[0], pfound->name); | ||
| 871 | } | ||
| 872 | d->__nextchar += wcslen(d->__nextchar); | ||
| 873 | return optstring[0] == L':' ? L':' : L'?'; | ||
| 874 | } | ||
| 875 | } | ||
| 876 | else | ||
| 877 | d->optarg = NULL; | ||
| 878 | d->__nextchar += wcslen(d->__nextchar); | ||
| 879 | if (longind != NULL) | ||
| 880 | *longind = option_index; | ||
| 881 | if (pfound->flag) | ||
| 882 | { | ||
| 883 | *(pfound->flag) = pfound->val; | ||
| 884 | return 0; | ||
| 885 | } | ||
| 886 | return pfound->val; | ||
| 887 | } | ||
| 888 | no_longs: | ||
| 889 | d->__nextchar = NULL; | ||
| 890 | return L'W'; | ||
| 891 | } | ||
| 892 | if (temp[1] == L':') | ||
| 893 | { | ||
| 894 | if (temp[2] == L':') | ||
| 895 | { | ||
| 896 | if (*d->__nextchar != L'\0') | ||
| 897 | { | ||
| 898 | d->optarg = d->__nextchar; | ||
| 899 | d->optind++; | ||
| 900 | } | ||
| 901 | else | ||
| 902 | d->optarg = NULL; | ||
| 903 | d->__nextchar = NULL; | ||
| 904 | } | ||
| 905 | else | ||
| 906 | { | ||
| 907 | if (*d->__nextchar != L'\0') | ||
| 908 | { | ||
| 909 | d->optarg = d->__nextchar; | ||
| 910 | d->optind++; | ||
| 911 | } | ||
| 912 | else if (d->optind == argc) | ||
| 913 | { | ||
| 914 | if (print_errors) | ||
| 915 | { | ||
| 916 | fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c); | ||
| 917 | } | ||
| 918 | d->optopt = c; | ||
| 919 | if (optstring[0] == L':') | ||
| 920 | c = L':'; | ||
| 921 | else | ||
| 922 | c = L'?'; | ||
| 923 | } | ||
| 924 | else | ||
| 925 | d->optarg = argv[d->optind++]; | ||
| 926 | d->__nextchar = NULL; | ||
| 927 | } | ||
| 928 | } | ||
| 929 | return c; | ||
| 930 | } | ||
| 931 | } | ||
| 932 | int _getopt_internal_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct) | ||
| 933 | { | ||
| 934 | int result; | ||
| 935 | getopt_data_w.optind = optind; | ||
| 936 | getopt_data_w.opterr = opterr; | ||
| 937 | result = _getopt_internal_r_w(argc, argv, optstring, longopts, longind, long_only, &getopt_data_w, posixly_correct); | ||
| 938 | optind = getopt_data_w.optind; | ||
| 939 | optarg_w = getopt_data_w.optarg; | ||
| 940 | optopt = getopt_data_w.optopt; | ||
| 941 | return result; | ||
| 942 | } | ||
| 943 | int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW | ||
| 944 | { | ||
| 945 | return _getopt_internal_w(argc, argv, optstring, (const struct option_w *) 0, (int *)0, 0, 0); | ||
| 946 | } | ||
| 947 | int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW | ||
| 948 | { | ||
| 949 | return _getopt_internal_w(argc, argv, options, long_options, opt_index, 0, 0); | ||
| 950 | } | ||
| 951 | int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW | ||
| 952 | { | ||
| 953 | return _getopt_internal_w(argc, argv, options, long_options, opt_index, 1, 0); | ||
| 954 | } | ||
| 955 | int _getopt_long_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) | ||
| 956 | { | ||
| 957 | return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 0, d, 0); | ||
| 958 | } | ||
| 959 | int _getopt_long_only_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) | ||
| 960 | { | ||
| 961 | return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 1, d, 0); | ||
| 962 | } \ No newline at end of file | ||
diff --git a/externals/getopt/getopt.h b/externals/getopt/getopt.h new file mode 100644 index 000000000..87e2ca396 --- /dev/null +++ b/externals/getopt/getopt.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* Getopt for Microsoft C | ||
| 2 | This code is a modification of the Free Software Foundation, Inc. | ||
| 3 | Getopt library for parsing command line argument the purpose was | ||
| 4 | to provide a Microsoft Visual C friendly derivative. This code | ||
| 5 | provides functionality for both Unicode and Multibyte builds. | ||
| 6 | |||
| 7 | Date: 02/03/2011 - Ludvik Jerabek - Initial Release | ||
| 8 | Version: 1.0 | ||
| 9 | Comment: Supports getopt, getopt_long, and getopt_long_only | ||
| 10 | and POSIXLY_CORRECT environment flag | ||
| 11 | License: LGPL | ||
| 12 | |||
| 13 | Revisions: | ||
| 14 | |||
| 15 | 02/03/2011 - Ludvik Jerabek - Initial Release | ||
| 16 | 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 | ||
| 17 | 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs | ||
| 18 | 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception | ||
| 19 | 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB | ||
| 20 | 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file | ||
| 21 | 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi | ||
| 22 | 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features | ||
| 23 | 06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable | ||
| 24 | |||
| 25 | **DISCLAIMER** | ||
| 26 | THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, | ||
| 27 | EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE | ||
| 28 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
| 29 | PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE | ||
| 30 | EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT | ||
| 31 | APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY | ||
| 32 | DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY | ||
| 33 | USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST | ||
| 34 | PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON | ||
| 35 | YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE | ||
| 36 | EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | ||
| 37 | */ | ||
| 38 | #ifndef __GETOPT_H_ | ||
| 39 | #define __GETOPT_H_ | ||
| 40 | |||
| 41 | #ifdef _GETOPT_API | ||
| 42 | #undef _GETOPT_API | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) | ||
| 46 | #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" | ||
| 47 | #elif defined(STATIC_GETOPT) | ||
| 48 | #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") | ||
| 49 | #define _GETOPT_API | ||
| 50 | #elif defined(EXPORTS_GETOPT) | ||
| 51 | #pragma message("Exporting getopt library") | ||
| 52 | #define _GETOPT_API __declspec(dllexport) | ||
| 53 | #else | ||
| 54 | #pragma message("Importing getopt library") | ||
| 55 | #define _GETOPT_API __declspec(dllimport) | ||
| 56 | #endif | ||
| 57 | |||
| 58 | // Change behavior for C\C++ | ||
| 59 | #ifdef __cplusplus | ||
| 60 | #define _BEGIN_EXTERN_C extern "C" { | ||
| 61 | #define _END_EXTERN_C } | ||
| 62 | #define _GETOPT_THROW throw() | ||
| 63 | #else | ||
| 64 | #define _BEGIN_EXTERN_C | ||
| 65 | #define _END_EXTERN_C | ||
| 66 | #define _GETOPT_THROW | ||
| 67 | #endif | ||
| 68 | |||
| 69 | // Standard GNU options | ||
| 70 | #define null_argument 0 | ||
| 71 | #define no_argument 0 | ||
| 72 | #define required_argument 1 | ||
| 73 | #define optional_argument 2 | ||
| 74 | |||
| 75 | // Shorter Options | ||
| 76 | #define ARG_NULL 0 | ||
| 77 | #define ARG_NONE 0 | ||
| 78 | #define ARG_REQ 1 | ||
| 79 | #define ARG_OPT 2 | ||
| 80 | |||
| 81 | #include <string.h> | ||
| 82 | #include <wchar.h> | ||
| 83 | |||
| 84 | _BEGIN_EXTERN_C | ||
| 85 | |||
| 86 | extern _GETOPT_API int optind; | ||
| 87 | extern _GETOPT_API int opterr; | ||
| 88 | extern _GETOPT_API int optopt; | ||
| 89 | |||
| 90 | // Ansi | ||
| 91 | struct option_a | ||
| 92 | { | ||
| 93 | const char* name; | ||
| 94 | int has_arg; | ||
| 95 | int *flag; | ||
| 96 | int val; | ||
| 97 | }; | ||
| 98 | extern _GETOPT_API char *optarg_a; | ||
| 99 | extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; | ||
| 100 | extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; | ||
| 101 | extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; | ||
| 102 | |||
| 103 | // Unicode | ||
| 104 | struct option_w | ||
| 105 | { | ||
| 106 | const wchar_t* name; | ||
| 107 | int has_arg; | ||
| 108 | int *flag; | ||
| 109 | int val; | ||
| 110 | }; | ||
| 111 | extern _GETOPT_API wchar_t *optarg_w; | ||
| 112 | extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; | ||
| 113 | extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; | ||
| 114 | extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; | ||
| 115 | |||
| 116 | _END_EXTERN_C | ||
| 117 | |||
| 118 | #undef _BEGIN_EXTERN_C | ||
| 119 | #undef _END_EXTERN_C | ||
| 120 | #undef _GETOPT_THROW | ||
| 121 | #undef _GETOPT_API | ||
| 122 | |||
| 123 | #ifdef _UNICODE | ||
| 124 | #define getopt getopt_w | ||
| 125 | #define getopt_long getopt_long_w | ||
| 126 | #define getopt_long_only getopt_long_only_w | ||
| 127 | #define option option_w | ||
| 128 | #define optarg optarg_w | ||
| 129 | #else | ||
| 130 | #define getopt getopt_a | ||
| 131 | #define getopt_long getopt_long_a | ||
| 132 | #define getopt_long_only getopt_long_only_a | ||
| 133 | #define option option_a | ||
| 134 | #define optarg optarg_a | ||
| 135 | #endif | ||
| 136 | #endif // __GETOPT_H_ | ||
diff --git a/externals/nihstro b/externals/nihstro | |||
| Subproject 81f1804a43f625e3a1a20752c0db70a41341038 | Subproject 676254f71e0a7ef0aca8acce078d3c3dc80ccf7 | ||
diff --git a/hooks/pre-commit b/hooks/pre-commit index bad84b14b..bad84b14b 100644..100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit | |||
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt index 713f49193..918687312 100644 --- a/src/citra/CMakeLists.txt +++ b/src/citra/CMakeLists.txt | |||
| @@ -16,6 +16,11 @@ create_directory_groups(${SRCS} ${HEADERS}) | |||
| 16 | add_executable(citra ${SRCS} ${HEADERS}) | 16 | add_executable(citra ${SRCS} ${HEADERS}) |
| 17 | target_link_libraries(citra core common video_core) | 17 | target_link_libraries(citra core common video_core) |
| 18 | target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) | 18 | target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) |
| 19 | if (MSVC) | ||
| 20 | target_link_libraries(citra getopt) | ||
| 21 | endif() | ||
| 19 | target_link_libraries(citra ${PLATFORM_LIBRARIES}) | 22 | target_link_libraries(citra ${PLATFORM_LIBRARIES}) |
| 20 | 23 | ||
| 21 | #install(TARGETS citra RUNTIME DESTINATION ${bindir}) | 24 | if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD") |
| 25 | install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | ||
| 26 | endif() \ No newline at end of file | ||
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index ce8d7dd25..182646f4c 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp | |||
| @@ -2,13 +2,20 @@ | |||
| 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 <string> | ||
| 5 | #include <thread> | 6 | #include <thread> |
| 7 | #include <iostream> | ||
| 8 | |||
| 9 | #ifdef _MSC_VER | ||
| 10 | #include <getopt.h> | ||
| 11 | #else | ||
| 12 | #include <unistd.h> | ||
| 13 | #include <getopt.h> | ||
| 14 | #endif | ||
| 6 | 15 | ||
| 7 | #include "common/logging/log.h" | 16 | #include "common/logging/log.h" |
| 8 | #include "common/logging/text_formatter.h" | ||
| 9 | #include "common/logging/backend.h" | 17 | #include "common/logging/backend.h" |
| 10 | #include "common/logging/filter.h" | 18 | #include "common/logging/filter.h" |
| 11 | #include "common/scope_exit.h" | ||
| 12 | 19 | ||
| 13 | #include "core/settings.h" | 20 | #include "core/settings.h" |
| 14 | #include "core/system.h" | 21 | #include "core/system.h" |
| @@ -20,12 +27,39 @@ | |||
| 20 | 27 | ||
| 21 | #include "video_core/video_core.h" | 28 | #include "video_core/video_core.h" |
| 22 | 29 | ||
| 30 | |||
| 31 | static void PrintHelp() | ||
| 32 | { | ||
| 33 | std::cout << "Usage: citra <filename>" << std::endl; | ||
| 34 | } | ||
| 35 | |||
| 23 | /// Application entry point | 36 | /// Application entry point |
| 24 | int main(int argc, char **argv) { | 37 | int main(int argc, char **argv) { |
| 38 | int option_index = 0; | ||
| 39 | std::string boot_filename; | ||
| 40 | static struct option long_options[] = { | ||
| 41 | { "help", no_argument, 0, 'h' }, | ||
| 42 | { 0, 0, 0, 0 } | ||
| 43 | }; | ||
| 44 | |||
| 45 | while (optind < argc) { | ||
| 46 | char arg = getopt_long(argc, argv, ":h", long_options, &option_index); | ||
| 47 | if (arg != -1) { | ||
| 48 | switch (arg) { | ||
| 49 | case 'h': | ||
| 50 | PrintHelp(); | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | } else { | ||
| 54 | boot_filename = argv[optind]; | ||
| 55 | optind++; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 25 | Log::Filter log_filter(Log::Level::Debug); | 59 | Log::Filter log_filter(Log::Level::Debug); |
| 26 | Log::SetFilter(&log_filter); | 60 | Log::SetFilter(&log_filter); |
| 27 | 61 | ||
| 28 | if (argc < 2) { | 62 | if (boot_filename.empty()) { |
| 29 | LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); | 63 | LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); |
| 30 | return -1; | 64 | return -1; |
| 31 | } | 65 | } |
| @@ -33,7 +67,7 @@ int main(int argc, char **argv) { | |||
| 33 | Config config; | 67 | Config config; |
| 34 | log_filter.ParseFilterString(Settings::values.log_filter); | 68 | log_filter.ParseFilterString(Settings::values.log_filter); |
| 35 | 69 | ||
| 36 | std::string boot_filename = argv[1]; | 70 | |
| 37 | EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; | 71 | EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; |
| 38 | 72 | ||
| 39 | VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer; | 73 | VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer; |
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 1378567c1..2c1407a6f 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -2,7 +2,9 @@ | |||
| 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 | #define GLFW_INCLUDE_NONE | ||
| 5 | #include <GLFW/glfw3.h> | 6 | #include <GLFW/glfw3.h> |
| 7 | #include <inih/cpp/INIReader.h> | ||
| 6 | 8 | ||
| 7 | #include "citra/default_ini.h" | 9 | #include "citra/default_ini.h" |
| 8 | 10 | ||
| @@ -10,7 +12,6 @@ | |||
| 10 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 11 | 13 | ||
| 12 | #include "core/settings.h" | 14 | #include "core/settings.h" |
| 13 | #include "core/core.h" | ||
| 14 | 15 | ||
| 15 | #include "config.h" | 16 | #include "config.h" |
| 16 | 17 | ||
| @@ -39,31 +40,21 @@ bool Config::LoadINI(INIReader* config, const char* location, const std::string& | |||
| 39 | return true; | 40 | return true; |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 43 | static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = { | ||
| 44 | GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_Z, GLFW_KEY_X, | ||
| 45 | GLFW_KEY_Q, GLFW_KEY_W, GLFW_KEY_1, GLFW_KEY_2, | ||
| 46 | GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B, | ||
| 47 | GLFW_KEY_T, GLFW_KEY_G, GLFW_KEY_F, GLFW_KEY_H, | ||
| 48 | GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT, | ||
| 49 | GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L | ||
| 50 | }; | ||
| 51 | |||
| 42 | void Config::ReadValues() { | 52 | void Config::ReadValues() { |
| 43 | // Controls | 53 | // Controls |
| 44 | Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A); | 54 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { |
| 45 | Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S); | 55 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = |
| 46 | Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z); | 56 | glfw_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]); |
| 47 | Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X); | 57 | } |
| 48 | Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q); | ||
| 49 | Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W); | ||
| 50 | Settings::values.pad_zl_key = glfw_config->GetInteger("Controls", "pad_zl", GLFW_KEY_1); | ||
| 51 | Settings::values.pad_zr_key = glfw_config->GetInteger("Controls", "pad_zr", GLFW_KEY_2); | ||
| 52 | Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M); | ||
| 53 | Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N); | ||
| 54 | Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B); | ||
| 55 | Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T); | ||
| 56 | Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G); | ||
| 57 | Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F); | ||
| 58 | Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H); | ||
| 59 | Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP); | ||
| 60 | Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN); | ||
| 61 | Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT); | ||
| 62 | Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT); | ||
| 63 | Settings::values.pad_cup_key = glfw_config->GetInteger("Controls", "pad_cup", GLFW_KEY_I); | ||
| 64 | Settings::values.pad_cdown_key = glfw_config->GetInteger("Controls", "pad_cdown", GLFW_KEY_K); | ||
| 65 | Settings::values.pad_cleft_key = glfw_config->GetInteger("Controls", "pad_cleft", GLFW_KEY_J); | ||
| 66 | Settings::values.pad_cright_key = glfw_config->GetInteger("Controls", "pad_cright", GLFW_KEY_L); | ||
| 67 | 58 | ||
| 68 | // Core | 59 | // Core |
| 69 | Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0); | 60 | Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0); |
diff --git a/src/citra/config.h b/src/citra/config.h index 0eb176c7d..c326ec669 100644 --- a/src/citra/config.h +++ b/src/citra/config.h | |||
| @@ -4,11 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <map> | 7 | #include <string> |
| 8 | 8 | ||
| 9 | #include <inih/cpp/INIReader.h> | 9 | class INIReader; |
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | 10 | ||
| 13 | class Config { | 11 | class Config { |
| 14 | INIReader* glfw_config; | 12 | INIReader* glfw_config; |
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index fd5a90d56..1925bece8 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -33,10 +33,6 @@ pad_cleft = | |||
| 33 | pad_cright = | 33 | pad_cright = |
| 34 | 34 | ||
| 35 | [Core] | 35 | [Core] |
| 36 | # The refresh rate for the GPU | ||
| 37 | # Defaults to 30 | ||
| 38 | gpu_refresh_rate = | ||
| 39 | |||
| 40 | # The applied frameskip amount. Must be a power of two. | 36 | # The applied frameskip amount. Must be a power of two. |
| 41 | # 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc. | 37 | # 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc. |
| 42 | frame_skip = | 38 | frame_skip = |
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp index 341b48d2a..6d6656b5a 100644 --- a/src/citra/emu_window/emu_window_glfw.cpp +++ b/src/citra/emu_window/emu_window_glfw.cpp | |||
| @@ -2,13 +2,25 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <cstdlib> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | // Let’s use our own GL header, instead of one from GLFW. | ||
| 10 | #include "video_core/renderer_opengl/generated/gl_3_2_core.h" | ||
| 11 | #define GLFW_INCLUDE_NONE | ||
| 5 | #include <GLFW/glfw3.h> | 12 | #include <GLFW/glfw3.h> |
| 6 | 13 | ||
| 14 | #include "common/assert.h" | ||
| 15 | #include "common/key_map.h" | ||
| 7 | #include "common/logging/log.h" | 16 | #include "common/logging/log.h" |
| 17 | #include "common/scm_rev.h" | ||
| 18 | #include "common/string_util.h" | ||
| 8 | 19 | ||
| 9 | #include "video_core/video_core.h" | 20 | #include "video_core/video_core.h" |
| 10 | 21 | ||
| 11 | #include "core/settings.h" | 22 | #include "core/settings.h" |
| 23 | #include "core/hle/service/hid/hid.h" | ||
| 12 | 24 | ||
| 13 | #include "citra/emu_window/emu_window_glfw.h" | 25 | #include "citra/emu_window/emu_window_glfw.h" |
| 14 | 26 | ||
| @@ -138,32 +150,9 @@ void EmuWindow_GLFW::DoneCurrent() { | |||
| 138 | } | 150 | } |
| 139 | 151 | ||
| 140 | void EmuWindow_GLFW::ReloadSetKeymaps() { | 152 | void EmuWindow_GLFW::ReloadSetKeymaps() { |
| 141 | KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A); | 153 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { |
| 142 | KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B); | 154 | KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]); |
| 143 | KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT); | 155 | } |
| 144 | KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START); | ||
| 145 | KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT); | ||
| 146 | KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT); | ||
| 147 | KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP); | ||
| 148 | KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN); | ||
| 149 | KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R); | ||
| 150 | KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L); | ||
| 151 | KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X); | ||
| 152 | KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y); | ||
| 153 | |||
| 154 | KeyMap::SetKeyMapping({Settings::values.pad_zl_key, keyboard_id}, Service::HID::PAD_ZL); | ||
| 155 | KeyMap::SetKeyMapping({Settings::values.pad_zr_key, keyboard_id}, Service::HID::PAD_ZR); | ||
| 156 | |||
| 157 | // KeyMap::SetKeyMapping({Settings::values.pad_touch_key, keyboard_id}, Service::HID::PAD_TOUCH); | ||
| 158 | |||
| 159 | KeyMap::SetKeyMapping({Settings::values.pad_cright_key, keyboard_id}, Service::HID::PAD_C_RIGHT); | ||
| 160 | KeyMap::SetKeyMapping({Settings::values.pad_cleft_key, keyboard_id}, Service::HID::PAD_C_LEFT); | ||
| 161 | KeyMap::SetKeyMapping({Settings::values.pad_cup_key, keyboard_id}, Service::HID::PAD_C_UP); | ||
| 162 | KeyMap::SetKeyMapping({Settings::values.pad_cdown_key, keyboard_id}, Service::HID::PAD_C_DOWN); | ||
| 163 | KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT); | ||
| 164 | KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT); | ||
| 165 | KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP); | ||
| 166 | KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN); | ||
| 167 | } | 156 | } |
| 168 | 157 | ||
| 169 | void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { | 158 | void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { |
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h index 16c109b79..7ccd5e6aa 100644 --- a/src/citra/emu_window/emu_window_glfw.h +++ b/src/citra/emu_window/emu_window_glfw.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <utility> | ||
| 8 | |||
| 7 | #include "common/emu_window.h" | 9 | #include "common/emu_window.h" |
| 8 | 10 | ||
| 9 | struct GLFWwindow; | 11 | struct GLFWwindow; |
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index c2d1ad240..47aaeca24 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt | |||
| @@ -12,6 +12,7 @@ set(SRCS | |||
| 12 | debugger/graphics_breakpoints.cpp | 12 | debugger/graphics_breakpoints.cpp |
| 13 | debugger/graphics_cmdlists.cpp | 13 | debugger/graphics_cmdlists.cpp |
| 14 | debugger/graphics_framebuffer.cpp | 14 | debugger/graphics_framebuffer.cpp |
| 15 | debugger/graphics_tracing.cpp | ||
| 15 | debugger/graphics_vertex_shader.cpp | 16 | debugger/graphics_vertex_shader.cpp |
| 16 | debugger/profiler.cpp | 17 | debugger/profiler.cpp |
| 17 | debugger/ramview.cpp | 18 | debugger/ramview.cpp |
| @@ -35,6 +36,7 @@ set(HEADERS | |||
| 35 | debugger/graphics_breakpoints_p.h | 36 | debugger/graphics_breakpoints_p.h |
| 36 | debugger/graphics_cmdlists.h | 37 | debugger/graphics_cmdlists.h |
| 37 | debugger/graphics_framebuffer.h | 38 | debugger/graphics_framebuffer.h |
| 39 | debugger/graphics_tracing.h | ||
| 38 | debugger/graphics_vertex_shader.h | 40 | debugger/graphics_vertex_shader.h |
| 39 | debugger/profiler.h | 41 | debugger/profiler.h |
| 40 | debugger/ramview.h | 42 | debugger/ramview.h |
| @@ -73,7 +75,9 @@ target_link_libraries(citra-qt core common video_core qhexedit) | |||
| 73 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) | 75 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) |
| 74 | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) | 76 | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) |
| 75 | 77 | ||
| 76 | #install(TARGETS citra-qt RUNTIME DESTINATION ${bindir}) | 78 | if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD") |
| 79 | install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | ||
| 80 | endif() | ||
| 77 | 81 | ||
| 78 | if (Qt5_FOUND AND MSVC) | 82 | if (Qt5_FOUND AND MSVC) |
| 79 | set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") | 83 | set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") |
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 3db09c65b..b12bd858b 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -11,6 +11,10 @@ | |||
| 11 | #include "bootmanager.h" | 11 | #include "bootmanager.h" |
| 12 | #include "main.h" | 12 | #include "main.h" |
| 13 | 13 | ||
| 14 | #include "common/string_util.h" | ||
| 15 | #include "common/scm_rev.h" | ||
| 16 | #include "common/key_map.h" | ||
| 17 | |||
| 14 | #include "core/core.h" | 18 | #include "core/core.h" |
| 15 | #include "core/settings.h" | 19 | #include "core/settings.h" |
| 16 | #include "core/system.h" | 20 | #include "core/system.h" |
| @@ -61,7 +65,7 @@ void EmuThread::run() { | |||
| 61 | was_active = false; | 65 | was_active = false; |
| 62 | } else { | 66 | } else { |
| 63 | std::unique_lock<std::mutex> lock(running_mutex); | 67 | std::unique_lock<std::mutex> lock(running_mutex); |
| 64 | running_cv.wait(lock, [this]{ return IsRunning() || stop_run; }); | 68 | running_cv.wait(lock, [this]{ return IsRunning() || exec_step || stop_run; }); |
| 65 | } | 69 | } |
| 66 | } | 70 | } |
| 67 | 71 | ||
| @@ -244,32 +248,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event) | |||
| 244 | 248 | ||
| 245 | void GRenderWindow::ReloadSetKeymaps() | 249 | void GRenderWindow::ReloadSetKeymaps() |
| 246 | { | 250 | { |
| 247 | KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A); | 251 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { |
| 248 | KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B); | 252 | KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]); |
| 249 | KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT); | 253 | } |
| 250 | KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START); | ||
| 251 | KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT); | ||
| 252 | KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT); | ||
| 253 | KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP); | ||
| 254 | KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN); | ||
| 255 | KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R); | ||
| 256 | KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L); | ||
| 257 | KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X); | ||
| 258 | KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y); | ||
| 259 | |||
| 260 | KeyMap::SetKeyMapping({Settings::values.pad_zl_key, keyboard_id}, Service::HID::PAD_ZL); | ||
| 261 | KeyMap::SetKeyMapping({Settings::values.pad_zr_key, keyboard_id}, Service::HID::PAD_ZR); | ||
| 262 | |||
| 263 | // KeyMap::SetKeyMapping({Settings::values.pad_touch_key, keyboard_id}, Service::HID::PAD_TOUCH); | ||
| 264 | |||
| 265 | KeyMap::SetKeyMapping({Settings::values.pad_cright_key, keyboard_id}, Service::HID::PAD_C_RIGHT); | ||
| 266 | KeyMap::SetKeyMapping({Settings::values.pad_cleft_key, keyboard_id}, Service::HID::PAD_C_LEFT); | ||
| 267 | KeyMap::SetKeyMapping({Settings::values.pad_cup_key, keyboard_id}, Service::HID::PAD_C_UP); | ||
| 268 | KeyMap::SetKeyMapping({Settings::values.pad_cdown_key, keyboard_id}, Service::HID::PAD_C_DOWN); | ||
| 269 | KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT); | ||
| 270 | KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT); | ||
| 271 | KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP); | ||
| 272 | KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN); | ||
| 273 | } | 254 | } |
| 274 | 255 | ||
| 275 | void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) | 256 | void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) |
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 475124319..1a1e0e6a5 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h | |||
| @@ -35,7 +35,10 @@ public: | |||
| 35 | * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) | 35 | * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) |
| 36 | * @note This function is thread-safe | 36 | * @note This function is thread-safe |
| 37 | */ | 37 | */ |
| 38 | void ExecStep() { exec_step = true; } | 38 | void ExecStep() { |
| 39 | exec_step = true; | ||
| 40 | running_cv.notify_all(); | ||
| 41 | } | ||
| 39 | 42 | ||
| 40 | /** | 43 | /** |
| 41 | * Sets whether the emulation thread is running or not | 44 | * Sets whether the emulation thread is running or not |
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 2a9af1f38..5716634ee 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp | |||
| @@ -2,11 +2,11 @@ | |||
| 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 <QSettings> | ||
| 5 | #include <QString> | 6 | #include <QString> |
| 6 | #include <QStringList> | 7 | #include <QStringList> |
| 7 | 8 | ||
| 8 | #include "core/settings.h" | 9 | #include "core/settings.h" |
| 9 | #include "core/core.h" | ||
| 10 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 11 | 11 | ||
| 12 | #include "config.h" | 12 | #include "config.h" |
| @@ -21,31 +21,21 @@ Config::Config() { | |||
| 21 | Reload(); | 21 | Reload(); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = { | ||
| 25 | Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, | ||
| 26 | Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, | ||
| 27 | Qt::Key_M, Qt::Key_N, Qt::Key_B, | ||
| 28 | Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, | ||
| 29 | Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, | ||
| 30 | Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L | ||
| 31 | }; | ||
| 32 | |||
| 24 | void Config::ReadValues() { | 33 | void Config::ReadValues() { |
| 25 | qt_config->beginGroup("Controls"); | 34 | qt_config->beginGroup("Controls"); |
| 26 | Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt(); | 35 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { |
| 27 | Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt(); | 36 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = |
| 28 | Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt(); | 37 | qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt(); |
| 29 | Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt(); | 38 | } |
| 30 | Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt(); | ||
| 31 | Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt(); | ||
| 32 | Settings::values.pad_zl_key = qt_config->value("pad_zl", Qt::Key_1).toInt(); | ||
| 33 | Settings::values.pad_zr_key = qt_config->value("pad_zr", Qt::Key_2).toInt(); | ||
| 34 | Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt(); | ||
| 35 | Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt(); | ||
| 36 | Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt(); | ||
| 37 | Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt(); | ||
| 38 | Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt(); | ||
| 39 | Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt(); | ||
| 40 | Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt(); | ||
| 41 | Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt(); | ||
| 42 | Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).toInt(); | ||
| 43 | Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt(); | ||
| 44 | Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt(); | ||
| 45 | Settings::values.pad_cup_key = qt_config->value("pad_cup", Qt::Key_I).toInt(); | ||
| 46 | Settings::values.pad_cdown_key = qt_config->value("pad_cdown", Qt::Key_K).toInt(); | ||
| 47 | Settings::values.pad_cleft_key = qt_config->value("pad_cleft", Qt::Key_J).toInt(); | ||
| 48 | Settings::values.pad_cright_key = qt_config->value("pad_cright", Qt::Key_L).toInt(); | ||
| 49 | qt_config->endGroup(); | 39 | qt_config->endGroup(); |
| 50 | 40 | ||
| 51 | qt_config->beginGroup("Core"); | 41 | qt_config->beginGroup("Core"); |
| @@ -75,29 +65,10 @@ void Config::ReadValues() { | |||
| 75 | 65 | ||
| 76 | void Config::SaveValues() { | 66 | void Config::SaveValues() { |
| 77 | qt_config->beginGroup("Controls"); | 67 | qt_config->beginGroup("Controls"); |
| 78 | qt_config->setValue("pad_a", Settings::values.pad_a_key); | 68 | for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { |
| 79 | qt_config->setValue("pad_b", Settings::values.pad_b_key); | 69 | qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]), |
| 80 | qt_config->setValue("pad_x", Settings::values.pad_x_key); | 70 | Settings::values.input_mappings[Settings::NativeInput::All[i]]); |
| 81 | qt_config->setValue("pad_y", Settings::values.pad_y_key); | 71 | } |
| 82 | qt_config->setValue("pad_l", Settings::values.pad_l_key); | ||
| 83 | qt_config->setValue("pad_r", Settings::values.pad_r_key); | ||
| 84 | qt_config->setValue("pad_zl", Settings::values.pad_zl_key); | ||
| 85 | qt_config->setValue("pad_zr", Settings::values.pad_zr_key); | ||
| 86 | qt_config->setValue("pad_start", Settings::values.pad_start_key); | ||
| 87 | qt_config->setValue("pad_select", Settings::values.pad_select_key); | ||
| 88 | qt_config->setValue("pad_home", Settings::values.pad_home_key); | ||
| 89 | qt_config->setValue("pad_dup", Settings::values.pad_dup_key); | ||
| 90 | qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key); | ||
| 91 | qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key); | ||
| 92 | qt_config->setValue("pad_dright", Settings::values.pad_dright_key); | ||
| 93 | qt_config->setValue("pad_sup", Settings::values.pad_sup_key); | ||
| 94 | qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key); | ||
| 95 | qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key); | ||
| 96 | qt_config->setValue("pad_sright", Settings::values.pad_sright_key); | ||
| 97 | qt_config->setValue("pad_cup", Settings::values.pad_cup_key); | ||
| 98 | qt_config->setValue("pad_cdown", Settings::values.pad_cdown_key); | ||
| 99 | qt_config->setValue("pad_cleft", Settings::values.pad_cleft_key); | ||
| 100 | qt_config->setValue("pad_cright", Settings::values.pad_cright_key); | ||
| 101 | qt_config->endGroup(); | 72 | qt_config->endGroup(); |
| 102 | 73 | ||
| 103 | qt_config->beginGroup("Core"); | 74 | qt_config->beginGroup("Core"); |
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h index 4485cae73..dd0b2ef0b 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/config.h | |||
| @@ -4,9 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <QSettings> | 7 | #include <string> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | class QSettings; |
| 10 | 10 | ||
| 11 | class Config { | 11 | class Config { |
| 12 | QSettings* qt_config; | 12 | QSettings* qt_config; |
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index e99ec1b30..1e5ef5299 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 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 <QShortcut> | ||
| 6 | |||
| 5 | #include "disassembler.h" | 7 | #include "disassembler.h" |
| 6 | 8 | ||
| 7 | #include "../bootmanager.h" | 9 | #include "../bootmanager.h" |
| @@ -13,7 +15,6 @@ | |||
| 13 | #include "common/break_points.h" | 15 | #include "common/break_points.h" |
| 14 | #include "common/symbols.h" | 16 | #include "common/symbols.h" |
| 15 | #include "core/arm/arm_interface.h" | 17 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 17 | #include "core/arm/disassembler/arm_disasm.h" | 18 | #include "core/arm/disassembler/arm_disasm.h" |
| 18 | 19 | ||
| 19 | 20 | ||
| @@ -217,7 +218,7 @@ void DisassemblerWidget::OnToggleStartStop() { | |||
| 217 | } | 218 | } |
| 218 | 219 | ||
| 219 | void DisassemblerWidget::OnDebugModeEntered() { | 220 | void DisassemblerWidget::OnDebugModeEntered() { |
| 220 | ARMword next_instr = Core::g_app_core->GetPC(); | 221 | u32 next_instr = Core::g_app_core->GetPC(); |
| 221 | 222 | ||
| 222 | if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) | 223 | if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) |
| 223 | emu_thread->SetRunning(false); | 224 | emu_thread->SetRunning(false); |
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics_breakpoint_observer.h index f0d3361f8..02a0f4f4f 100644 --- a/src/citra_qt/debugger/graphics_breakpoint_observer.h +++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while | 13 | * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while |
| 14 | * the widget usually wants to perform reactions in the GUI thread. | 14 | * the widget usually wants to perform reactions in the GUI thread. |
| 15 | */ | 15 | */ |
| 16 | class BreakPointObserverDock : public QDockWidget, private Pica::DebugContext::BreakPointObserver { | 16 | class BreakPointObserverDock : public QDockWidget, protected Pica::DebugContext::BreakPointObserver { |
| 17 | Q_OBJECT | 17 | Q_OBJECT |
| 18 | 18 | ||
| 19 | public: | 19 | public: |
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 1da64f616..5202c168c 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <QMetaType> | 5 | #include <QMetaType> |
| 6 | #include <QPushButton> | 6 | #include <QPushButton> |
| 7 | #include <QTreeWidget> | 7 | #include <QTreeView> |
| 8 | #include <QVBoxLayout> | 8 | #include <QVBoxLayout> |
| 9 | #include <QLabel> | 9 | #include <QLabel> |
| 10 | 10 | ||
| @@ -23,7 +23,7 @@ BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_conte | |||
| 23 | 23 | ||
| 24 | int BreakPointModel::columnCount(const QModelIndex& parent) const | 24 | int BreakPointModel::columnCount(const QModelIndex& parent) const |
| 25 | { | 25 | { |
| 26 | return 2; | 26 | return 1; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | int BreakPointModel::rowCount(const QModelIndex& parent) const | 29 | int BreakPointModel::rowCount(const QModelIndex& parent) const |
| @@ -38,29 +38,29 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const | |||
| 38 | switch (role) { | 38 | switch (role) { |
| 39 | case Qt::DisplayRole: | 39 | case Qt::DisplayRole: |
| 40 | { | 40 | { |
| 41 | switch (index.column()) { | 41 | if (index.column() == 0) { |
| 42 | case 0: | ||
| 43 | { | ||
| 44 | static const std::map<Pica::DebugContext::Event, QString> map = { | 42 | static const std::map<Pica::DebugContext::Event, QString> map = { |
| 45 | { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") }, | 43 | { Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded") }, |
| 46 | { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") }, | 44 | { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") }, |
| 47 | { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, | 45 | { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, |
| 48 | { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, | 46 | { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, |
| 49 | { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") } | 47 | { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") }, |
| 48 | { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") }, | ||
| 49 | { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") }, | ||
| 50 | { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") } | ||
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); | 53 | DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); |
| 53 | |||
| 54 | return (map.find(event) != map.end()) ? map.at(event) : QString(); | 54 | return (map.find(event) != map.end()) ? map.at(event) : QString(); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | case 1: | 57 | break; |
| 58 | return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled"); | 58 | } |
| 59 | |||
| 60 | default: | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | 59 | ||
| 60 | case Qt::CheckStateRole: | ||
| 61 | { | ||
| 62 | if (index.column() == 0) | ||
| 63 | return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked; | ||
| 64 | break; | 64 | break; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| @@ -84,37 +84,34 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const | |||
| 84 | return QVariant(); | 84 | return QVariant(); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const | 87 | Qt::ItemFlags BreakPointModel::flags(const QModelIndex &index) const |
| 88 | { | 88 | { |
| 89 | switch(role) { | 89 | if (!index.isValid()) |
| 90 | case Qt::DisplayRole: | 90 | return 0; |
| 91 | { | ||
| 92 | if (section == 0) { | ||
| 93 | return tr("Event"); | ||
| 94 | } else if (section == 1) { | ||
| 95 | return tr("Status"); | ||
| 96 | } | ||
| 97 | |||
| 98 | break; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | 91 | ||
| 102 | return QVariant(); | 92 | Qt::ItemFlags flags = Qt::ItemIsEnabled; |
| 93 | if (index.column() == 0) | ||
| 94 | flags |= Qt::ItemIsUserCheckable; | ||
| 95 | return flags; | ||
| 103 | } | 96 | } |
| 104 | 97 | ||
| 98 | |||
| 105 | bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) | 99 | bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) |
| 106 | { | 100 | { |
| 107 | const auto event = static_cast<Pica::DebugContext::Event>(index.row()); | 101 | const auto event = static_cast<Pica::DebugContext::Event>(index.row()); |
| 108 | 102 | ||
| 109 | switch (role) { | 103 | switch (role) { |
| 110 | case Role_IsEnabled: | 104 | case Qt::CheckStateRole: |
| 111 | { | 105 | { |
| 106 | if (index.column() != 0) | ||
| 107 | return false; | ||
| 108 | |||
| 112 | auto context = context_weak.lock(); | 109 | auto context = context_weak.lock(); |
| 113 | if (!context) | 110 | if (!context) |
| 114 | return false; | 111 | return false; |
| 115 | 112 | ||
| 116 | context->breakpoints[event].enabled = value.toBool(); | 113 | context->breakpoints[event].enabled = value == Qt::Checked; |
| 117 | QModelIndex changed_index = createIndex(index.row(), 1); | 114 | QModelIndex changed_index = createIndex(index.row(), 0); |
| 118 | emit dataChanged(changed_index, changed_index); | 115 | emit dataChanged(changed_index, changed_index); |
| 119 | return true; | 116 | return true; |
| 120 | } | 117 | } |
| @@ -133,7 +130,7 @@ void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event) | |||
| 133 | active_breakpoint = context->active_breakpoint; | 130 | active_breakpoint = context->active_breakpoint; |
| 134 | at_breakpoint = context->at_breakpoint; | 131 | at_breakpoint = context->at_breakpoint; |
| 135 | emit dataChanged(createIndex(static_cast<int>(event), 0), | 132 | emit dataChanged(createIndex(static_cast<int>(event), 0), |
| 136 | createIndex(static_cast<int>(event), 1)); | 133 | createIndex(static_cast<int>(event), 0)); |
| 137 | } | 134 | } |
| 138 | 135 | ||
| 139 | void BreakPointModel::OnResumed() | 136 | void BreakPointModel::OnResumed() |
| @@ -144,7 +141,7 @@ void BreakPointModel::OnResumed() | |||
| 144 | 141 | ||
| 145 | at_breakpoint = context->at_breakpoint; | 142 | at_breakpoint = context->at_breakpoint; |
| 146 | emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0), | 143 | emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0), |
| 147 | createIndex(static_cast<int>(active_breakpoint), 1)); | 144 | createIndex(static_cast<int>(active_breakpoint), 0)); |
| 148 | active_breakpoint = context->active_breakpoint; | 145 | active_breakpoint = context->active_breakpoint; |
| 149 | } | 146 | } |
| 150 | 147 | ||
| @@ -162,13 +159,15 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug | |||
| 162 | 159 | ||
| 163 | breakpoint_model = new BreakPointModel(debug_context, this); | 160 | breakpoint_model = new BreakPointModel(debug_context, this); |
| 164 | breakpoint_list = new QTreeView; | 161 | breakpoint_list = new QTreeView; |
| 162 | breakpoint_list->setRootIsDecorated(false); | ||
| 163 | breakpoint_list->setHeaderHidden(true); | ||
| 165 | breakpoint_list->setModel(breakpoint_model); | 164 | breakpoint_list->setModel(breakpoint_model); |
| 166 | 165 | ||
| 167 | toggle_breakpoint_button = new QPushButton(tr("Enable")); | ||
| 168 | toggle_breakpoint_button->setEnabled(false); | ||
| 169 | |||
| 170 | qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); | 166 | qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); |
| 171 | 167 | ||
| 168 | connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)), | ||
| 169 | this, SLOT(OnItemDoubleClicked(const QModelIndex&))); | ||
| 170 | |||
| 172 | connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); | 171 | connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); |
| 173 | 172 | ||
| 174 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), | 173 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), |
| @@ -184,11 +183,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug | |||
| 184 | connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)), | 183 | connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)), |
| 185 | breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); | 184 | breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); |
| 186 | 185 | ||
| 187 | connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), | ||
| 188 | this, SLOT(OnBreakpointSelectionChanged(QModelIndex))); | ||
| 189 | |||
| 190 | connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled())); | ||
| 191 | |||
| 192 | QWidget* main_widget = new QWidget; | 186 | QWidget* main_widget = new QWidget; |
| 193 | auto main_layout = new QVBoxLayout; | 187 | auto main_layout = new QVBoxLayout; |
| 194 | { | 188 | { |
| @@ -198,7 +192,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug | |||
| 198 | main_layout->addLayout(sub_layout); | 192 | main_layout->addLayout(sub_layout); |
| 199 | } | 193 | } |
| 200 | main_layout->addWidget(breakpoint_list); | 194 | main_layout->addWidget(breakpoint_list); |
| 201 | main_layout->addWidget(toggle_breakpoint_button); | ||
| 202 | main_widget->setLayout(main_layout); | 195 | main_widget->setLayout(main_layout); |
| 203 | 196 | ||
| 204 | setWidget(main_widget); | 197 | setWidget(main_widget); |
| @@ -234,32 +227,15 @@ void GraphicsBreakPointsWidget::OnResumeRequested() | |||
| 234 | context->Resume(); | 227 | context->Resume(); |
| 235 | } | 228 | } |
| 236 | 229 | ||
| 237 | void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index) | 230 | void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index) |
| 238 | { | 231 | { |
| 239 | if (!index.isValid()) { | 232 | if (!index.isValid()) |
| 240 | toggle_breakpoint_button->setEnabled(false); | ||
| 241 | return; | 233 | return; |
| 242 | } | ||
| 243 | 234 | ||
| 244 | toggle_breakpoint_button->setEnabled(true); | 235 | QModelIndex check_index = breakpoint_list->model()->index(index.row(), 0); |
| 245 | UpdateToggleBreakpointButton(index); | 236 | QVariant enabled = breakpoint_list->model()->data(check_index, Qt::CheckStateRole); |
| 246 | } | 237 | QVariant new_state = Qt::Unchecked; |
| 247 | 238 | if (enabled == Qt::Unchecked) | |
| 248 | void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled() | 239 | new_state = Qt::Checked; |
| 249 | { | 240 | breakpoint_list->model()->setData(check_index, new_state, Qt::CheckStateRole); |
| 250 | QModelIndex index = breakpoint_list->selectionModel()->currentIndex(); | ||
| 251 | bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()); | ||
| 252 | |||
| 253 | breakpoint_model->setData(index, new_state, | ||
| 254 | BreakPointModel::Role_IsEnabled); | ||
| 255 | UpdateToggleBreakpointButton(index); | ||
| 256 | } | ||
| 257 | |||
| 258 | void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index) | ||
| 259 | { | ||
| 260 | if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) { | ||
| 261 | toggle_breakpoint_button->setText(tr("Disable")); | ||
| 262 | } else { | ||
| 263 | toggle_breakpoint_button->setText(tr("Enable")); | ||
| 264 | } | ||
| 265 | } | 241 | } |
diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics_breakpoints.h index 5b9ba324e..d900729da 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.h +++ b/src/citra_qt/debugger/graphics_breakpoints.h | |||
| @@ -31,10 +31,9 @@ public: | |||
| 31 | 31 | ||
| 32 | public slots: | 32 | public slots: |
| 33 | void OnBreakPointHit(Pica::DebugContext::Event event, void* data); | 33 | void OnBreakPointHit(Pica::DebugContext::Event event, void* data); |
| 34 | void OnItemDoubleClicked(const QModelIndex&); | ||
| 34 | void OnResumeRequested(); | 35 | void OnResumeRequested(); |
| 35 | void OnResumed(); | 36 | void OnResumed(); |
| 36 | void OnBreakpointSelectionChanged(const QModelIndex&); | ||
| 37 | void OnToggleBreakpointEnabled(); | ||
| 38 | 37 | ||
| 39 | signals: | 38 | signals: |
| 40 | void Resumed(); | 39 | void Resumed(); |
| @@ -42,11 +41,8 @@ signals: | |||
| 42 | void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); | 41 | void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); |
| 43 | 42 | ||
| 44 | private: | 43 | private: |
| 45 | void UpdateToggleBreakpointButton(const QModelIndex& index); | ||
| 46 | |||
| 47 | QLabel* status_text; | 44 | QLabel* status_text; |
| 48 | QPushButton* resume_button; | 45 | QPushButton* resume_button; |
| 49 | QPushButton* toggle_breakpoint_button; | ||
| 50 | 46 | ||
| 51 | BreakPointModel* breakpoint_model; | 47 | BreakPointModel* breakpoint_model; |
| 52 | QTreeView* breakpoint_list; | 48 | QTreeView* breakpoint_list; |
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h index 34e72e859..00d8d5101 100644 --- a/src/citra_qt/debugger/graphics_breakpoints_p.h +++ b/src/citra_qt/debugger/graphics_breakpoints_p.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; | 23 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| 24 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 24 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 25 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | 25 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 26 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | 26 | Qt::ItemFlags flags(const QModelIndex &index) const; |
| 27 | 27 | ||
| 28 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; | 28 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; |
| 29 | 29 | ||
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index cabf5fe07..7ac3ea542 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp | |||
| @@ -2,12 +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 <QApplication> | ||
| 6 | #include <QClipboard> | ||
| 5 | #include <QLabel> | 7 | #include <QLabel> |
| 6 | #include <QListView> | 8 | #include <QListView> |
| 7 | #include <QMainWindow> | 9 | #include <QMainWindow> |
| 8 | #include <QPushButton> | 10 | #include <QPushButton> |
| 9 | #include <QVBoxLayout> | 11 | #include <QVBoxLayout> |
| 10 | #include <QTreeView> | 12 | #include <QTreeView> |
| 13 | #include <QHeaderView> | ||
| 11 | #include <QSpinBox> | 14 | #include <QSpinBox> |
| 12 | #include <QComboBox> | 15 | #include <QComboBox> |
| 13 | 16 | ||
| @@ -74,7 +77,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo | |||
| 74 | format_choice->addItem(tr("I8")); | 77 | format_choice->addItem(tr("I8")); |
| 75 | format_choice->addItem(tr("A8")); | 78 | format_choice->addItem(tr("A8")); |
| 76 | format_choice->addItem(tr("IA4")); | 79 | format_choice->addItem(tr("IA4")); |
| 77 | format_choice->addItem(tr("UNK10")); | 80 | format_choice->addItem(tr("I4")); |
| 78 | format_choice->addItem(tr("A4")); | 81 | format_choice->addItem(tr("A4")); |
| 79 | format_choice->addItem(tr("ETC1")); | 82 | format_choice->addItem(tr("ETC1")); |
| 80 | format_choice->addItem(tr("ETC1A4")); | 83 | format_choice->addItem(tr("ETC1A4")); |
| @@ -168,11 +171,11 @@ GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(p | |||
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const { | 173 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const { |
| 171 | return pica_trace.writes.size(); | 174 | return static_cast<int>(pica_trace.writes.size()); |
| 172 | } | 175 | } |
| 173 | 176 | ||
| 174 | int GPUCommandListModel::columnCount(const QModelIndex& parent) const { | 177 | int GPUCommandListModel::columnCount(const QModelIndex& parent) const { |
| 175 | return 2; | 178 | return 3; |
| 176 | } | 179 | } |
| 177 | 180 | ||
| 178 | QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | 181 | QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { |
| @@ -185,14 +188,13 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | |||
| 185 | 188 | ||
| 186 | if (role == Qt::DisplayRole) { | 189 | if (role == Qt::DisplayRole) { |
| 187 | QString content; | 190 | QString content; |
| 188 | if (index.column() == 0) { | 191 | switch ( index.column() ) { |
| 189 | QString content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); | 192 | case 0: |
| 190 | content.append(" "); | 193 | return QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); |
| 191 | return content; | 194 | case 1: |
| 192 | } else if (index.column() == 1) { | 195 | return QString("%1").arg(cmd.cmd_id, 3, 16, QLatin1Char('0')); |
| 193 | QString content = QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0')); | 196 | case 2: |
| 194 | content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0'))); | 197 | return QString("%1").arg(val, 8, 16, QLatin1Char('0')); |
| 195 | return content; | ||
| 196 | } | 198 | } |
| 197 | } else if (role == CommandIdRole) { | 199 | } else if (role == CommandIdRole) { |
| 198 | return QVariant::fromValue<int>(cmd.cmd_id.Value()); | 200 | return QVariant::fromValue<int>(cmd.cmd_id.Value()); |
| @@ -205,10 +207,13 @@ QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientatio | |||
| 205 | switch(role) { | 207 | switch(role) { |
| 206 | case Qt::DisplayRole: | 208 | case Qt::DisplayRole: |
| 207 | { | 209 | { |
| 208 | if (section == 0) { | 210 | switch (section) { |
| 211 | case 0: | ||
| 209 | return tr("Command Name"); | 212 | return tr("Command Name"); |
| 210 | } else if (section == 1) { | 213 | case 1: |
| 211 | return tr("Data"); | 214 | return tr("Register"); |
| 215 | case 2: | ||
| 216 | return tr("New Value"); | ||
| 212 | } | 217 | } |
| 213 | 218 | ||
| 214 | break; | 219 | break; |
| @@ -297,6 +302,13 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi | |||
| 297 | list_widget->setModel(model); | 302 | list_widget->setModel(model); |
| 298 | list_widget->setFont(QFont("monospace")); | 303 | list_widget->setFont(QFont("monospace")); |
| 299 | list_widget->setRootIsDecorated(false); | 304 | list_widget->setRootIsDecorated(false); |
| 305 | list_widget->setUniformRowHeights(true); | ||
| 306 | |||
| 307 | #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) | ||
| 308 | list_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents); | ||
| 309 | #else | ||
| 310 | list_widget->header()->setResizeMode(QHeaderView::ResizeToContents); | ||
| 311 | #endif | ||
| 300 | 312 | ||
| 301 | connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), | 313 | connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), |
| 302 | this, SLOT(SetCommandInfo(const QModelIndex&))); | 314 | this, SLOT(SetCommandInfo(const QModelIndex&))); |
| @@ -304,16 +316,24 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi | |||
| 304 | this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); | 316 | this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); |
| 305 | 317 | ||
| 306 | toggle_tracing = new QPushButton(tr("Start Tracing")); | 318 | toggle_tracing = new QPushButton(tr("Start Tracing")); |
| 319 | QPushButton* copy_all = new QPushButton(tr("Copy All")); | ||
| 307 | 320 | ||
| 308 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); | 321 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); |
| 309 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), | 322 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), |
| 310 | model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); | 323 | model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); |
| 311 | 324 | ||
| 325 | connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); | ||
| 326 | |||
| 312 | command_info_widget = new QWidget; | 327 | command_info_widget = new QWidget; |
| 313 | 328 | ||
| 314 | QVBoxLayout* main_layout = new QVBoxLayout; | 329 | QVBoxLayout* main_layout = new QVBoxLayout; |
| 315 | main_layout->addWidget(list_widget); | 330 | main_layout->addWidget(list_widget); |
| 316 | main_layout->addWidget(toggle_tracing); | 331 | { |
| 332 | QHBoxLayout* sub_layout = new QHBoxLayout; | ||
| 333 | sub_layout->addWidget(toggle_tracing); | ||
| 334 | sub_layout->addWidget(copy_all); | ||
| 335 | main_layout->addLayout(sub_layout); | ||
| 336 | } | ||
| 317 | main_layout->addWidget(command_info_widget); | 337 | main_layout->addWidget(command_info_widget); |
| 318 | main_widget->setLayout(main_layout); | 338 | main_widget->setLayout(main_layout); |
| 319 | 339 | ||
| @@ -330,3 +350,21 @@ void GPUCommandListWidget::OnToggleTracing() { | |||
| 330 | toggle_tracing->setText(tr("Start Tracing")); | 350 | toggle_tracing->setText(tr("Start Tracing")); |
| 331 | } | 351 | } |
| 332 | } | 352 | } |
| 353 | |||
| 354 | void GPUCommandListWidget::CopyAllToClipboard() { | ||
| 355 | QClipboard* clipboard = QApplication::clipboard(); | ||
| 356 | QString text; | ||
| 357 | |||
| 358 | QAbstractItemModel* model = static_cast<QAbstractListModel*>(list_widget->model()); | ||
| 359 | |||
| 360 | for (int row = 0; row < model->rowCount({}); ++row) { | ||
| 361 | for (int col = 0; col < model->columnCount({}); ++col) { | ||
| 362 | QModelIndex index = model->index(row, col); | ||
| 363 | text += model->data(index).value<QString>(); | ||
| 364 | text += '\t'; | ||
| 365 | } | ||
| 366 | text += '\n'; | ||
| 367 | } | ||
| 368 | |||
| 369 | clipboard->setText(text); | ||
| 370 | } | ||
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h index a465d044c..4859b6ec8 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.h +++ b/src/citra_qt/debugger/graphics_cmdlists.h | |||
| @@ -49,6 +49,8 @@ public slots: | |||
| 49 | 49 | ||
| 50 | void SetCommandInfo(const QModelIndex&); | 50 | void SetCommandInfo(const QModelIndex&); |
| 51 | 51 | ||
| 52 | void CopyAllToClipboard(); | ||
| 53 | |||
| 52 | signals: | 54 | signals: |
| 53 | void TracingFinished(const Pica::DebugUtils::PicaTrace&); | 55 | void TracingFinished(const Pica::DebugUtils::PicaTrace&); |
| 54 | 56 | ||
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index 6bbe7572c..39eefbf75 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp | |||
| @@ -55,7 +55,9 @@ GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::Debug | |||
| 55 | framebuffer_format_control->addItem(tr("RGBA4")); | 55 | framebuffer_format_control->addItem(tr("RGBA4")); |
| 56 | framebuffer_format_control->addItem(tr("D16")); | 56 | framebuffer_format_control->addItem(tr("D16")); |
| 57 | framebuffer_format_control->addItem(tr("D24")); | 57 | framebuffer_format_control->addItem(tr("D24")); |
| 58 | framebuffer_format_control->addItem(tr("D24S8")); | 58 | framebuffer_format_control->addItem(tr("D24X8")); |
| 59 | framebuffer_format_control->addItem(tr("X24S8")); | ||
| 60 | framebuffer_format_control->addItem(tr("(unknown)")); | ||
| 59 | 61 | ||
| 60 | // TODO: This QLabel should shrink the image to the available space rather than just expanding... | 62 | // TODO: This QLabel should shrink the image to the available space rather than just expanding... |
| 61 | framebuffer_picture_label = new QLabel; | 63 | framebuffer_picture_label = new QLabel; |
| @@ -184,8 +186,32 @@ void GraphicsFramebufferWidget::OnUpdate() | |||
| 184 | framebuffer_address = framebuffer.GetColorBufferPhysicalAddress(); | 186 | framebuffer_address = framebuffer.GetColorBufferPhysicalAddress(); |
| 185 | framebuffer_width = framebuffer.GetWidth(); | 187 | framebuffer_width = framebuffer.GetWidth(); |
| 186 | framebuffer_height = framebuffer.GetHeight(); | 188 | framebuffer_height = framebuffer.GetHeight(); |
| 187 | // TODO: It's unknown how this format is actually specified | 189 | |
| 188 | framebuffer_format = Format::RGBA8; | 190 | switch (framebuffer.color_format) { |
| 191 | case Pica::Regs::ColorFormat::RGBA8: | ||
| 192 | framebuffer_format = Format::RGBA8; | ||
| 193 | break; | ||
| 194 | |||
| 195 | case Pica::Regs::ColorFormat::RGB8: | ||
| 196 | framebuffer_format = Format::RGB8; | ||
| 197 | break; | ||
| 198 | |||
| 199 | case Pica::Regs::ColorFormat::RGB5A1: | ||
| 200 | framebuffer_format = Format::RGB5A1; | ||
| 201 | break; | ||
| 202 | |||
| 203 | case Pica::Regs::ColorFormat::RGB565: | ||
| 204 | framebuffer_format = Format::RGB565; | ||
| 205 | break; | ||
| 206 | |||
| 207 | case Pica::Regs::ColorFormat::RGBA4: | ||
| 208 | framebuffer_format = Format::RGBA4; | ||
| 209 | break; | ||
| 210 | |||
| 211 | default: | ||
| 212 | framebuffer_format = Format::Unknown; | ||
| 213 | break; | ||
| 214 | } | ||
| 189 | 215 | ||
| 190 | break; | 216 | break; |
| 191 | } | 217 | } |
| @@ -197,7 +223,24 @@ void GraphicsFramebufferWidget::OnUpdate() | |||
| 197 | framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress(); | 223 | framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress(); |
| 198 | framebuffer_width = framebuffer.GetWidth(); | 224 | framebuffer_width = framebuffer.GetWidth(); |
| 199 | framebuffer_height = framebuffer.GetHeight(); | 225 | framebuffer_height = framebuffer.GetHeight(); |
| 200 | framebuffer_format = Format::D16; | 226 | |
| 227 | switch (framebuffer.depth_format) { | ||
| 228 | case Pica::Regs::DepthFormat::D16: | ||
| 229 | framebuffer_format = Format::D16; | ||
| 230 | break; | ||
| 231 | |||
| 232 | case Pica::Regs::DepthFormat::D24: | ||
| 233 | framebuffer_format = Format::D24; | ||
| 234 | break; | ||
| 235 | |||
| 236 | case Pica::Regs::DepthFormat::D24S8: | ||
| 237 | framebuffer_format = Format::D24X8; | ||
| 238 | break; | ||
| 239 | |||
| 240 | default: | ||
| 241 | framebuffer_format = Format::Unknown; | ||
| 242 | break; | ||
| 243 | } | ||
| 201 | 244 | ||
| 202 | break; | 245 | break; |
| 203 | } | 246 | } |
| @@ -258,7 +301,7 @@ void GraphicsFramebufferWidget::OnUpdate() | |||
| 258 | color.b() = (data >> 16) & 0xFF; | 301 | color.b() = (data >> 16) & 0xFF; |
| 259 | break; | 302 | break; |
| 260 | } | 303 | } |
| 261 | case Format::D24S8: | 304 | case Format::D24X8: |
| 262 | { | 305 | { |
| 263 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); | 306 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); |
| 264 | color.r() = data.x & 0xFF; | 307 | color.r() = data.x & 0xFF; |
| @@ -266,6 +309,12 @@ void GraphicsFramebufferWidget::OnUpdate() | |||
| 266 | color.b() = (data.x >> 16) & 0xFF; | 309 | color.b() = (data.x >> 16) & 0xFF; |
| 267 | break; | 310 | break; |
| 268 | } | 311 | } |
| 312 | case Format::X24S8: | ||
| 313 | { | ||
| 314 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); | ||
| 315 | color.r() = color.g() = color.b() = data.y; | ||
| 316 | break; | ||
| 317 | } | ||
| 269 | default: | 318 | default: |
| 270 | qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); | 319 | qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); |
| 271 | break; | 320 | break; |
| @@ -286,7 +335,8 @@ void GraphicsFramebufferWidget::OnUpdate() | |||
| 286 | u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) { | 335 | u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) { |
| 287 | switch (format) { | 336 | switch (format) { |
| 288 | case Format::RGBA8: | 337 | case Format::RGBA8: |
| 289 | case Format::D24S8: | 338 | case Format::D24X8: |
| 339 | case Format::X24S8: | ||
| 290 | return 4; | 340 | return 4; |
| 291 | case Format::RGB8: | 341 | case Format::RGB8: |
| 292 | case Format::D24: | 342 | case Format::D24: |
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h index 4cb396ffe..e9eae679f 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.h +++ b/src/citra_qt/debugger/graphics_framebuffer.h | |||
| @@ -35,7 +35,9 @@ class GraphicsFramebufferWidget : public BreakPointObserverDock { | |||
| 35 | RGBA4 = 4, | 35 | RGBA4 = 4, |
| 36 | D16 = 5, | 36 | D16 = 5, |
| 37 | D24 = 6, | 37 | D24 = 6, |
| 38 | D24S8 = 7 | 38 | D24X8 = 7, |
| 39 | X24S8 = 8, | ||
| 40 | Unknown = 9 | ||
| 39 | }; | 41 | }; |
| 40 | 42 | ||
| 41 | static u32 BytesPerPixel(Format format); | 43 | static u32 BytesPerPixel(Format format); |
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp new file mode 100644 index 000000000..3f20f149d --- /dev/null +++ b/src/citra_qt/debugger/graphics_tracing.cpp | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | |||
| 7 | #include <QBoxLayout> | ||
| 8 | #include <QComboBox> | ||
| 9 | #include <QFileDialog> | ||
| 10 | #include <QLabel> | ||
| 11 | #include <QMessageBox> | ||
| 12 | #include <QPushButton> | ||
| 13 | #include <QSpinBox> | ||
| 14 | |||
| 15 | #include <boost/range/algorithm/copy.hpp> | ||
| 16 | |||
| 17 | #include "core/hw/gpu.h" | ||
| 18 | #include "core/hw/lcd.h" | ||
| 19 | |||
| 20 | #include "video_core/pica.h" | ||
| 21 | |||
| 22 | #include "nihstro/float24.h" | ||
| 23 | |||
| 24 | #include "graphics_tracing.h" | ||
| 25 | |||
| 26 | GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, | ||
| 27 | QWidget* parent) | ||
| 28 | : BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) { | ||
| 29 | |||
| 30 | setObjectName("CiTracing"); | ||
| 31 | |||
| 32 | QPushButton* start_recording = new QPushButton(tr("Start Recording")); | ||
| 33 | QPushButton* stop_recording = new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save")); | ||
| 34 | QPushButton* abort_recording = new QPushButton(tr("Abort Recording")); | ||
| 35 | |||
| 36 | connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, SLOT(setVisible(bool))); | ||
| 37 | connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, SLOT(setVisible(bool))); | ||
| 38 | connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, SLOT(setVisible(bool))); | ||
| 39 | connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording())); | ||
| 40 | connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording())); | ||
| 41 | connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording())); | ||
| 42 | |||
| 43 | stop_recording->setVisible(false); | ||
| 44 | abort_recording->setVisible(false); | ||
| 45 | |||
| 46 | auto main_widget = new QWidget; | ||
| 47 | auto main_layout = new QVBoxLayout; | ||
| 48 | { | ||
| 49 | auto sub_layout = new QHBoxLayout; | ||
| 50 | sub_layout->addWidget(start_recording); | ||
| 51 | sub_layout->addWidget(stop_recording); | ||
| 52 | sub_layout->addWidget(abort_recording); | ||
| 53 | main_layout->addLayout(sub_layout); | ||
| 54 | } | ||
| 55 | main_widget->setLayout(main_layout); | ||
| 56 | setWidget(main_widget); | ||
| 57 | } | ||
| 58 | |||
| 59 | void GraphicsTracingWidget::StartRecording() { | ||
| 60 | auto context = context_weak.lock(); | ||
| 61 | if (!context) | ||
| 62 | return; | ||
| 63 | |||
| 64 | auto shader_binary = Pica::g_state.vs.program_code; | ||
| 65 | auto swizzle_data = Pica::g_state.vs.swizzle_data; | ||
| 66 | |||
| 67 | // Encode floating point numbers to 24-bit values | ||
| 68 | // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally. | ||
| 69 | std::array<uint32_t, 4 * 16> default_attributes; | ||
| 70 | for (unsigned i = 0; i < 16; ++i) { | ||
| 71 | for (unsigned comp = 0; comp < 3; ++comp) { | ||
| 72 | default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32()); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | std::array<uint32_t, 4 * 96> vs_float_uniforms; | ||
| 77 | for (unsigned i = 0; i < 96; ++i) | ||
| 78 | for (unsigned comp = 0; comp < 3; ++comp) | ||
| 79 | vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); | ||
| 80 | |||
| 81 | CiTrace::Recorder::InitialState state; | ||
| 82 | std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), std::back_inserter(state.gpu_registers)); | ||
| 83 | std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), std::back_inserter(state.lcd_registers)); | ||
| 84 | std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), std::back_inserter(state.pica_registers)); | ||
| 85 | boost::copy(default_attributes, std::back_inserter(state.default_attributes)); | ||
| 86 | boost::copy(shader_binary, std::back_inserter(state.vs_program_binary)); | ||
| 87 | boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data)); | ||
| 88 | boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms)); | ||
| 89 | //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary)); | ||
| 90 | //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data)); | ||
| 91 | //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms)); | ||
| 92 | |||
| 93 | auto recorder = new CiTrace::Recorder(state); | ||
| 94 | context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder); | ||
| 95 | |||
| 96 | emit SetStartTracingButtonEnabled(false); | ||
| 97 | emit SetStopTracingButtonEnabled(true); | ||
| 98 | emit SetAbortTracingButtonEnabled(true); | ||
| 99 | } | ||
| 100 | |||
| 101 | void GraphicsTracingWidget::StopRecording() { | ||
| 102 | auto context = context_weak.lock(); | ||
| 103 | if (!context) | ||
| 104 | return; | ||
| 105 | |||
| 106 | QString filename = QFileDialog::getSaveFileName(this, tr("Save CiTrace"), "citrace.ctf", | ||
| 107 | tr("CiTrace File (*.ctf)")); | ||
| 108 | |||
| 109 | if (filename.isEmpty()) { | ||
| 110 | // If the user canceled the dialog, keep recording | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | |||
| 114 | context->recorder->Finish(filename.toStdString()); | ||
| 115 | context->recorder = nullptr; | ||
| 116 | |||
| 117 | emit SetStopTracingButtonEnabled(false); | ||
| 118 | emit SetAbortTracingButtonEnabled(false); | ||
| 119 | emit SetStartTracingButtonEnabled(true); | ||
| 120 | } | ||
| 121 | |||
| 122 | void GraphicsTracingWidget::AbortRecording() { | ||
| 123 | auto context = context_weak.lock(); | ||
| 124 | if (!context) | ||
| 125 | return; | ||
| 126 | |||
| 127 | context->recorder = nullptr; | ||
| 128 | |||
| 129 | emit SetStopTracingButtonEnabled(false); | ||
| 130 | emit SetAbortTracingButtonEnabled(false); | ||
| 131 | emit SetStartTracingButtonEnabled(true); | ||
| 132 | } | ||
| 133 | |||
| 134 | void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { | ||
| 135 | widget()->setEnabled(true); | ||
| 136 | } | ||
| 137 | |||
| 138 | void GraphicsTracingWidget::OnResumed() { | ||
| 139 | widget()->setEnabled(false); | ||
| 140 | } | ||
| 141 | |||
| 142 | void GraphicsTracingWidget::OnEmulationStarting(EmuThread* emu_thread) { | ||
| 143 | // Disable tracing starting/stopping until a GPU breakpoint is reached | ||
| 144 | widget()->setEnabled(false); | ||
| 145 | } | ||
| 146 | |||
| 147 | void GraphicsTracingWidget::OnEmulationStopping() { | ||
| 148 | // TODO: Is it safe to access the context here? | ||
| 149 | |||
| 150 | auto context = context_weak.lock(); | ||
| 151 | if (!context) | ||
| 152 | return; | ||
| 153 | |||
| 154 | |||
| 155 | if (context->recorder) { | ||
| 156 | auto reply = QMessageBox::question(this, tr("CiTracing still active"), | ||
| 157 | tr("A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded."), | ||
| 158 | QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); | ||
| 159 | |||
| 160 | if (reply == QMessageBox::Yes) { | ||
| 161 | StopRecording(); | ||
| 162 | } else { | ||
| 163 | AbortRecording(); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | // If the widget was disabled before, enable it now to allow starting | ||
| 168 | // tracing before starting the next emulation session | ||
| 169 | widget()->setEnabled(true); | ||
| 170 | } | ||
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h new file mode 100644 index 000000000..2a0e4819b --- /dev/null +++ b/src/citra_qt/debugger/graphics_tracing.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "graphics_breakpoint_observer.h" | ||
| 8 | |||
| 9 | class EmuThread; | ||
| 10 | |||
| 11 | class GraphicsTracingWidget : public BreakPointObserverDock { | ||
| 12 | Q_OBJECT | ||
| 13 | |||
| 14 | public: | ||
| 15 | GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr); | ||
| 16 | |||
| 17 | private slots: | ||
| 18 | void StartRecording(); | ||
| 19 | void StopRecording(); | ||
| 20 | void AbortRecording(); | ||
| 21 | |||
| 22 | void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override; | ||
| 23 | void OnResumed() override; | ||
| 24 | |||
| 25 | void OnEmulationStarting(EmuThread* emu_thread); | ||
| 26 | void OnEmulationStopping(); | ||
| 27 | |||
| 28 | signals: | ||
| 29 | void SetStartTracingButtonEnabled(bool enable); | ||
| 30 | void SetStopTracingButtonEnabled(bool enable); | ||
| 31 | void SetAbortTracingButtonEnabled(bool enable); | ||
| 32 | }; | ||
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index 14d3f8f39..f42a2f4ce 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp | |||
| @@ -34,7 +34,7 @@ int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { | |||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { | 36 | int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { |
| 37 | return info.code.size(); | 37 | return static_cast<int>(info.code.size()); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { | 40 | QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { |
| @@ -259,7 +259,7 @@ void GraphicsVertexShaderModel::OnUpdate() | |||
| 259 | for (auto pattern : Pica::g_state.vs.swizzle_data) | 259 | for (auto pattern : Pica::g_state.vs.swizzle_data) |
| 260 | info.swizzle_info.push_back({pattern}); | 260 | info.swizzle_info.push_back({pattern}); |
| 261 | 261 | ||
| 262 | info.labels.insert({ Pica::g_state.regs.vs_main_offset, "main" }); | 262 | info.labels.insert({ Pica::g_state.regs.vs.main_offset, "main" }); |
| 263 | 263 | ||
| 264 | endResetModel(); | 264 | endResetModel(); |
| 265 | } | 265 | } |
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp index 2ac1748b7..89b28c2f4 100644 --- a/src/citra_qt/debugger/profiler.cpp +++ b/src/citra_qt/debugger/profiler.cpp | |||
| @@ -74,7 +74,7 @@ int ProfilerModel::rowCount(const QModelIndex& parent) const | |||
| 74 | if (parent.isValid()) { | 74 | if (parent.isValid()) { |
| 75 | return 0; | 75 | return 0; |
| 76 | } else { | 76 | } else { |
| 77 | return results.time_per_category.size() + 2; | 77 | return static_cast<int>(results.time_per_category.size() + 2); |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | 80 | ||
diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp index 322c25c9e..5ed6cf0b1 100644 --- a/src/citra_qt/hotkeys.cpp +++ b/src/citra_qt/hotkeys.cpp | |||
| @@ -2,10 +2,13 @@ | |||
| 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 <map> | ||
| 6 | |||
| 5 | #include <QKeySequence> | 7 | #include <QKeySequence> |
| 6 | #include <QSettings> | 8 | #include <QSettings> |
| 9 | #include <QShortcut> | ||
| 10 | |||
| 7 | #include "hotkeys.h" | 11 | #include "hotkeys.h" |
| 8 | #include <map> | ||
| 9 | 12 | ||
| 10 | struct Hotkey | 13 | struct Hotkey |
| 11 | { | 14 | { |
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h index 75c7cc625..2317f8188 100644 --- a/src/citra_qt/hotkeys.h +++ b/src/citra_qt/hotkeys.h | |||
| @@ -2,12 +2,12 @@ | |||
| 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 <QShortcut> | ||
| 6 | #include <QDialog> | ||
| 7 | #include "ui_hotkeys.h" | 5 | #include "ui_hotkeys.h" |
| 8 | 6 | ||
| 7 | class QDialog; | ||
| 9 | class QKeySequence; | 8 | class QKeySequence; |
| 10 | class QSettings; | 9 | class QSettings; |
| 10 | class QShortcut; | ||
| 11 | 11 | ||
| 12 | /** | 12 | /** |
| 13 | * Register a hotkey. | 13 | * Register a hotkey. |
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 8041816a0..34831f2ec 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -10,18 +10,16 @@ | |||
| 10 | #include "qhexedit.h" | 10 | #include "qhexedit.h" |
| 11 | #include "main.h" | 11 | #include "main.h" |
| 12 | 12 | ||
| 13 | #include "common/string_util.h" | ||
| 13 | #include "common/logging/text_formatter.h" | 14 | #include "common/logging/text_formatter.h" |
| 14 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 15 | #include "common/logging/backend.h" | 16 | #include "common/logging/backend.h" |
| 16 | #include "common/logging/filter.h" | 17 | #include "common/logging/filter.h" |
| 17 | #include "common/make_unique.h" | 18 | #include "common/make_unique.h" |
| 18 | #include "common/platform.h" | 19 | #include "common/platform.h" |
| 20 | #include "common/scm_rev.h" | ||
| 19 | #include "common/scope_exit.h" | 21 | #include "common/scope_exit.h" |
| 20 | 22 | ||
| 21 | #if EMU_PLATFORM == PLATFORM_LINUX | ||
| 22 | #include <unistd.h> | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #include "bootmanager.h" | 23 | #include "bootmanager.h" |
| 26 | #include "hotkeys.h" | 24 | #include "hotkeys.h" |
| 27 | 25 | ||
| @@ -34,6 +32,7 @@ | |||
| 34 | #include "debugger/graphics_breakpoints.h" | 32 | #include "debugger/graphics_breakpoints.h" |
| 35 | #include "debugger/graphics_cmdlists.h" | 33 | #include "debugger/graphics_cmdlists.h" |
| 36 | #include "debugger/graphics_framebuffer.h" | 34 | #include "debugger/graphics_framebuffer.h" |
| 35 | #include "debugger/graphics_tracing.h" | ||
| 37 | #include "debugger/graphics_vertex_shader.h" | 36 | #include "debugger/graphics_vertex_shader.h" |
| 38 | #include "debugger/profiler.h" | 37 | #include "debugger/profiler.h" |
| 39 | 38 | ||
| @@ -96,6 +95,10 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) | |||
| 96 | addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); | 95 | addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); |
| 97 | graphicsVertexShaderWidget->hide(); | 96 | graphicsVertexShaderWidget->hide(); |
| 98 | 97 | ||
| 98 | auto graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this); | ||
| 99 | addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget); | ||
| 100 | graphicsTracingWidget->hide(); | ||
| 101 | |||
| 99 | QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); | 102 | QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); |
| 100 | debug_menu->addAction(profilerWidget->toggleViewAction()); | 103 | debug_menu->addAction(profilerWidget->toggleViewAction()); |
| 101 | debug_menu->addAction(disasmWidget->toggleViewAction()); | 104 | debug_menu->addAction(disasmWidget->toggleViewAction()); |
| @@ -106,6 +109,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) | |||
| 106 | debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); | 109 | debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); |
| 107 | debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); | 110 | debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); |
| 108 | debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); | 111 | debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); |
| 112 | debug_menu->addAction(graphicsTracingWidget->toggleViewAction()); | ||
| 109 | 113 | ||
| 110 | // Set default UI state | 114 | // Set default UI state |
| 111 | // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half | 115 | // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half |
| @@ -150,6 +154,9 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) | |||
| 150 | connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping())); | 154 | connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping())); |
| 151 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*))); | 155 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*))); |
| 152 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); | 156 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); |
| 157 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), graphicsTracingWidget, SLOT(OnEmulationStarting(EmuThread*))); | ||
| 158 | connect(this, SIGNAL(EmulationStopping()), graphicsTracingWidget, SLOT(OnEmulationStopping())); | ||
| 159 | |||
| 153 | 160 | ||
| 154 | // Setup hotkeys | 161 | // Setup hotkeys |
| 155 | RegisterHotkey("Main Window", "Load File", QKeySequence::Open); | 162 | RegisterHotkey("Main Window", "Load File", QKeySequence::Open); |
| @@ -256,6 +263,7 @@ void GMainWindow::ShutdownGame() { | |||
| 256 | 263 | ||
| 257 | // Update the GUI | 264 | // Update the GUI |
| 258 | ui.action_Start->setEnabled(false); | 265 | ui.action_Start->setEnabled(false); |
| 266 | ui.action_Start->setText(tr("Start")); | ||
| 259 | ui.action_Pause->setEnabled(false); | 267 | ui.action_Pause->setEnabled(false); |
| 260 | ui.action_Stop->setEnabled(false); | 268 | ui.action_Stop->setEnabled(false); |
| 261 | render_window->hide(); | 269 | render_window->hide(); |
| @@ -284,6 +292,8 @@ void GMainWindow::OnStartGame() | |||
| 284 | emu_thread->SetRunning(true); | 292 | emu_thread->SetRunning(true); |
| 285 | 293 | ||
| 286 | ui.action_Start->setEnabled(false); | 294 | ui.action_Start->setEnabled(false); |
| 295 | ui.action_Start->setText(tr("Continue")); | ||
| 296 | |||
| 287 | ui.action_Pause->setEnabled(true); | 297 | ui.action_Pause->setEnabled(true); |
| 288 | ui.action_Stop->setEnabled(true); | 298 | ui.action_Stop->setEnabled(true); |
| 289 | } | 299 | } |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e78f4f144..4c086cd2f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -31,7 +31,6 @@ set(HEADERS | |||
| 31 | cpu_detect.h | 31 | cpu_detect.h |
| 32 | debug_interface.h | 32 | debug_interface.h |
| 33 | emu_window.h | 33 | emu_window.h |
| 34 | fifo_queue.h | ||
| 35 | file_util.h | 34 | file_util.h |
| 36 | key_map.h | 35 | key_map.h |
| 37 | linear_disk_cache.h | 36 | linear_disk_cache.h |
| @@ -53,7 +52,6 @@ set(HEADERS | |||
| 53 | synchronized_wrapper.h | 52 | synchronized_wrapper.h |
| 54 | thread.h | 53 | thread.h |
| 55 | thread_queue_list.h | 54 | thread_queue_list.h |
| 56 | thunk.h | ||
| 57 | timer.h | 55 | timer.h |
| 58 | vector_math.h | 56 | vector_math.h |
| 59 | ) | 57 | ) |
diff --git a/src/common/assert.h b/src/common/assert.h index 7b7d8bf28..6849778b7 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstdio> | ||
| 8 | #include <cstdlib> | 7 | #include <cstdlib> |
| 9 | 8 | ||
| 10 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 1f3ecf844..f64ebdaf6 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | 32 | ||
| 33 | #pragma once | 33 | #pragma once |
| 34 | 34 | ||
| 35 | #include <cstddef> | ||
| 35 | #include <limits> | 36 | #include <limits> |
| 36 | #include <type_traits> | 37 | #include <type_traits> |
| 37 | 38 | ||
| @@ -160,7 +161,7 @@ public: | |||
| 160 | if (std::numeric_limits<T>::is_signed) | 161 | if (std::numeric_limits<T>::is_signed) |
| 161 | { | 162 | { |
| 162 | std::size_t shift = 8 * sizeof(T)-bits; | 163 | std::size_t shift = 8 * sizeof(T)-bits; |
| 163 | return (T)(((storage & GetMask()) << (shift - position)) >> shift); | 164 | return (T)((storage << (shift - position)) >> shift); |
| 164 | } | 165 | } |
| 165 | else | 166 | else |
| 166 | { | 167 | { |
| @@ -188,7 +189,7 @@ private: | |||
| 188 | 189 | ||
| 189 | __forceinline StorageType GetMask() const | 190 | __forceinline StorageType GetMask() const |
| 190 | { | 191 | { |
| 191 | return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position; | 192 | return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position; |
| 192 | } | 193 | } |
| 193 | 194 | ||
| 194 | StorageType storage; | 195 | StorageType storage; |
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h index dcd80525e..8be0b1109 100644 --- a/src/common/chunk_file.h +++ b/src/common/chunk_file.h | |||
| @@ -26,16 +26,18 @@ | |||
| 26 | // - Zero backwards/forwards compatibility | 26 | // - Zero backwards/forwards compatibility |
| 27 | // - Serialization code for anything complex has to be manually written. | 27 | // - Serialization code for anything complex has to be manually written. |
| 28 | 28 | ||
| 29 | #include <map> | 29 | #include <cstring> |
| 30 | #include <vector> | ||
| 31 | #include <deque> | 30 | #include <deque> |
| 32 | #include <string> | ||
| 33 | #include <list> | 31 | #include <list> |
| 32 | #include <map> | ||
| 34 | #include <set> | 33 | #include <set> |
| 34 | #include <string> | ||
| 35 | #include <type_traits> | 35 | #include <type_traits> |
| 36 | #include <utility> | ||
| 37 | #include <vector> | ||
| 36 | 38 | ||
| 39 | #include "common/assert.h" | ||
| 37 | #include "common/common_types.h" | 40 | #include "common/common_types.h" |
| 38 | #include "common/file_util.h" | ||
| 39 | #include "common/logging/log.h" | 41 | #include "common/logging/log.h" |
| 40 | 42 | ||
| 41 | template <class T> | 43 | template <class T> |
diff --git a/src/common/color.h b/src/common/color.h index 422fdc8af..9dafdca0c 100644 --- a/src/common/color.h +++ b/src/common/color.h | |||
| @@ -208,7 +208,32 @@ inline void EncodeD24(u32 value, u8* bytes) { | |||
| 208 | * @param bytes Pointer where to store the encoded value | 208 | * @param bytes Pointer where to store the encoded value |
| 209 | */ | 209 | */ |
| 210 | inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) { | 210 | inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) { |
| 211 | *reinterpret_cast<u32_le*>(bytes) = (stencil << 24) | depth; | 211 | bytes[0] = depth & 0xFF; |
| 212 | bytes[1] = (depth >> 8) & 0xFF; | ||
| 213 | bytes[2] = (depth >> 16) & 0xFF; | ||
| 214 | bytes[3] = stencil; | ||
| 215 | } | ||
| 216 | |||
| 217 | /** | ||
| 218 | * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused) | ||
| 219 | * @param depth 24 bit source depth value to encode | ||
| 220 | * @param bytes Pointer where to store the encoded value | ||
| 221 | * @note unused bits will not be modified | ||
| 222 | */ | ||
| 223 | inline void EncodeD24X8(u32 depth, u8* bytes) { | ||
| 224 | bytes[0] = depth & 0xFF; | ||
| 225 | bytes[1] = (depth >> 8) & 0xFF; | ||
| 226 | bytes[2] = (depth >> 16) & 0xFF; | ||
| 227 | } | ||
| 228 | |||
| 229 | /** | ||
| 230 | * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused) | ||
| 231 | * @param stencil 8 bit source stencil value to encode | ||
| 232 | * @param bytes Pointer where to store the encoded value | ||
| 233 | * @note unused bits will not be modified | ||
| 234 | */ | ||
| 235 | inline void EncodeX24S8(u8 stencil, u8* bytes) { | ||
| 236 | bytes[3] = stencil; | ||
| 212 | } | 237 | } |
| 213 | 238 | ||
| 214 | } // namespace | 239 | } // namespace |
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 91b74c6bc..59bd16dbf 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -5,15 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common_types.h" | 7 | #include "common_types.h" |
| 8 | #include <cstdlib> | ||
| 9 | |||
| 10 | |||
| 11 | #define b2(x) ( (x) | ( (x) >> 1) ) | ||
| 12 | #define b4(x) ( b2(x) | ( b2(x) >> 2) ) | ||
| 13 | #define b8(x) ( b4(x) | ( b4(x) >> 4) ) | ||
| 14 | #define b16(x) ( b8(x) | ( b8(x) >> 8) ) | ||
| 15 | #define b32(x) (b16(x) | (b16(x) >>16) ) | ||
| 16 | #define ROUND_UP_POW2(x) (b32(x - 1) + 1) | ||
| 17 | 8 | ||
| 18 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | 9 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) |
| 19 | 10 | ||
| @@ -43,8 +34,6 @@ | |||
| 43 | 34 | ||
| 44 | #ifndef _MSC_VER | 35 | #ifndef _MSC_VER |
| 45 | 36 | ||
| 46 | #include <errno.h> | ||
| 47 | |||
| 48 | #if defined(__x86_64__) || defined(_M_X64) | 37 | #if defined(__x86_64__) || defined(_M_X64) |
| 49 | #define Crash() __asm__ __volatile__("int $3") | 38 | #define Crash() __asm__ __volatile__("int $3") |
| 50 | #elif defined(_M_ARM) | 39 | #elif defined(_M_ARM) |
| @@ -80,8 +69,10 @@ inline u64 _rotr64(u64 x, unsigned int shift){ | |||
| 80 | } | 69 | } |
| 81 | 70 | ||
| 82 | #else // _MSC_VER | 71 | #else // _MSC_VER |
| 83 | // Function Cross-Compatibility | 72 | #if (_MSC_VER < 1900) |
| 84 | #define snprintf _snprintf | 73 | // Function Cross-Compatibility |
| 74 | #define snprintf _snprintf | ||
| 75 | #endif | ||
| 85 | 76 | ||
| 86 | // Locale Cross-Compatibility | 77 | // Locale Cross-Compatibility |
| 87 | #define locale_t _locale_t | 78 | #define locale_t _locale_t |
diff --git a/src/common/common_types.h b/src/common/common_types.h index f6de0adfc..fa3e0b8d6 100644 --- a/src/common/common_types.h +++ b/src/common/common_types.h | |||
| @@ -24,9 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #pragma once | 25 | #pragma once |
| 26 | 26 | ||
| 27 | #include <cmath> | ||
| 28 | #include <cstdint> | 27 | #include <cstdint> |
| 29 | #include <cstdlib> | ||
| 30 | 28 | ||
| 31 | #ifdef _MSC_VER | 29 | #ifdef _MSC_VER |
| 32 | #ifndef __func__ | 30 | #ifndef __func__ |
| @@ -52,32 +50,6 @@ typedef double f64; ///< 64-bit floating point | |||
| 52 | typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. | 50 | typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. |
| 53 | typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. | 51 | typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. |
| 54 | 52 | ||
| 55 | /// Union for fast 16-bit type casting | ||
| 56 | union t16 { | ||
| 57 | u8 _u8[2]; ///< 8-bit unsigned char(s) | ||
| 58 | u16 _u16; ///< 16-bit unsigned shorts(s) | ||
| 59 | }; | ||
| 60 | |||
| 61 | /// Union for fast 32-bit type casting | ||
| 62 | union t32 { | ||
| 63 | f32 _f32; ///< 32-bit floating point(s) | ||
| 64 | u32 _u32; ///< 32-bit unsigned int(s) | ||
| 65 | s32 _s32; ///< 32-bit signed int(s) | ||
| 66 | u16 _u16[2]; ///< 16-bit unsigned shorts(s) | ||
| 67 | u8 _u8[4]; ///< 8-bit unsigned char(s) | ||
| 68 | }; | ||
| 69 | |||
| 70 | /// Union for fast 64-bit type casting | ||
| 71 | union t64 { | ||
| 72 | f64 _f64; ///< 64-bit floating point | ||
| 73 | u64 _u64; ///< 64-bit unsigned long | ||
| 74 | f32 _f32[2]; ///< 32-bit floating point(s) | ||
| 75 | u32 _u32[2]; ///< 32-bit unsigned int(s) | ||
| 76 | s32 _s32[2]; ///< 32-bit signed int(s) | ||
| 77 | u16 _u16[4]; ///< 16-bit unsigned shorts(s) | ||
| 78 | u8 _u8[8]; ///< 8-bit unsigned char(s) | ||
| 79 | }; | ||
| 80 | |||
| 81 | // An inheritable class to disallow the copy constructor and operator= functions | 53 | // An inheritable class to disallow the copy constructor and operator= functions |
| 82 | class NonCopyable { | 54 | class NonCopyable { |
| 83 | protected: | 55 | protected: |
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp index 43facb85c..b69b05cb9 100644 --- a/src/common/emu_window.cpp +++ b/src/common/emu_window.cpp | |||
| @@ -2,6 +2,12 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <cmath> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/key_map.h" | ||
| 10 | |||
| 5 | #include "emu_window.h" | 11 | #include "emu_window.h" |
| 6 | #include "video_core/video_core.h" | 12 | #include "video_core/video_core.h" |
| 7 | 13 | ||
diff --git a/src/common/emu_window.h b/src/common/emu_window.h index 8eca6b5d5..a0ae4c9fa 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h | |||
| @@ -4,11 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <tuple> | ||
| 8 | #include <utility> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | #include "common/key_map.h" | ||
| 9 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 10 | #include "common/scm_rev.h" | 12 | |
| 11 | #include "common/string_util.h" | 13 | #include "core/hle/service/hid/hid.h" |
| 14 | |||
| 15 | namespace KeyMap { | ||
| 16 | struct HostDeviceKey; | ||
| 17 | } | ||
| 12 | 18 | ||
| 13 | /** | 19 | /** |
| 14 | * Abstraction class used to provide an interface between emulation code and the frontend | 20 | * Abstraction class used to provide an interface between emulation code and the frontend |
diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h deleted file mode 100644 index b426e6596..000000000 --- a/src/common/fifo_queue.h +++ /dev/null | |||
| @@ -1,111 +0,0 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | // a simple lockless thread-safe, | ||
| 4 | // single reader, single writer queue | ||
| 5 | |||
| 6 | #include "common/atomic.h" | ||
| 7 | |||
| 8 | namespace Common | ||
| 9 | { | ||
| 10 | |||
| 11 | template <typename T> | ||
| 12 | class FifoQueue | ||
| 13 | { | ||
| 14 | public: | ||
| 15 | FifoQueue() : m_size(0) | ||
| 16 | { | ||
| 17 | m_write_ptr = m_read_ptr = new ElementPtr(); | ||
| 18 | } | ||
| 19 | |||
| 20 | ~FifoQueue() | ||
| 21 | { | ||
| 22 | // this will empty out the whole queue | ||
| 23 | delete m_read_ptr; | ||
| 24 | } | ||
| 25 | |||
| 26 | u32 Size() const | ||
| 27 | { | ||
| 28 | return m_size; | ||
| 29 | } | ||
| 30 | |||
| 31 | bool Empty() const | ||
| 32 | { | ||
| 33 | //return (m_read_ptr == m_write_ptr); | ||
| 34 | return (0 == m_size); | ||
| 35 | } | ||
| 36 | |||
| 37 | T& Front() const | ||
| 38 | { | ||
| 39 | return *m_read_ptr->current; | ||
| 40 | } | ||
| 41 | |||
| 42 | template <typename Arg> | ||
| 43 | void Push(Arg&& t) | ||
| 44 | { | ||
| 45 | // create the element, add it to the queue | ||
| 46 | m_write_ptr->current = new T(std::forward<Arg>(t)); | ||
| 47 | // set the next pointer to a new element ptr | ||
| 48 | // then advance the write pointer | ||
| 49 | m_write_ptr = m_write_ptr->next = new ElementPtr(); | ||
| 50 | Common::AtomicIncrement(m_size); | ||
| 51 | } | ||
| 52 | |||
| 53 | void Pop() | ||
| 54 | { | ||
| 55 | Common::AtomicDecrement(m_size); | ||
| 56 | ElementPtr *const tmpptr = m_read_ptr; | ||
| 57 | // advance the read pointer | ||
| 58 | m_read_ptr = m_read_ptr->next; | ||
| 59 | // set the next element to NULL to stop the recursive deletion | ||
| 60 | tmpptr->next = nullptr; | ||
| 61 | delete tmpptr; // this also deletes the element | ||
| 62 | } | ||
| 63 | |||
| 64 | bool Pop(T& t) | ||
| 65 | { | ||
| 66 | if (Empty()) | ||
| 67 | return false; | ||
| 68 | |||
| 69 | t = std::move(Front()); | ||
| 70 | Pop(); | ||
| 71 | |||
| 72 | return true; | ||
| 73 | } | ||
| 74 | |||
| 75 | // not thread-safe | ||
| 76 | void Clear() | ||
| 77 | { | ||
| 78 | m_size = 0; | ||
| 79 | delete m_read_ptr; | ||
| 80 | m_write_ptr = m_read_ptr = new ElementPtr(); | ||
| 81 | } | ||
| 82 | |||
| 83 | private: | ||
| 84 | // stores a pointer to element | ||
| 85 | // and a pointer to the next ElementPtr | ||
| 86 | class ElementPtr | ||
| 87 | { | ||
| 88 | public: | ||
| 89 | ElementPtr() : current(nullptr), next(nullptr) {} | ||
| 90 | |||
| 91 | ~ElementPtr() | ||
| 92 | { | ||
| 93 | if (current) | ||
| 94 | { | ||
| 95 | delete current; | ||
| 96 | // recusion ftw | ||
| 97 | if (next) | ||
| 98 | delete next; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | T *volatile current; | ||
| 103 | ElementPtr *volatile next; | ||
| 104 | }; | ||
| 105 | |||
| 106 | ElementPtr *volatile m_write_ptr; | ||
| 107 | ElementPtr *volatile m_read_ptr; | ||
| 108 | volatile u32 m_size; | ||
| 109 | }; | ||
| 110 | |||
| 111 | } | ||
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 24648ea33..836b58d52 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <direct.h> // getcwd | 17 | #include <direct.h> // getcwd |
| 18 | #include <tchar.h> | 18 | #include <tchar.h> |
| 19 | 19 | ||
| 20 | #include "common/string_util.h" | ||
| 21 | |||
| 20 | // 64 bit offsets for windows | 22 | // 64 bit offsets for windows |
| 21 | #define fseeko _fseeki64 | 23 | #define fseeko _fseeki64 |
| 22 | #define ftello _ftelli64 | 24 | #define ftello _ftelli64 |
| @@ -25,8 +27,13 @@ | |||
| 25 | #define fstat64 _fstat64 | 27 | #define fstat64 _fstat64 |
| 26 | #define fileno _fileno | 28 | #define fileno _fileno |
| 27 | #else | 29 | #else |
| 28 | #include <sys/param.h> | 30 | #ifdef __APPLE__ |
| 29 | #include <sys/types.h> | 31 | #include <sys/param.h> |
| 32 | #endif | ||
| 33 | #include <cctype> | ||
| 34 | #include <cerrno> | ||
| 35 | #include <cstdlib> | ||
| 36 | #include <cstring> | ||
| 30 | #include <dirent.h> | 37 | #include <dirent.h> |
| 31 | #include <pwd.h> | 38 | #include <pwd.h> |
| 32 | #include <unistd.h> | 39 | #include <unistd.h> |
diff --git a/src/common/file_util.h b/src/common/file_util.h index b65829291..d0dccdf69 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -6,13 +6,12 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <fstream> | 8 | #include <fstream> |
| 9 | #include <cstddef> | ||
| 9 | #include <cstdio> | 10 | #include <cstdio> |
| 10 | #include <cstring> | ||
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <vector> | 12 | #include <vector> |
| 13 | 13 | ||
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "common/string_util.h" | ||
| 16 | 15 | ||
| 17 | // User directory indices for GetUserPath | 16 | // User directory indices for GetUserPath |
| 18 | enum { | 17 | enum { |
| @@ -117,9 +116,6 @@ bool SetCurrentDir(const std::string &directory); | |||
| 117 | // directory. To be used in "multi-user" mode (that is, installed). | 116 | // directory. To be used in "multi-user" mode (that is, installed). |
| 118 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); | 117 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); |
| 119 | 118 | ||
| 120 | // probably doesn't belong here | ||
| 121 | //std::string GetThemeDir(const std::string& theme_name); | ||
| 122 | |||
| 123 | // Returns the path to where the sys file are | 119 | // Returns the path to where the sys file are |
| 124 | std::string GetSysDirectory(); | 120 | std::string GetSysDirectory(); |
| 125 | 121 | ||
| @@ -182,6 +178,10 @@ public: | |||
| 182 | template <typename T> | 178 | template <typename T> |
| 183 | size_t WriteArray(const T* data, size_t length) | 179 | size_t WriteArray(const T* data, size_t length) |
| 184 | { | 180 | { |
| 181 | static_assert(std::is_standard_layout<T>::value, "Given array does not consist of standard layout objects"); | ||
| 182 | // TODO: gcc 4.8 does not support is_trivially_copyable, but we really should check for it here. | ||
| 183 | //static_assert(std::is_trivially_copyable<T>::value, "Given array does not consist of trivially copyable objects"); | ||
| 184 | |||
| 185 | if (!IsOpen()) { | 185 | if (!IsOpen()) { |
| 186 | m_good = false; | 186 | m_good = false; |
| 187 | return -1; | 187 | return -1; |
| @@ -204,6 +204,12 @@ public: | |||
| 204 | return WriteArray(reinterpret_cast<const char*>(data), length); | 204 | return WriteArray(reinterpret_cast<const char*>(data), length); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | template<typename T> | ||
| 208 | size_t WriteObject(const T& object) { | ||
| 209 | static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); | ||
| 210 | return WriteArray(&object, 1); | ||
| 211 | } | ||
| 212 | |||
| 207 | bool IsOpen() { return nullptr != m_file; } | 213 | bool IsOpen() { return nullptr != m_file; } |
| 208 | 214 | ||
| 209 | // m_good is set to false when a read, write or other function fails | 215 | // m_good is set to false when a read, write or other function fails |
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h index 0b71ea3b2..a2b4eca43 100644 --- a/src/common/logging/filter.h +++ b/src/common/logging/filter.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | ||
| 8 | #include <string> | 9 | #include <string> |
| 9 | 10 | ||
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 5b3a731e9..e16dde7fc 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -4,10 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cassert> | ||
| 8 | #include <chrono> | ||
| 9 | #include <string> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 12 | 8 | ||
| 13 | namespace Log { | 9 | namespace Log { |
diff --git a/src/common/make_unique.h b/src/common/make_unique.h index 2a7b76412..f6e7f017c 100644 --- a/src/common/make_unique.h +++ b/src/common/make_unique.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | 9 | ||
| 9 | namespace Common { | 10 | namespace Common { |
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index 20b791a10..2b3ace528 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp | |||
| @@ -3,14 +3,17 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 8 | #include "common/memory_util.h" | 7 | #include "common/memory_util.h" |
| 9 | #include "common/string_util.h" | ||
| 10 | 8 | ||
| 11 | #ifdef _WIN32 | 9 | #ifdef _WIN32 |
| 12 | #include <windows.h> | 10 | #include <windows.h> |
| 13 | #include <psapi.h> | 11 | #include <psapi.h> |
| 12 | #include "common/common_funcs.h" | ||
| 13 | #include "common/string_util.h" | ||
| 14 | #else | ||
| 15 | #include <cstdlib> | ||
| 16 | #include <sys/mman.h> | ||
| 14 | #endif | 17 | #endif |
| 15 | 18 | ||
| 16 | #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) | 19 | #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) |
diff --git a/src/common/memory_util.h b/src/common/memory_util.h index 9fdbf1f12..9bf37c44f 100644 --- a/src/common/memory_util.h +++ b/src/common/memory_util.h | |||
| @@ -4,9 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #ifndef _WIN32 | 7 | #include <cstddef> |
| 8 | #include <sys/mman.h> | ||
| 9 | #endif | ||
| 10 | #include <string> | 8 | #include <string> |
| 11 | 9 | ||
| 12 | void* AllocateExecutableMemory(size_t size, bool low = true); | 10 | void* AllocateExecutableMemory(size_t size, bool low = true); |
diff --git a/src/common/misc.cpp b/src/common/misc.cpp index 53cacf37c..d2a049b63 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp | |||
| @@ -2,12 +2,13 @@ | |||
| 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/common_funcs.h" | 5 | #include <cstddef> |
| 6 | 6 | ||
| 7 | #ifdef _WIN32 | 7 | #ifdef _WIN32 |
| 8 | #include <windows.h> | 8 | #include <windows.h> |
| 9 | #else | 9 | #else |
| 10 | #include <string.h> | 10 | #include <cerrno> |
| 11 | #include <cstring> | ||
| 11 | #endif | 12 | #endif |
| 12 | 13 | ||
| 13 | // Neither Android nor OS X support TLS | 14 | // Neither Android nor OS X support TLS |
diff --git a/src/common/platform.h b/src/common/platform.h index df780ac6f..0a912dda3 100644 --- a/src/common/platform.h +++ b/src/common/platform.h | |||
| @@ -24,66 +24,11 @@ | |||
| 24 | 24 | ||
| 25 | #pragma once | 25 | #pragma once |
| 26 | 26 | ||
| 27 | #include "common/common_types.h" | ||
| 28 | |||
| 29 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 30 | // Platform definitions | ||
| 31 | |||
| 32 | /// Enumeration for defining the supported platforms | ||
| 33 | #define PLATFORM_NULL 0 | ||
| 34 | #define PLATFORM_WINDOWS 1 | ||
| 35 | #define PLATFORM_MACOSX 2 | ||
| 36 | #define PLATFORM_LINUX 3 | ||
| 37 | #define PLATFORM_ANDROID 4 | ||
| 38 | |||
| 39 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 27 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 40 | // Platform detection | 28 | // Platform detection |
| 41 | 29 | ||
| 42 | #ifndef EMU_PLATFORM | ||
| 43 | |||
| 44 | #if defined( __WIN32__ ) || defined( _WIN32 ) | ||
| 45 | #define EMU_PLATFORM PLATFORM_WINDOWS | ||
| 46 | |||
| 47 | #elif defined( __APPLE__ ) || defined( __APPLE_CC__ ) | ||
| 48 | #define EMU_PLATFORM PLATFORM_MACOSX | ||
| 49 | |||
| 50 | #elif defined(__linux__) | ||
| 51 | #define EMU_PLATFORM PLATFORM_LINUX | ||
| 52 | |||
| 53 | #else // Assume linux otherwise | ||
| 54 | #define EMU_PLATFORM PLATFORM_LINUX | ||
| 55 | |||
| 56 | #endif | ||
| 57 | |||
| 58 | #endif | ||
| 59 | |||
| 60 | #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) | 30 | #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) |
| 61 | #define EMU_ARCH_BITS 64 | 31 | #define EMU_ARCH_BITS 64 |
| 62 | #elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) | 32 | #elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) |
| 63 | #define EMU_ARCH_BITS 32 | 33 | #define EMU_ARCH_BITS 32 |
| 64 | #endif | 34 | #endif |
| 65 | |||
| 66 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 67 | // Feature detection | ||
| 68 | |||
| 69 | #if defined _M_GENERIC | ||
| 70 | # define _M_SSE 0x0 | ||
| 71 | #elif defined __GNUC__ | ||
| 72 | # if defined __SSE4_2__ | ||
| 73 | # define _M_SSE 0x402 | ||
| 74 | # elif defined __SSE4_1__ | ||
| 75 | # define _M_SSE 0x401 | ||
| 76 | # elif defined __SSSE3__ | ||
| 77 | # define _M_SSE 0x301 | ||
| 78 | # elif defined __SSE3__ | ||
| 79 | # define _M_SSE 0x300 | ||
| 80 | # endif | ||
| 81 | #elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008 | ||
| 82 | # define _M_SSE 0x402 | ||
| 83 | #endif | ||
| 84 | |||
| 85 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 86 | // Compiler-Specific Definitions | ||
| 87 | |||
| 88 | #define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \ | ||
| 89 | (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) | ||
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp index cf6b6b258..7792edd2f 100644 --- a/src/common/profiler.cpp +++ b/src/common/profiler.cpp | |||
| @@ -2,13 +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 <algorithm> | ||
| 6 | #include <cstddef> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 5 | #include "common/profiler.h" | 10 | #include "common/profiler.h" |
| 6 | #include "common/profiler_reporting.h" | 11 | #include "common/profiler_reporting.h" |
| 7 | #include "common/assert.h" | 12 | #include "common/synchronized_wrapper.h" |
| 8 | 13 | ||
| 9 | #if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013. | 14 | #if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013. |
| 10 | #define WIN32_LEAN_AND_MEAN | 15 | #define WIN32_LEAN_AND_MEAN |
| 11 | #include <Windows.h> // For QueryPerformanceCounter/Frequency | 16 | #include <Windows.h> // For QueryPerformanceCounter/Frequency |
| 12 | #endif | 17 | #endif |
| 13 | 18 | ||
| 14 | namespace Common { | 19 | namespace Common { |
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h index 3abb73315..df98e05b7 100644 --- a/src/common/profiler_reporting.h +++ b/src/common/profiler_reporting.h | |||
| @@ -4,10 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <cstddef> |
| 8 | #include <chrono> | ||
| 9 | #include <mutex> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | 8 | #include <vector> |
| 12 | 9 | ||
| 13 | #include "common/profiler.h" | 10 | #include "common/profiler.h" |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 7dc0ba7ba..b2f7f7b1d 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -2,9 +2,13 @@ | |||
| 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 <boost/range/algorithm.hpp> | 5 | #include <cctype> |
| 6 | #include <cerrno> | ||
| 7 | #include <cstdio> | ||
| 8 | #include <cstdlib> | ||
| 9 | #include <cstring> | ||
| 10 | #include <boost/range/algorithm/transform.hpp> | ||
| 6 | 11 | ||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_paths.h" | 12 | #include "common/common_paths.h" |
| 9 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 10 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| @@ -12,6 +16,7 @@ | |||
| 12 | #ifdef _MSC_VER | 16 | #ifdef _MSC_VER |
| 13 | #include <Windows.h> | 17 | #include <Windows.h> |
| 14 | #include <codecvt> | 18 | #include <codecvt> |
| 19 | #include "common/common_funcs.h" | ||
| 15 | #else | 20 | #else |
| 16 | #include <iconv.h> | 21 | #include <iconv.h> |
| 17 | #endif | 22 | #endif |
| @@ -308,7 +313,7 @@ static std::string UTF16ToUTF8(const std::wstring& input) | |||
| 308 | std::string output; | 313 | std::string output; |
| 309 | output.resize(size); | 314 | output.resize(size); |
| 310 | 315 | ||
| 311 | if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) | 316 | if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr)) |
| 312 | output.clear(); | 317 | output.clear(); |
| 313 | 318 | ||
| 314 | return output; | 319 | return output; |
diff --git a/src/common/string_util.h b/src/common/string_util.h index fdc410499..c5c474c6f 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h | |||
| @@ -5,9 +5,10 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstdarg> | 7 | #include <cstdarg> |
| 8 | #include <cstddef> | ||
| 8 | #include <iomanip> | 9 | #include <iomanip> |
| 9 | #include <string> | ||
| 10 | #include <sstream> | 10 | #include <sstream> |
| 11 | #include <string> | ||
| 11 | #include <vector> | 12 | #include <vector> |
| 12 | 13 | ||
| 13 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
diff --git a/src/common/swap.h b/src/common/swap.h index 588cebc70..b92e5bfa4 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -17,12 +17,16 @@ | |||
| 17 | 17 | ||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #if defined(__linux__) | 20 | #if defined(_MSC_VER) |
| 21 | #include <byteswap.h> | 21 | #include <cstdlib> |
| 22 | #elif defined(__linux__) | ||
| 23 | #include <byteswap.h> | ||
| 22 | #elif defined(__FreeBSD__) | 24 | #elif defined(__FreeBSD__) |
| 23 | #include <sys/endian.h> | 25 | #include <sys/endian.h> |
| 24 | #endif | 26 | #endif |
| 25 | 27 | ||
| 28 | #include "common/common_types.h" | ||
| 29 | |||
| 26 | // GCC 4.6+ | 30 | // GCC 4.6+ |
| 27 | #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | 31 | #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) |
| 28 | 32 | ||
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h index 946252b8c..ae5e8b1ed 100644 --- a/src/common/synchronized_wrapper.h +++ b/src/common/synchronized_wrapper.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 7 | #include <mutex> | 8 | #include <mutex> |
| 8 | 9 | ||
| 9 | namespace Common { | 10 | namespace Common { |
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 8bf005857..7bbf080bc 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -5,11 +5,20 @@ | |||
| 5 | #include "common/thread.h" | 5 | #include "common/thread.h" |
| 6 | 6 | ||
| 7 | #ifdef __APPLE__ | 7 | #ifdef __APPLE__ |
| 8 | #include <mach/mach.h> | 8 | #include <mach/mach.h> |
| 9 | #elif defined(BSD4_4) || defined(__OpenBSD__) | ||
| 10 | #include <pthread_np.h> | ||
| 11 | #elif defined(_WIN32) | 9 | #elif defined(_WIN32) |
| 12 | #include <Windows.h> | 10 | #include <Windows.h> |
| 11 | #else | ||
| 12 | #if defined(BSD4_4) || defined(__OpenBSD__) | ||
| 13 | #include <pthread_np.h> | ||
| 14 | #else | ||
| 15 | #include <pthread.h> | ||
| 16 | #endif | ||
| 17 | #include <sched.h> | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #ifndef _WIN32 | ||
| 21 | #include <unistd.h> | ||
| 13 | #endif | 22 | #endif |
| 14 | 23 | ||
| 15 | namespace Common | 24 | namespace Common |
diff --git a/src/common/thread.h b/src/common/thread.h index 7bc419497..8255ee6d3 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -4,24 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include <cstddef> |
| 8 | #include <cstdio> | ||
| 9 | #include <cstring> | ||
| 10 | #include <thread> | 8 | #include <thread> |
| 11 | #include <condition_variable> | 9 | #include <condition_variable> |
| 12 | #include <mutex> | 10 | #include <mutex> |
| 13 | 11 | ||
| 14 | // This may not be defined outside _WIN32 | 12 | #include "common/common_types.h" |
| 15 | #ifndef _WIN32 | ||
| 16 | #ifndef INFINITE | ||
| 17 | #define INFINITE 0xffffffff | ||
| 18 | #endif | ||
| 19 | |||
| 20 | //for gettimeofday and struct time(spec|val) | ||
| 21 | #include <time.h> | ||
| 22 | #include <sys/time.h> | ||
| 23 | #include <unistd.h> | ||
| 24 | #endif | ||
| 25 | 13 | ||
| 26 | // Support for C++11's thread_local keyword was surprisingly spotty in compilers until very | 14 | // Support for C++11's thread_local keyword was surprisingly spotty in compilers until very |
| 27 | // recently. Fortunately, thread local variables have been well supported for compilers for a while, | 15 | // recently. Fortunately, thread local variables have been well supported for compilers for a while, |
diff --git a/src/common/thunk.h b/src/common/thunk.h deleted file mode 100644 index 533480056..000000000 --- a/src/common/thunk.h +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <map> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | // This simple class creates a wrapper around a C/C++ function that saves all fp state | ||
| 12 | // before entering it, and restores it upon exit. This is required to be able to selectively | ||
| 13 | // call functions from generated code, without inflicting the performance hit and increase | ||
| 14 | // of complexity that it means to protect the generated code from this problem. | ||
| 15 | |||
| 16 | // This process is called thunking. | ||
| 17 | |||
| 18 | // There will only ever be one level of thunking on the stack, plus, | ||
| 19 | // we don't want to pollute the stack, so we store away regs somewhere global. | ||
| 20 | // NOT THREAD SAFE. This may only be used from the CPU thread. | ||
| 21 | // Any other thread using this stuff will be FATAL. | ||
| 22 | |||
| 23 | class ThunkManager : public Gen::XCodeBlock | ||
| 24 | { | ||
| 25 | std::map<void *, const u8 *> thunks; | ||
| 26 | |||
| 27 | const u8 *save_regs; | ||
| 28 | const u8 *load_regs; | ||
| 29 | |||
| 30 | public: | ||
| 31 | ThunkManager() { | ||
| 32 | Init(); | ||
| 33 | } | ||
| 34 | ~ThunkManager() { | ||
| 35 | Shutdown(); | ||
| 36 | } | ||
| 37 | void *ProtectFunction(void *function, int num_params); | ||
| 38 | private: | ||
| 39 | void Init(); | ||
| 40 | void Shutdown(); | ||
| 41 | void Reset(); | ||
| 42 | }; | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4fcda4874..6cc60fd58 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -4,10 +4,9 @@ set(SRCS | |||
| 4 | arm/dyncom/arm_dyncom.cpp | 4 | arm/dyncom/arm_dyncom.cpp |
| 5 | arm/dyncom/arm_dyncom_dec.cpp | 5 | arm/dyncom/arm_dyncom_dec.cpp |
| 6 | arm/dyncom/arm_dyncom_interpreter.cpp | 6 | arm/dyncom/arm_dyncom_interpreter.cpp |
| 7 | arm/dyncom/arm_dyncom_run.cpp | ||
| 8 | arm/dyncom/arm_dyncom_thumb.cpp | 7 | arm/dyncom/arm_dyncom_thumb.cpp |
| 9 | arm/interpreter/arminit.cpp | 8 | arm/skyeye_common/armstate.cpp |
| 10 | arm/interpreter/armsupp.cpp | 9 | arm/skyeye_common/armsupp.cpp |
| 11 | arm/skyeye_common/vfp/vfp.cpp | 10 | arm/skyeye_common/vfp/vfp.cpp |
| 12 | arm/skyeye_common/vfp/vfpdouble.cpp | 11 | arm/skyeye_common/vfp/vfpdouble.cpp |
| 13 | arm/skyeye_common/vfp/vfpinstr.cpp | 12 | arm/skyeye_common/vfp/vfpinstr.cpp |
| @@ -25,6 +24,8 @@ set(SRCS | |||
| 25 | file_sys/ivfc_archive.cpp | 24 | file_sys/ivfc_archive.cpp |
| 26 | hle/config_mem.cpp | 25 | hle/config_mem.cpp |
| 27 | hle/hle.cpp | 26 | hle/hle.cpp |
| 27 | hle/applets/applet.cpp | ||
| 28 | hle/applets/swkbd.cpp | ||
| 28 | hle/kernel/address_arbiter.cpp | 29 | hle/kernel/address_arbiter.cpp |
| 29 | hle/kernel/event.cpp | 30 | hle/kernel/event.cpp |
| 30 | hle/kernel/kernel.cpp | 31 | hle/kernel/kernel.cpp |
| @@ -113,6 +114,7 @@ set(SRCS | |||
| 113 | loader/elf.cpp | 114 | loader/elf.cpp |
| 114 | loader/loader.cpp | 115 | loader/loader.cpp |
| 115 | loader/ncch.cpp | 116 | loader/ncch.cpp |
| 117 | tracer/recorder.cpp | ||
| 116 | mem_map.cpp | 118 | mem_map.cpp |
| 117 | memory.cpp | 119 | memory.cpp |
| 118 | settings.cpp | 120 | settings.cpp |
| @@ -129,8 +131,8 @@ set(HEADERS | |||
| 129 | arm/dyncom/arm_dyncom_run.h | 131 | arm/dyncom/arm_dyncom_run.h |
| 130 | arm/dyncom/arm_dyncom_thumb.h | 132 | arm/dyncom/arm_dyncom_thumb.h |
| 131 | arm/skyeye_common/arm_regformat.h | 133 | arm/skyeye_common/arm_regformat.h |
| 132 | arm/skyeye_common/armdefs.h | 134 | arm/skyeye_common/armstate.h |
| 133 | arm/skyeye_common/armmmu.h | 135 | arm/skyeye_common/armsupp.h |
| 134 | arm/skyeye_common/vfp/asm_vfp.h | 136 | arm/skyeye_common/vfp/asm_vfp.h |
| 135 | arm/skyeye_common/vfp/vfp.h | 137 | arm/skyeye_common/vfp/vfp.h |
| 136 | arm/skyeye_common/vfp/vfp_helper.h | 138 | arm/skyeye_common/vfp/vfp_helper.h |
| @@ -150,6 +152,8 @@ set(HEADERS | |||
| 150 | hle/config_mem.h | 152 | hle/config_mem.h |
| 151 | hle/function_wrappers.h | 153 | hle/function_wrappers.h |
| 152 | hle/hle.h | 154 | hle/hle.h |
| 155 | hle/applets/applet.h | ||
| 156 | hle/applets/swkbd.h | ||
| 153 | hle/kernel/address_arbiter.h | 157 | hle/kernel/address_arbiter.h |
| 154 | hle/kernel/event.h | 158 | hle/kernel/event.h |
| 155 | hle/kernel/kernel.h | 159 | hle/kernel/kernel.h |
| @@ -239,6 +243,8 @@ set(HEADERS | |||
| 239 | loader/elf.h | 243 | loader/elf.h |
| 240 | loader/loader.h | 244 | loader/loader.h |
| 241 | loader/ncch.h | 245 | loader/ncch.h |
| 246 | tracer/recorder.h | ||
| 247 | tracer/citrace.h | ||
| 242 | mem_map.h | 248 | mem_map.h |
| 243 | memory.h | 249 | memory.h |
| 244 | memory_setup.h | 250 | memory_setup.h |
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp index 13d26d170..eb20bf6f7 100644 --- a/src/core/arm/disassembler/load_symbol_map.cpp +++ b/src/core/arm/disassembler/load_symbol_map.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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 <sstream> | ||
| 5 | #include <string> | 6 | #include <string> |
| 6 | #include <vector> | 7 | #include <vector> |
| 7 | 8 | ||
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 529c4ac70..c665f706f 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/make_unique.h" | 7 | #include "common/make_unique.h" |
| 8 | 8 | ||
| 9 | #include "core/arm/skyeye_common/armdefs.h" | 9 | #include "core/arm/skyeye_common/armstate.h" |
| 10 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 10 | #include "core/arm/skyeye_common/vfp/vfp.h" | 11 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 11 | 12 | ||
| 12 | #include "core/arm/dyncom/arm_dyncom.h" | 13 | #include "core/arm/dyncom/arm_dyncom.h" |
| @@ -17,26 +18,7 @@ | |||
| 17 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 18 | 19 | ||
| 19 | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | 20 | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { |
| 20 | state = Common::make_unique<ARMul_State>(); | 21 | state = Common::make_unique<ARMul_State>(initial_mode); |
| 21 | |||
| 22 | ARMul_NewState(state.get()); | ||
| 23 | ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); | ||
| 24 | |||
| 25 | state->abort_model = ABORT_BASE_RESTORED; | ||
| 26 | |||
| 27 | state->bigendSig = LOW; | ||
| 28 | state->lateabtSig = LOW; | ||
| 29 | state->NirqSig = HIGH; | ||
| 30 | |||
| 31 | // Reset the core to initial state | ||
| 32 | ARMul_Reset(state.get()); | ||
| 33 | state->Emulate = RUN; | ||
| 34 | |||
| 35 | // Switch to the desired privilege mode. | ||
| 36 | switch_mode(state.get(), initial_mode); | ||
| 37 | |||
| 38 | state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack | ||
| 39 | state->Reg[15] = 0x00000000; | ||
| 40 | } | 22 | } |
| 41 | 23 | ||
| 42 | ARM_DynCom::~ARM_DynCom() { | 24 | ARM_DynCom::~ARM_DynCom() { |
| @@ -100,8 +82,8 @@ void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 e | |||
| 100 | } | 82 | } |
| 101 | 83 | ||
| 102 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | 84 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { |
| 103 | memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); | 85 | memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); |
| 104 | memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); | 86 | memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); |
| 105 | 87 | ||
| 106 | ctx.sp = state->Reg[13]; | 88 | ctx.sp = state->Reg[13]; |
| 107 | ctx.lr = state->Reg[14]; | 89 | ctx.lr = state->Reg[14]; |
| @@ -113,8 +95,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | |||
| 113 | } | 95 | } |
| 114 | 96 | ||
| 115 | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | 97 | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { |
| 116 | memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); | 98 | memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); |
| 117 | memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); | 99 | memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); |
| 118 | 100 | ||
| 119 | state->Reg[13] = ctx.sp; | 101 | state->Reg[13] = ctx.sp; |
| 120 | state->Reg[14] = ctx.lr; | 102 | state->Reg[14] = ctx.lr; |
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 2488c879c..87ab6908a 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h | |||
| @@ -9,7 +9,12 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | 10 | ||
| 11 | #include "core/arm/arm_interface.h" | 11 | #include "core/arm/arm_interface.h" |
| 12 | #include "core/arm/skyeye_common/armdefs.h" | 12 | #include "core/arm/skyeye_common/arm_regformat.h" |
| 13 | #include "core/arm/skyeye_common/armstate.h" | ||
| 14 | |||
| 15 | namespace Core { | ||
| 16 | struct ThreadContext; | ||
| 17 | } | ||
| 13 | 18 | ||
| 14 | class ARM_DynCom final : virtual public ARM_Interface { | 19 | class ARM_DynCom final : virtual public ARM_Interface { |
| 15 | public: | 20 | public: |
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index 697be9556..ee4288314 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp | |||
| @@ -2,10 +2,10 @@ | |||
| 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 "core/arm/skyeye_common/armdefs.h" | ||
| 6 | #include "core/arm/dyncom/arm_dyncom_dec.h" | 5 | #include "core/arm/dyncom/arm_dyncom_dec.h" |
| 6 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 7 | 7 | ||
| 8 | const ISEITEM arm_instruction[] = { | 8 | const InstructionSetEncodingItem arm_instruction[] = { |
| 9 | { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }}, | 9 | { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }}, |
| 10 | { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }}, | 10 | { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }}, |
| 11 | { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }}, | 11 | { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }}, |
| @@ -207,7 +207,7 @@ const ISEITEM arm_instruction[] = { | |||
| 207 | { "bbl", 1, 0, { 25, 27, 0x00000005 }}, | 207 | { "bbl", 1, 0, { 25, 27, 0x00000005 }}, |
| 208 | }; | 208 | }; |
| 209 | 209 | ||
| 210 | const ISEITEM arm_exclusion_code[] = { | 210 | const InstructionSetEncodingItem arm_exclusion_code[] = { |
| 211 | { "vmla", 0, ARMVFP2, { 0 }}, | 211 | { "vmla", 0, ARMVFP2, { 0 }}, |
| 212 | { "vmls", 0, ARMVFP2, { 0 }}, | 212 | { "vmls", 0, ARMVFP2, { 0 }}, |
| 213 | { "vnmla", 0, ARMVFP2, { 0 }}, | 213 | { "vnmla", 0, ARMVFP2, { 0 }}, |
| @@ -414,14 +414,13 @@ const ISEITEM arm_exclusion_code[] = { | |||
| 414 | { "invalid", 0, INVALID, { 0 }} | 414 | { "invalid", 0, INVALID, { 0 }} |
| 415 | }; | 415 | }; |
| 416 | 416 | ||
| 417 | int decode_arm_instr(uint32_t instr, int32_t *idx) { | 417 | ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) { |
| 418 | int n = 0; | 418 | int n = 0; |
| 419 | int base = 0; | 419 | int base = 0; |
| 420 | int ret = DECODE_FAILURE; | 420 | int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem); |
| 421 | int i = 0; | 421 | ARMDecodeStatus ret = ARMDecodeStatus::FAILURE; |
| 422 | int instr_slots = sizeof(arm_instruction) / sizeof(ISEITEM); | ||
| 423 | 422 | ||
| 424 | for (i = 0; i < instr_slots; i++) { | 423 | for (int i = 0; i < instr_slots; i++) { |
| 425 | n = arm_instruction[i].attribute_value; | 424 | n = arm_instruction[i].attribute_value; |
| 426 | base = 0; | 425 | base = 0; |
| 427 | 426 | ||
| @@ -438,11 +437,11 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) { | |||
| 438 | n--; | 437 | n--; |
| 439 | } | 438 | } |
| 440 | 439 | ||
| 441 | // All conditions is satisfied. | 440 | // All conditions are satisfied. |
| 442 | if (n == 0) | 441 | if (n == 0) |
| 443 | ret = DECODE_SUCCESS; | 442 | ret = ARMDecodeStatus::SUCCESS; |
| 444 | 443 | ||
| 445 | if (ret == DECODE_SUCCESS) { | 444 | if (ret == ARMDecodeStatus::SUCCESS) { |
| 446 | n = arm_exclusion_code[i].attribute_value; | 445 | n = arm_exclusion_code[i].attribute_value; |
| 447 | if (n != 0) { | 446 | if (n != 0) { |
| 448 | base = 0; | 447 | base = 0; |
| @@ -454,13 +453,13 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) { | |||
| 454 | n--; | 453 | n--; |
| 455 | } | 454 | } |
| 456 | 455 | ||
| 457 | // All conditions is satisfied. | 456 | // All conditions are satisfied. |
| 458 | if (n == 0) | 457 | if (n == 0) |
| 459 | ret = DECODE_FAILURE; | 458 | ret = ARMDecodeStatus::FAILURE; |
| 460 | } | 459 | } |
| 461 | } | 460 | } |
| 462 | 461 | ||
| 463 | if (ret == DECODE_SUCCESS) { | 462 | if (ret == ARMDecodeStatus::SUCCESS) { |
| 464 | *idx = i; | 463 | *idx = i; |
| 465 | return ret; | 464 | return ret; |
| 466 | } | 465 | } |
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h index 4b5f5ad7e..d7170e0fc 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.h +++ b/src/core/arm/dyncom/arm_dyncom_dec.h | |||
| @@ -4,22 +4,22 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | int decode_arm_instr(uint32_t instr, int32_t *idx); | 7 | #include "common/common_types.h" |
| 8 | 8 | ||
| 9 | enum DECODE_STATUS { | 9 | enum class ARMDecodeStatus { |
| 10 | DECODE_SUCCESS, | 10 | SUCCESS, |
| 11 | DECODE_FAILURE | 11 | FAILURE |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | struct instruction_set_encoding_item { | 14 | ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx); |
| 15 | |||
| 16 | struct InstructionSetEncodingItem { | ||
| 15 | const char *name; | 17 | const char *name; |
| 16 | int attribute_value; | 18 | int attribute_value; |
| 17 | int version; | 19 | int version; |
| 18 | u32 content[21]; | 20 | u32 content[21]; |
| 19 | }; | 21 | }; |
| 20 | 22 | ||
| 21 | typedef struct instruction_set_encoding_item ISEITEM; | ||
| 22 | |||
| 23 | // ARM versions | 23 | // ARM versions |
| 24 | enum { | 24 | enum { |
| 25 | INVALID = 0, | 25 | INVALID = 0, |
| @@ -36,4 +36,4 @@ enum { | |||
| 36 | ARMV6K, | 36 | ARMV6K, |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | extern const ISEITEM arm_instruction[]; | 39 | extern const InstructionSetEncodingItem arm_instruction[]; |
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index b00eb49a9..d022546ed 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -17,8 +17,8 @@ | |||
| 17 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | 17 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" |
| 18 | #include "core/arm/dyncom/arm_dyncom_thumb.h" | 18 | #include "core/arm/dyncom/arm_dyncom_thumb.h" |
| 19 | #include "core/arm/dyncom/arm_dyncom_run.h" | 19 | #include "core/arm/dyncom/arm_dyncom_run.h" |
| 20 | #include "core/arm/skyeye_common/armdefs.h" | 20 | #include "core/arm/skyeye_common/armstate.h" |
| 21 | #include "core/arm/skyeye_common/armmmu.h" | 21 | #include "core/arm/skyeye_common/armsupp.h" |
| 22 | #include "core/arm/skyeye_common/vfp/vfp.h" | 22 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 23 | 23 | ||
| 24 | Common::Profiling::TimingCategory profile_execute("DynCom::Execute"); | 24 | Common::Profiling::TimingCategory profile_execute("DynCom::Execute"); |
| @@ -47,28 +47,6 @@ enum { | |||
| 47 | 47 | ||
| 48 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); | 48 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); |
| 49 | 49 | ||
| 50 | // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag. | ||
| 51 | // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to | ||
| 52 | // support LDR/STREXD. | ||
| 53 | static const ARMword RESERVATION_GRANULE_MASK = 0xFFFFFFF8; | ||
| 54 | |||
| 55 | // Exclusive memory access | ||
| 56 | static int exclusive_detect(ARMul_State* state, ARMword addr) { | ||
| 57 | if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK)) | ||
| 58 | return 0; | ||
| 59 | else | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | |||
| 63 | static void add_exclusive_addr(ARMul_State* state, ARMword addr){ | ||
| 64 | state->exclusive_tag = addr & RESERVATION_GRANULE_MASK; | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | static void remove_exclusive(ARMul_State* state, ARMword addr){ | ||
| 69 | state->exclusive_tag = 0xFFFFFFFF; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int CondPassed(ARMul_State* cpu, unsigned int cond) { | 50 | static int CondPassed(ARMul_State* cpu, unsigned int cond) { |
| 73 | const u32 NFLAG = cpu->NFlag; | 51 | const u32 NFLAG = cpu->NFlag; |
| 74 | const u32 ZFLAG = cpu->ZFlag; | 52 | const u32 ZFLAG = cpu->ZFlag; |
| @@ -3490,21 +3468,15 @@ enum { | |||
| 3490 | FETCH_FAILURE | 3468 | FETCH_FAILURE |
| 3491 | }; | 3469 | }; |
| 3492 | 3470 | ||
| 3493 | static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) { | 3471 | static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) { |
| 3494 | // Check if in Thumb mode | 3472 | // Check if in Thumb mode |
| 3495 | tdstate ret = thumb_translate (addr, inst, arm_inst, inst_size); | 3473 | ThumbDecodeStatus ret = TranslateThumbInstruction (addr, inst, arm_inst, inst_size); |
| 3496 | if(ret == t_branch){ | 3474 | if (ret == ThumbDecodeStatus::BRANCH) { |
| 3497 | // TODO: FIXME, endian should be judged | ||
| 3498 | u32 tinstr; | ||
| 3499 | if((addr & 0x3) != 0) | ||
| 3500 | tinstr = inst >> 16; | ||
| 3501 | else | ||
| 3502 | tinstr = inst & 0xFFFF; | ||
| 3503 | |||
| 3504 | int inst_index; | 3475 | int inst_index; |
| 3505 | int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); | 3476 | int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); |
| 3477 | u32 tinstr = GetThumbInstruction(inst, addr); | ||
| 3506 | 3478 | ||
| 3507 | switch((tinstr & 0xF800) >> 11){ | 3479 | switch ((tinstr & 0xF800) >> 11) { |
| 3508 | case 26: | 3480 | case 26: |
| 3509 | case 27: | 3481 | case 27: |
| 3510 | if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ | 3482 | if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ |
| @@ -3537,7 +3509,7 @@ static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_s | |||
| 3537 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | 3509 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); |
| 3538 | break; | 3510 | break; |
| 3539 | default: | 3511 | default: |
| 3540 | ret = t_undefined; | 3512 | ret = ThumbDecodeStatus::UNDEFINED; |
| 3541 | break; | 3513 | break; |
| 3542 | } | 3514 | } |
| 3543 | } | 3515 | } |
| @@ -3549,10 +3521,6 @@ enum { | |||
| 3549 | FETCH_EXCEPTION | 3521 | FETCH_EXCEPTION |
| 3550 | }; | 3522 | }; |
| 3551 | 3523 | ||
| 3552 | typedef struct instruction_set_encoding_item ISEITEM; | ||
| 3553 | |||
| 3554 | extern const ISEITEM arm_instruction[]; | ||
| 3555 | |||
| 3556 | static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { | 3524 | static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { |
| 3557 | Common::Profiling::ScopeTimer timer_decode(profile_decode); | 3525 | Common::Profiling::ScopeTimer timer_decode(profile_decode); |
| 3558 | 3526 | ||
| @@ -3574,20 +3542,19 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { | |||
| 3574 | inst = Memory::Read32(phys_addr & 0xFFFFFFFC); | 3542 | inst = Memory::Read32(phys_addr & 0xFFFFFFFC); |
| 3575 | 3543 | ||
| 3576 | size++; | 3544 | size++; |
| 3577 | // If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction | 3545 | // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction |
| 3578 | if (cpu->TFlag) { | 3546 | if (cpu->TFlag) { |
| 3579 | uint32_t arm_inst; | 3547 | uint32_t arm_inst; |
| 3580 | tdstate state = decode_thumb_instr(inst, phys_addr, &arm_inst, &inst_size, &inst_base); | 3548 | ThumbDecodeStatus state = DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base); |
| 3581 | 3549 | ||
| 3582 | // We have translated the branch instruction of thumb in thumb decoder | 3550 | // We have translated the Thumb branch instruction in the Thumb decoder |
| 3583 | if(state == t_branch){ | 3551 | if (state == ThumbDecodeStatus::BRANCH) { |
| 3584 | goto translated; | 3552 | goto translated; |
| 3585 | } | 3553 | } |
| 3586 | inst = arm_inst; | 3554 | inst = arm_inst; |
| 3587 | } | 3555 | } |
| 3588 | 3556 | ||
| 3589 | ret = decode_arm_instr(inst, &idx); | 3557 | if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { |
| 3590 | if (ret == DECODE_FAILURE) { | ||
| 3591 | std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); | 3558 | std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); |
| 3592 | LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst); | 3559 | LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst); |
| 3593 | LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); | 3560 | LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); |
| @@ -3964,7 +3931,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3964 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 3931 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 3965 | if (CurrentModeHasSPSR) { | 3932 | if (CurrentModeHasSPSR) { |
| 3966 | cpu->Cpsr = cpu->Spsr_copy; | 3933 | cpu->Cpsr = cpu->Spsr_copy; |
| 3967 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 3934 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 3968 | LOAD_NZCVT; | 3935 | LOAD_NZCVT; |
| 3969 | } | 3936 | } |
| 3970 | } else if (inst_cream->S) { | 3937 | } else if (inst_cream->S) { |
| @@ -3978,7 +3945,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3978 | goto DISPATCH; | 3945 | goto DISPATCH; |
| 3979 | } | 3946 | } |
| 3980 | } | 3947 | } |
| 3981 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 3948 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 3982 | INC_PC(sizeof(adc_inst)); | 3949 | INC_PC(sizeof(adc_inst)); |
| 3983 | FETCH_INST; | 3950 | FETCH_INST; |
| 3984 | GOTO_NEXT_INST; | 3951 | GOTO_NEXT_INST; |
| @@ -3990,7 +3957,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3990 | 3957 | ||
| 3991 | u32 rn_val = RN; | 3958 | u32 rn_val = RN; |
| 3992 | if (inst_cream->Rn == 15) | 3959 | if (inst_cream->Rn == 15) |
| 3993 | rn_val += 2 * GET_INST_SIZE(cpu); | 3960 | rn_val += 2 * cpu->GetInstructionSize(); |
| 3994 | 3961 | ||
| 3995 | bool carry; | 3962 | bool carry; |
| 3996 | bool overflow; | 3963 | bool overflow; |
| @@ -3999,7 +3966,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3999 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 3966 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 4000 | if (CurrentModeHasSPSR) { | 3967 | if (CurrentModeHasSPSR) { |
| 4001 | cpu->Cpsr = cpu->Spsr_copy; | 3968 | cpu->Cpsr = cpu->Spsr_copy; |
| 4002 | switch_mode(cpu, cpu->Cpsr & 0x1f); | 3969 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); |
| 4003 | LOAD_NZCVT; | 3970 | LOAD_NZCVT; |
| 4004 | } | 3971 | } |
| 4005 | } else if (inst_cream->S) { | 3972 | } else if (inst_cream->S) { |
| @@ -4013,7 +3980,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4013 | goto DISPATCH; | 3980 | goto DISPATCH; |
| 4014 | } | 3981 | } |
| 4015 | } | 3982 | } |
| 4016 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 3983 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4017 | INC_PC(sizeof(add_inst)); | 3984 | INC_PC(sizeof(add_inst)); |
| 4018 | FETCH_INST; | 3985 | FETCH_INST; |
| 4019 | GOTO_NEXT_INST; | 3986 | GOTO_NEXT_INST; |
| @@ -4028,7 +3995,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4028 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 3995 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 4029 | if (CurrentModeHasSPSR) { | 3996 | if (CurrentModeHasSPSR) { |
| 4030 | cpu->Cpsr = cpu->Spsr_copy; | 3997 | cpu->Cpsr = cpu->Spsr_copy; |
| 4031 | switch_mode(cpu, cpu->Cpsr & 0x1f); | 3998 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); |
| 4032 | LOAD_NZCVT; | 3999 | LOAD_NZCVT; |
| 4033 | } | 4000 | } |
| 4034 | } else if (inst_cream->S) { | 4001 | } else if (inst_cream->S) { |
| @@ -4041,7 +4008,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4041 | goto DISPATCH; | 4008 | goto DISPATCH; |
| 4042 | } | 4009 | } |
| 4043 | } | 4010 | } |
| 4044 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4011 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4045 | INC_PC(sizeof(and_inst)); | 4012 | INC_PC(sizeof(and_inst)); |
| 4046 | FETCH_INST; | 4013 | FETCH_INST; |
| 4047 | GOTO_NEXT_INST; | 4014 | GOTO_NEXT_INST; |
| @@ -4057,7 +4024,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4057 | INC_PC(sizeof(bbl_inst)); | 4024 | INC_PC(sizeof(bbl_inst)); |
| 4058 | goto DISPATCH; | 4025 | goto DISPATCH; |
| 4059 | } | 4026 | } |
| 4060 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4027 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4061 | INC_PC(sizeof(bbl_inst)); | 4028 | INC_PC(sizeof(bbl_inst)); |
| 4062 | goto DISPATCH; | 4029 | goto DISPATCH; |
| 4063 | } | 4030 | } |
| @@ -4067,14 +4034,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4067 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | 4034 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { |
| 4068 | u32 lop = RN; | 4035 | u32 lop = RN; |
| 4069 | if (inst_cream->Rn == 15) { | 4036 | if (inst_cream->Rn == 15) { |
| 4070 | lop += 2 * GET_INST_SIZE(cpu); | 4037 | lop += 2 * cpu->GetInstructionSize(); |
| 4071 | } | 4038 | } |
| 4072 | u32 rop = SHIFTER_OPERAND; | 4039 | u32 rop = SHIFTER_OPERAND; |
| 4073 | RD = lop & (~rop); | 4040 | RD = lop & (~rop); |
| 4074 | if ((inst_cream->S) && (inst_cream->Rd == 15)) { | 4041 | if ((inst_cream->S) && (inst_cream->Rd == 15)) { |
| 4075 | if (CurrentModeHasSPSR) { | 4042 | if (CurrentModeHasSPSR) { |
| 4076 | cpu->Cpsr = cpu->Spsr_copy; | 4043 | cpu->Cpsr = cpu->Spsr_copy; |
| 4077 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 4044 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 4078 | LOAD_NZCVT; | 4045 | LOAD_NZCVT; |
| 4079 | } | 4046 | } |
| 4080 | } else if (inst_cream->S) { | 4047 | } else if (inst_cream->S) { |
| @@ -4087,7 +4054,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4087 | goto DISPATCH; | 4054 | goto DISPATCH; |
| 4088 | } | 4055 | } |
| 4089 | } | 4056 | } |
| 4090 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4057 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4091 | INC_PC(sizeof(bic_inst)); | 4058 | INC_PC(sizeof(bic_inst)); |
| 4092 | FETCH_INST; | 4059 | FETCH_INST; |
| 4093 | GOTO_NEXT_INST; | 4060 | GOTO_NEXT_INST; |
| @@ -4098,7 +4065,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4098 | bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; | 4065 | bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; |
| 4099 | LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm); | 4066 | LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm); |
| 4100 | } | 4067 | } |
| 4101 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4068 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4102 | INC_PC(sizeof(bkpt_inst)); | 4069 | INC_PC(sizeof(bkpt_inst)); |
| 4103 | FETCH_INST; | 4070 | FETCH_INST; |
| 4104 | GOTO_NEXT_INST; | 4071 | GOTO_NEXT_INST; |
| @@ -4109,13 +4076,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4109 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | 4076 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { |
| 4110 | unsigned int inst = inst_cream->inst; | 4077 | unsigned int inst = inst_cream->inst; |
| 4111 | if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { | 4078 | if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { |
| 4112 | cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); | 4079 | cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize()); |
| 4113 | if(cpu->TFlag) | 4080 | if(cpu->TFlag) |
| 4114 | cpu->Reg[14] |= 0x1; | 4081 | cpu->Reg[14] |= 0x1; |
| 4115 | cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe; | 4082 | cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe; |
| 4116 | cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1; | 4083 | cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1; |
| 4117 | } else { | 4084 | } else { |
| 4118 | cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); | 4085 | cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize()); |
| 4119 | cpu->TFlag = 0x1; | 4086 | cpu->TFlag = 0x1; |
| 4120 | int signed_int = inst_cream->val.signed_immed_24; | 4087 | int signed_int = inst_cream->val.signed_immed_24; |
| 4121 | signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int; | 4088 | signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int; |
| @@ -4125,7 +4092,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4125 | INC_PC(sizeof(blx_inst)); | 4092 | INC_PC(sizeof(blx_inst)); |
| 4126 | goto DISPATCH; | 4093 | goto DISPATCH; |
| 4127 | } | 4094 | } |
| 4128 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4095 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4129 | INC_PC(sizeof(blx_inst)); | 4096 | INC_PC(sizeof(blx_inst)); |
| 4130 | goto DISPATCH; | 4097 | goto DISPATCH; |
| 4131 | } | 4098 | } |
| @@ -4144,16 +4111,18 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4144 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | 4111 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { |
| 4145 | bx_inst* const inst_cream = (bx_inst*)inst_base->component; | 4112 | bx_inst* const inst_cream = (bx_inst*)inst_base->component; |
| 4146 | 4113 | ||
| 4114 | u32 address = RM; | ||
| 4115 | |||
| 4147 | if (inst_cream->Rm == 15) | 4116 | if (inst_cream->Rm == 15) |
| 4148 | LOG_WARNING(Core_ARM11, "BX at pc %x: use of Rm = R15 is discouraged", cpu->Reg[15]); | 4117 | address += 2 * cpu->GetInstructionSize(); |
| 4149 | 4118 | ||
| 4150 | cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; | 4119 | cpu->TFlag = address & 1; |
| 4151 | cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; | 4120 | cpu->Reg[15] = address & 0xfffffffe; |
| 4152 | INC_PC(sizeof(bx_inst)); | 4121 | INC_PC(sizeof(bx_inst)); |
| 4153 | goto DISPATCH; | 4122 | goto DISPATCH; |
| 4154 | } | 4123 | } |
| 4155 | 4124 | ||
| 4156 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4125 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4157 | INC_PC(sizeof(bx_inst)); | 4126 | INC_PC(sizeof(bx_inst)); |
| 4158 | goto DISPATCH; | 4127 | goto DISPATCH; |
| 4159 | } | 4128 | } |
| @@ -4165,7 +4134,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4165 | cpu->NumInstrsToExecute = 0; | 4134 | cpu->NumInstrsToExecute = 0; |
| 4166 | return num_instrs; | 4135 | return num_instrs; |
| 4167 | } | 4136 | } |
| 4168 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4137 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4169 | INC_PC(sizeof(cdp_inst)); | 4138 | INC_PC(sizeof(cdp_inst)); |
| 4170 | FETCH_INST; | 4139 | FETCH_INST; |
| 4171 | GOTO_NEXT_INST; | 4140 | GOTO_NEXT_INST; |
| @@ -4173,10 +4142,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4173 | 4142 | ||
| 4174 | CLREX_INST: | 4143 | CLREX_INST: |
| 4175 | { | 4144 | { |
| 4176 | remove_exclusive(cpu, 0); | 4145 | cpu->UnsetExclusiveMemoryAddress(); |
| 4177 | cpu->exclusive_state = 0; | 4146 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4178 | |||
| 4179 | cpu->Reg[15] += GET_INST_SIZE(cpu); | ||
| 4180 | INC_PC(sizeof(clrex_inst)); | 4147 | INC_PC(sizeof(clrex_inst)); |
| 4181 | FETCH_INST; | 4148 | FETCH_INST; |
| 4182 | GOTO_NEXT_INST; | 4149 | GOTO_NEXT_INST; |
| @@ -4187,7 +4154,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4187 | clz_inst* inst_cream = (clz_inst*)inst_base->component; | 4154 | clz_inst* inst_cream = (clz_inst*)inst_base->component; |
| 4188 | RD = clz(RM); | 4155 | RD = clz(RM); |
| 4189 | } | 4156 | } |
| 4190 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4157 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4191 | INC_PC(sizeof(clz_inst)); | 4158 | INC_PC(sizeof(clz_inst)); |
| 4192 | FETCH_INST; | 4159 | FETCH_INST; |
| 4193 | GOTO_NEXT_INST; | 4160 | GOTO_NEXT_INST; |
| @@ -4206,7 +4173,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4206 | cpu->CFlag = carry; | 4173 | cpu->CFlag = carry; |
| 4207 | cpu->VFlag = overflow; | 4174 | cpu->VFlag = overflow; |
| 4208 | } | 4175 | } |
| 4209 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4176 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4210 | INC_PC(sizeof(cmn_inst)); | 4177 | INC_PC(sizeof(cmn_inst)); |
| 4211 | FETCH_INST; | 4178 | FETCH_INST; |
| 4212 | GOTO_NEXT_INST; | 4179 | GOTO_NEXT_INST; |
| @@ -4218,7 +4185,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4218 | 4185 | ||
| 4219 | u32 rn_val = RN; | 4186 | u32 rn_val = RN; |
| 4220 | if (inst_cream->Rn == 15) | 4187 | if (inst_cream->Rn == 15) |
| 4221 | rn_val += 2 * GET_INST_SIZE(cpu); | 4188 | rn_val += 2 * cpu->GetInstructionSize(); |
| 4222 | 4189 | ||
| 4223 | bool carry; | 4190 | bool carry; |
| 4224 | bool overflow; | 4191 | bool overflow; |
| @@ -4229,7 +4196,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4229 | cpu->CFlag = carry; | 4196 | cpu->CFlag = carry; |
| 4230 | cpu->VFlag = overflow; | 4197 | cpu->VFlag = overflow; |
| 4231 | } | 4198 | } |
| 4232 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4199 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4233 | INC_PC(sizeof(cmp_inst)); | 4200 | INC_PC(sizeof(cmp_inst)); |
| 4234 | FETCH_INST; | 4201 | FETCH_INST; |
| 4235 | GOTO_NEXT_INST; | 4202 | GOTO_NEXT_INST; |
| @@ -4239,7 +4206,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4239 | cps_inst *inst_cream = (cps_inst *)inst_base->component; | 4206 | cps_inst *inst_cream = (cps_inst *)inst_base->component; |
| 4240 | uint32_t aif_val = 0; | 4207 | uint32_t aif_val = 0; |
| 4241 | uint32_t aif_mask = 0; | 4208 | uint32_t aif_mask = 0; |
| 4242 | if (InAPrivilegedMode(cpu)) { | 4209 | if (cpu->InAPrivilegedMode()) { |
| 4243 | if (inst_cream->imod1) { | 4210 | if (inst_cream->imod1) { |
| 4244 | if (inst_cream->A) { | 4211 | if (inst_cream->A) { |
| 4245 | aif_val |= (inst_cream->imod0 << 8); | 4212 | aif_val |= (inst_cream->imod0 << 8); |
| @@ -4258,10 +4225,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4258 | } | 4225 | } |
| 4259 | if (inst_cream->mmod) { | 4226 | if (inst_cream->mmod) { |
| 4260 | cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; | 4227 | cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; |
| 4261 | switch_mode(cpu, inst_cream->mode); | 4228 | cpu->ChangePrivilegeMode(inst_cream->mode); |
| 4262 | } | 4229 | } |
| 4263 | } | 4230 | } |
| 4264 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4231 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4265 | INC_PC(sizeof(cps_inst)); | 4232 | INC_PC(sizeof(cps_inst)); |
| 4266 | FETCH_INST; | 4233 | FETCH_INST; |
| 4267 | GOTO_NEXT_INST; | 4234 | GOTO_NEXT_INST; |
| @@ -4277,7 +4244,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4277 | goto DISPATCH; | 4244 | goto DISPATCH; |
| 4278 | } | 4245 | } |
| 4279 | } | 4246 | } |
| 4280 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4247 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4281 | INC_PC(sizeof(mov_inst)); | 4248 | INC_PC(sizeof(mov_inst)); |
| 4282 | FETCH_INST; | 4249 | FETCH_INST; |
| 4283 | GOTO_NEXT_INST; | 4250 | GOTO_NEXT_INST; |
| @@ -4289,14 +4256,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4289 | 4256 | ||
| 4290 | u32 lop = RN; | 4257 | u32 lop = RN; |
| 4291 | if (inst_cream->Rn == 15) { | 4258 | if (inst_cream->Rn == 15) { |
| 4292 | lop += 2 * GET_INST_SIZE(cpu); | 4259 | lop += 2 * cpu->GetInstructionSize(); |
| 4293 | } | 4260 | } |
| 4294 | u32 rop = SHIFTER_OPERAND; | 4261 | u32 rop = SHIFTER_OPERAND; |
| 4295 | RD = lop ^ rop; | 4262 | RD = lop ^ rop; |
| 4296 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 4263 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 4297 | if (CurrentModeHasSPSR) { | 4264 | if (CurrentModeHasSPSR) { |
| 4298 | cpu->Cpsr = cpu->Spsr_copy; | 4265 | cpu->Cpsr = cpu->Spsr_copy; |
| 4299 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 4266 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 4300 | LOAD_NZCVT; | 4267 | LOAD_NZCVT; |
| 4301 | } | 4268 | } |
| 4302 | } else if (inst_cream->S) { | 4269 | } else if (inst_cream->S) { |
| @@ -4309,7 +4276,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4309 | goto DISPATCH; | 4276 | goto DISPATCH; |
| 4310 | } | 4277 | } |
| 4311 | } | 4278 | } |
| 4312 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4279 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4313 | INC_PC(sizeof(eor_inst)); | 4280 | INC_PC(sizeof(eor_inst)); |
| 4314 | FETCH_INST; | 4281 | FETCH_INST; |
| 4315 | GOTO_NEXT_INST; | 4282 | GOTO_NEXT_INST; |
| @@ -4318,7 +4285,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4318 | { | 4285 | { |
| 4319 | // Instruction not implemented | 4286 | // Instruction not implemented |
| 4320 | //LOG_CRITICAL(Core_ARM11, "unimplemented instruction"); | 4287 | //LOG_CRITICAL(Core_ARM11, "unimplemented instruction"); |
| 4321 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4288 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4322 | INC_PC(sizeof(ldc_inst)); | 4289 | INC_PC(sizeof(ldc_inst)); |
| 4323 | FETCH_INST; | 4290 | FETCH_INST; |
| 4324 | GOTO_NEXT_INST; | 4291 | GOTO_NEXT_INST; |
| @@ -4333,30 +4300,30 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4333 | if (BIT(inst, 22) && !BIT(inst, 15)) { | 4300 | if (BIT(inst, 22) && !BIT(inst, 15)) { |
| 4334 | for (int i = 0; i < 13; i++) { | 4301 | for (int i = 0; i < 13; i++) { |
| 4335 | if(BIT(inst, i)) { | 4302 | if(BIT(inst, i)) { |
| 4336 | cpu->Reg[i] = ReadMemory32(cpu, addr); | 4303 | cpu->Reg[i] = cpu->ReadMemory32(addr); |
| 4337 | addr += 4; | 4304 | addr += 4; |
| 4338 | } | 4305 | } |
| 4339 | } | 4306 | } |
| 4340 | if (BIT(inst, 13)) { | 4307 | if (BIT(inst, 13)) { |
| 4341 | if (cpu->Mode == USER32MODE) | 4308 | if (cpu->Mode == USER32MODE) |
| 4342 | cpu->Reg[13] = ReadMemory32(cpu, addr); | 4309 | cpu->Reg[13] = cpu->ReadMemory32(addr); |
| 4343 | else | 4310 | else |
| 4344 | cpu->Reg_usr[0] = ReadMemory32(cpu, addr); | 4311 | cpu->Reg_usr[0] = cpu->ReadMemory32(addr); |
| 4345 | 4312 | ||
| 4346 | addr += 4; | 4313 | addr += 4; |
| 4347 | } | 4314 | } |
| 4348 | if (BIT(inst, 14)) { | 4315 | if (BIT(inst, 14)) { |
| 4349 | if (cpu->Mode == USER32MODE) | 4316 | if (cpu->Mode == USER32MODE) |
| 4350 | cpu->Reg[14] = ReadMemory32(cpu, addr); | 4317 | cpu->Reg[14] = cpu->ReadMemory32(addr); |
| 4351 | else | 4318 | else |
| 4352 | cpu->Reg_usr[1] = ReadMemory32(cpu, addr); | 4319 | cpu->Reg_usr[1] = cpu->ReadMemory32(addr); |
| 4353 | 4320 | ||
| 4354 | addr += 4; | 4321 | addr += 4; |
| 4355 | } | 4322 | } |
| 4356 | } else if (!BIT(inst, 22)) { | 4323 | } else if (!BIT(inst, 22)) { |
| 4357 | for(int i = 0; i < 16; i++ ){ | 4324 | for(int i = 0; i < 16; i++ ){ |
| 4358 | if(BIT(inst, i)){ | 4325 | if(BIT(inst, i)){ |
| 4359 | unsigned int ret = ReadMemory32(cpu, addr); | 4326 | unsigned int ret = cpu->ReadMemory32(addr); |
| 4360 | 4327 | ||
| 4361 | // For armv5t, should enter thumb when bits[0] is non-zero. | 4328 | // For armv5t, should enter thumb when bits[0] is non-zero. |
| 4362 | if(i == 15){ | 4329 | if(i == 15){ |
| @@ -4371,18 +4338,18 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4371 | } else if (BIT(inst, 22) && BIT(inst, 15)) { | 4338 | } else if (BIT(inst, 22) && BIT(inst, 15)) { |
| 4372 | for(int i = 0; i < 15; i++ ){ | 4339 | for(int i = 0; i < 15; i++ ){ |
| 4373 | if(BIT(inst, i)){ | 4340 | if(BIT(inst, i)){ |
| 4374 | cpu->Reg[i] = ReadMemory32(cpu, addr); | 4341 | cpu->Reg[i] = cpu->ReadMemory32(addr); |
| 4375 | addr += 4; | 4342 | addr += 4; |
| 4376 | } | 4343 | } |
| 4377 | } | 4344 | } |
| 4378 | 4345 | ||
| 4379 | if (CurrentModeHasSPSR) { | 4346 | if (CurrentModeHasSPSR) { |
| 4380 | cpu->Cpsr = cpu->Spsr_copy; | 4347 | cpu->Cpsr = cpu->Spsr_copy; |
| 4381 | switch_mode(cpu, cpu->Cpsr & 0x1f); | 4348 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); |
| 4382 | LOAD_NZCVT; | 4349 | LOAD_NZCVT; |
| 4383 | } | 4350 | } |
| 4384 | 4351 | ||
| 4385 | cpu->Reg[15] = ReadMemory32(cpu, addr); | 4352 | cpu->Reg[15] = cpu->ReadMemory32(addr); |
| 4386 | } | 4353 | } |
| 4387 | 4354 | ||
| 4388 | if (BIT(inst, 15)) { | 4355 | if (BIT(inst, 15)) { |
| @@ -4390,7 +4357,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4390 | goto DISPATCH; | 4357 | goto DISPATCH; |
| 4391 | } | 4358 | } |
| 4392 | } | 4359 | } |
| 4393 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4360 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4394 | INC_PC(sizeof(ldst_inst)); | 4361 | INC_PC(sizeof(ldst_inst)); |
| 4395 | FETCH_INST; | 4362 | FETCH_INST; |
| 4396 | GOTO_NEXT_INST; | 4363 | GOTO_NEXT_INST; |
| @@ -4408,7 +4375,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4408 | } | 4375 | } |
| 4409 | RD = operand2; | 4376 | RD = operand2; |
| 4410 | } | 4377 | } |
| 4411 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4378 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4412 | INC_PC(sizeof(sxth_inst)); | 4379 | INC_PC(sizeof(sxth_inst)); |
| 4413 | FETCH_INST; | 4380 | FETCH_INST; |
| 4414 | GOTO_NEXT_INST; | 4381 | GOTO_NEXT_INST; |
| @@ -4418,7 +4385,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4418 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | 4385 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; |
| 4419 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4386 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4420 | 4387 | ||
| 4421 | unsigned int value = ReadMemory32(cpu, addr); | 4388 | unsigned int value = cpu->ReadMemory32(addr); |
| 4422 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | 4389 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; |
| 4423 | 4390 | ||
| 4424 | if (BITS(inst_cream->inst, 12, 15) == 15) { | 4391 | if (BITS(inst_cream->inst, 12, 15) == 15) { |
| @@ -4429,7 +4396,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4429 | goto DISPATCH; | 4396 | goto DISPATCH; |
| 4430 | } | 4397 | } |
| 4431 | 4398 | ||
| 4432 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4399 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4433 | INC_PC(sizeof(ldst_inst)); | 4400 | INC_PC(sizeof(ldst_inst)); |
| 4434 | FETCH_INST; | 4401 | FETCH_INST; |
| 4435 | GOTO_NEXT_INST; | 4402 | GOTO_NEXT_INST; |
| @@ -4440,7 +4407,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4440 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; | 4407 | ldst_inst *inst_cream = (ldst_inst *)inst_base->component; |
| 4441 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4408 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4442 | 4409 | ||
| 4443 | unsigned int value = ReadMemory32(cpu, addr); | 4410 | unsigned int value = cpu->ReadMemory32(addr); |
| 4444 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | 4411 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; |
| 4445 | 4412 | ||
| 4446 | if (BITS(inst_cream->inst, 12, 15) == 15) { | 4413 | if (BITS(inst_cream->inst, 12, 15) == 15) { |
| @@ -4451,7 +4418,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4451 | goto DISPATCH; | 4418 | goto DISPATCH; |
| 4452 | } | 4419 | } |
| 4453 | } | 4420 | } |
| 4454 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4421 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4455 | INC_PC(sizeof(ldst_inst)); | 4422 | INC_PC(sizeof(ldst_inst)); |
| 4456 | FETCH_INST; | 4423 | FETCH_INST; |
| 4457 | GOTO_NEXT_INST; | 4424 | GOTO_NEXT_INST; |
| @@ -4462,7 +4429,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4462 | uxth_inst* inst_cream = (uxth_inst*)inst_base->component; | 4429 | uxth_inst* inst_cream = (uxth_inst*)inst_base->component; |
| 4463 | RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; | 4430 | RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; |
| 4464 | } | 4431 | } |
| 4465 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4432 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4466 | INC_PC(sizeof(uxth_inst)); | 4433 | INC_PC(sizeof(uxth_inst)); |
| 4467 | FETCH_INST; | 4434 | FETCH_INST; |
| 4468 | GOTO_NEXT_INST; | 4435 | GOTO_NEXT_INST; |
| @@ -4475,7 +4442,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4475 | 4442 | ||
| 4476 | RD = RN + operand2; | 4443 | RD = RN + operand2; |
| 4477 | } | 4444 | } |
| 4478 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4445 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4479 | INC_PC(sizeof(uxtah_inst)); | 4446 | INC_PC(sizeof(uxtah_inst)); |
| 4480 | FETCH_INST; | 4447 | FETCH_INST; |
| 4481 | GOTO_NEXT_INST; | 4448 | GOTO_NEXT_INST; |
| @@ -4493,7 +4460,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4493 | goto DISPATCH; | 4460 | goto DISPATCH; |
| 4494 | } | 4461 | } |
| 4495 | } | 4462 | } |
| 4496 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4463 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4497 | INC_PC(sizeof(ldst_inst)); | 4464 | INC_PC(sizeof(ldst_inst)); |
| 4498 | FETCH_INST; | 4465 | FETCH_INST; |
| 4499 | GOTO_NEXT_INST; | 4466 | GOTO_NEXT_INST; |
| @@ -4511,7 +4478,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4511 | goto DISPATCH; | 4478 | goto DISPATCH; |
| 4512 | } | 4479 | } |
| 4513 | } | 4480 | } |
| 4514 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4481 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4515 | INC_PC(sizeof(ldst_inst)); | 4482 | INC_PC(sizeof(ldst_inst)); |
| 4516 | FETCH_INST; | 4483 | FETCH_INST; |
| 4517 | GOTO_NEXT_INST; | 4484 | GOTO_NEXT_INST; |
| @@ -4525,8 +4492,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4525 | 4492 | ||
| 4526 | // The 3DS doesn't have LPAE (Large Physical Access Extension), so it | 4493 | // The 3DS doesn't have LPAE (Large Physical Access Extension), so it |
| 4527 | // wouldn't do this as a single read. | 4494 | // wouldn't do this as a single read. |
| 4528 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = ReadMemory32(cpu, addr); | 4495 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = cpu->ReadMemory32(addr); |
| 4529 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = ReadMemory32(cpu, addr + 4); | 4496 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = cpu->ReadMemory32(addr + 4); |
| 4530 | 4497 | ||
| 4531 | // No dispatch since this operation should not modify R15 | 4498 | // No dispatch since this operation should not modify R15 |
| 4532 | } | 4499 | } |
| @@ -4542,16 +4509,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4542 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4509 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4543 | unsigned int read_addr = RN; | 4510 | unsigned int read_addr = RN; |
| 4544 | 4511 | ||
| 4545 | add_exclusive_addr(cpu, read_addr); | 4512 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4546 | cpu->exclusive_state = 1; | ||
| 4547 | 4513 | ||
| 4548 | RD = ReadMemory32(cpu, read_addr); | 4514 | RD = cpu->ReadMemory32(read_addr); |
| 4549 | if (inst_cream->Rd == 15) { | 4515 | if (inst_cream->Rd == 15) { |
| 4550 | INC_PC(sizeof(generic_arm_inst)); | 4516 | INC_PC(sizeof(generic_arm_inst)); |
| 4551 | goto DISPATCH; | 4517 | goto DISPATCH; |
| 4552 | } | 4518 | } |
| 4553 | } | 4519 | } |
| 4554 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4520 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4555 | INC_PC(sizeof(generic_arm_inst)); | 4521 | INC_PC(sizeof(generic_arm_inst)); |
| 4556 | FETCH_INST; | 4522 | FETCH_INST; |
| 4557 | GOTO_NEXT_INST; | 4523 | GOTO_NEXT_INST; |
| @@ -4562,8 +4528,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4562 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4528 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4563 | unsigned int read_addr = RN; | 4529 | unsigned int read_addr = RN; |
| 4564 | 4530 | ||
| 4565 | add_exclusive_addr(cpu, read_addr); | 4531 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4566 | cpu->exclusive_state = 1; | ||
| 4567 | 4532 | ||
| 4568 | RD = Memory::Read8(read_addr); | 4533 | RD = Memory::Read8(read_addr); |
| 4569 | if (inst_cream->Rd == 15) { | 4534 | if (inst_cream->Rd == 15) { |
| @@ -4571,7 +4536,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4571 | goto DISPATCH; | 4536 | goto DISPATCH; |
| 4572 | } | 4537 | } |
| 4573 | } | 4538 | } |
| 4574 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4539 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4575 | INC_PC(sizeof(generic_arm_inst)); | 4540 | INC_PC(sizeof(generic_arm_inst)); |
| 4576 | FETCH_INST; | 4541 | FETCH_INST; |
| 4577 | GOTO_NEXT_INST; | 4542 | GOTO_NEXT_INST; |
| @@ -4582,16 +4547,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4582 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4547 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4583 | unsigned int read_addr = RN; | 4548 | unsigned int read_addr = RN; |
| 4584 | 4549 | ||
| 4585 | add_exclusive_addr(cpu, read_addr); | 4550 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4586 | cpu->exclusive_state = 1; | ||
| 4587 | 4551 | ||
| 4588 | RD = ReadMemory16(cpu, read_addr); | 4552 | RD = cpu->ReadMemory16(read_addr); |
| 4589 | if (inst_cream->Rd == 15) { | 4553 | if (inst_cream->Rd == 15) { |
| 4590 | INC_PC(sizeof(generic_arm_inst)); | 4554 | INC_PC(sizeof(generic_arm_inst)); |
| 4591 | goto DISPATCH; | 4555 | goto DISPATCH; |
| 4592 | } | 4556 | } |
| 4593 | } | 4557 | } |
| 4594 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4558 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4595 | INC_PC(sizeof(generic_arm_inst)); | 4559 | INC_PC(sizeof(generic_arm_inst)); |
| 4596 | FETCH_INST; | 4560 | FETCH_INST; |
| 4597 | GOTO_NEXT_INST; | 4561 | GOTO_NEXT_INST; |
| @@ -4602,18 +4566,17 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4602 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 4566 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 4603 | unsigned int read_addr = RN; | 4567 | unsigned int read_addr = RN; |
| 4604 | 4568 | ||
| 4605 | add_exclusive_addr(cpu, read_addr); | 4569 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4606 | cpu->exclusive_state = 1; | ||
| 4607 | 4570 | ||
| 4608 | RD = ReadMemory32(cpu, read_addr); | 4571 | RD = cpu->ReadMemory32(read_addr); |
| 4609 | RD2 = ReadMemory32(cpu, read_addr + 4); | 4572 | RD2 = cpu->ReadMemory32(read_addr + 4); |
| 4610 | 4573 | ||
| 4611 | if (inst_cream->Rd == 15) { | 4574 | if (inst_cream->Rd == 15) { |
| 4612 | INC_PC(sizeof(generic_arm_inst)); | 4575 | INC_PC(sizeof(generic_arm_inst)); |
| 4613 | goto DISPATCH; | 4576 | goto DISPATCH; |
| 4614 | } | 4577 | } |
| 4615 | } | 4578 | } |
| 4616 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4579 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4617 | INC_PC(sizeof(generic_arm_inst)); | 4580 | INC_PC(sizeof(generic_arm_inst)); |
| 4618 | FETCH_INST; | 4581 | FETCH_INST; |
| 4619 | GOTO_NEXT_INST; | 4582 | GOTO_NEXT_INST; |
| @@ -4624,13 +4587,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4624 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4587 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4625 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4588 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4626 | 4589 | ||
| 4627 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ReadMemory16(cpu, addr); | 4590 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr); |
| 4628 | if (BITS(inst_cream->inst, 12, 15) == 15) { | 4591 | if (BITS(inst_cream->inst, 12, 15) == 15) { |
| 4629 | INC_PC(sizeof(ldst_inst)); | 4592 | INC_PC(sizeof(ldst_inst)); |
| 4630 | goto DISPATCH; | 4593 | goto DISPATCH; |
| 4631 | } | 4594 | } |
| 4632 | } | 4595 | } |
| 4633 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4596 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4634 | INC_PC(sizeof(ldst_inst)); | 4597 | INC_PC(sizeof(ldst_inst)); |
| 4635 | FETCH_INST; | 4598 | FETCH_INST; |
| 4636 | GOTO_NEXT_INST; | 4599 | GOTO_NEXT_INST; |
| @@ -4650,7 +4613,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4650 | goto DISPATCH; | 4613 | goto DISPATCH; |
| 4651 | } | 4614 | } |
| 4652 | } | 4615 | } |
| 4653 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4616 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4654 | INC_PC(sizeof(ldst_inst)); | 4617 | INC_PC(sizeof(ldst_inst)); |
| 4655 | FETCH_INST; | 4618 | FETCH_INST; |
| 4656 | GOTO_NEXT_INST; | 4619 | GOTO_NEXT_INST; |
| @@ -4661,7 +4624,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4661 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4624 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4662 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4625 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4663 | 4626 | ||
| 4664 | unsigned int value = ReadMemory16(cpu, addr); | 4627 | unsigned int value = cpu->ReadMemory16(addr); |
| 4665 | if (BIT(value, 15)) { | 4628 | if (BIT(value, 15)) { |
| 4666 | value |= 0xffff0000; | 4629 | value |= 0xffff0000; |
| 4667 | } | 4630 | } |
| @@ -4671,7 +4634,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4671 | goto DISPATCH; | 4634 | goto DISPATCH; |
| 4672 | } | 4635 | } |
| 4673 | } | 4636 | } |
| 4674 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4637 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4675 | INC_PC(sizeof(ldst_inst)); | 4638 | INC_PC(sizeof(ldst_inst)); |
| 4676 | FETCH_INST; | 4639 | FETCH_INST; |
| 4677 | GOTO_NEXT_INST; | 4640 | GOTO_NEXT_INST; |
| @@ -4682,7 +4645,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4682 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4645 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4683 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4646 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4684 | 4647 | ||
| 4685 | unsigned int value = ReadMemory32(cpu, addr); | 4648 | unsigned int value = cpu->ReadMemory32(addr); |
| 4686 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | 4649 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; |
| 4687 | 4650 | ||
| 4688 | if (BITS(inst_cream->inst, 12, 15) == 15) { | 4651 | if (BITS(inst_cream->inst, 12, 15) == 15) { |
| @@ -4690,7 +4653,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4690 | goto DISPATCH; | 4653 | goto DISPATCH; |
| 4691 | } | 4654 | } |
| 4692 | } | 4655 | } |
| 4693 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4656 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4694 | INC_PC(sizeof(ldst_inst)); | 4657 | INC_PC(sizeof(ldst_inst)); |
| 4695 | FETCH_INST; | 4658 | FETCH_INST; |
| 4696 | GOTO_NEXT_INST; | 4659 | GOTO_NEXT_INST; |
| @@ -4705,10 +4668,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4705 | DEBUG_MSG; | 4668 | DEBUG_MSG; |
| 4706 | } else { | 4669 | } else { |
| 4707 | if (inst_cream->cp_num == 15) | 4670 | if (inst_cream->cp_num == 15) |
| 4708 | WriteCP15Register(cpu, RD, CRn, OPCODE_1, CRm, OPCODE_2); | 4671 | cpu->WriteCP15Register(RD, CRn, OPCODE_1, CRm, OPCODE_2); |
| 4709 | } | 4672 | } |
| 4710 | } | 4673 | } |
| 4711 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4674 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4712 | INC_PC(sizeof(mcr_inst)); | 4675 | INC_PC(sizeof(mcr_inst)); |
| 4713 | FETCH_INST; | 4676 | FETCH_INST; |
| 4714 | GOTO_NEXT_INST; | 4677 | GOTO_NEXT_INST; |
| @@ -4725,7 +4688,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4725 | inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2); | 4688 | inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2); |
| 4726 | } | 4689 | } |
| 4727 | 4690 | ||
| 4728 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4691 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4729 | INC_PC(sizeof(mcrr_inst)); | 4692 | INC_PC(sizeof(mcrr_inst)); |
| 4730 | FETCH_INST; | 4693 | FETCH_INST; |
| 4731 | GOTO_NEXT_INST; | 4694 | GOTO_NEXT_INST; |
| @@ -4750,7 +4713,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4750 | goto DISPATCH; | 4713 | goto DISPATCH; |
| 4751 | } | 4714 | } |
| 4752 | } | 4715 | } |
| 4753 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4716 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4754 | INC_PC(sizeof(mla_inst)); | 4717 | INC_PC(sizeof(mla_inst)); |
| 4755 | FETCH_INST; | 4718 | FETCH_INST; |
| 4756 | GOTO_NEXT_INST; | 4719 | GOTO_NEXT_INST; |
| @@ -4764,7 +4727,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4764 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 4727 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 4765 | if (CurrentModeHasSPSR) { | 4728 | if (CurrentModeHasSPSR) { |
| 4766 | cpu->Cpsr = cpu->Spsr_copy; | 4729 | cpu->Cpsr = cpu->Spsr_copy; |
| 4767 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 4730 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 4768 | LOAD_NZCVT; | 4731 | LOAD_NZCVT; |
| 4769 | } | 4732 | } |
| 4770 | } else if (inst_cream->S) { | 4733 | } else if (inst_cream->S) { |
| @@ -4777,7 +4740,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4777 | goto DISPATCH; | 4740 | goto DISPATCH; |
| 4778 | } | 4741 | } |
| 4779 | } | 4742 | } |
| 4780 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4743 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4781 | INC_PC(sizeof(mov_inst)); | 4744 | INC_PC(sizeof(mov_inst)); |
| 4782 | FETCH_INST; | 4745 | FETCH_INST; |
| 4783 | GOTO_NEXT_INST; | 4746 | GOTO_NEXT_INST; |
| @@ -4798,10 +4761,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4798 | goto END; | 4761 | goto END; |
| 4799 | } else { | 4762 | } else { |
| 4800 | if (inst_cream->cp_num == 15) | 4763 | if (inst_cream->cp_num == 15) |
| 4801 | RD = ReadCP15Register(cpu, CRn, OPCODE_1, CRm, OPCODE_2); | 4764 | RD = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2); |
| 4802 | } | 4765 | } |
| 4803 | } | 4766 | } |
| 4804 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4767 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4805 | INC_PC(sizeof(mrc_inst)); | 4768 | INC_PC(sizeof(mrc_inst)); |
| 4806 | FETCH_INST; | 4769 | FETCH_INST; |
| 4807 | GOTO_NEXT_INST; | 4770 | GOTO_NEXT_INST; |
| @@ -4818,7 +4781,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4818 | inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2); | 4781 | inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2); |
| 4819 | } | 4782 | } |
| 4820 | 4783 | ||
| 4821 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4784 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4822 | INC_PC(sizeof(mcrr_inst)); | 4785 | INC_PC(sizeof(mcrr_inst)); |
| 4823 | FETCH_INST; | 4786 | FETCH_INST; |
| 4824 | GOTO_NEXT_INST; | 4787 | GOTO_NEXT_INST; |
| @@ -4836,7 +4799,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4836 | RD = cpu->Cpsr; | 4799 | RD = cpu->Cpsr; |
| 4837 | } | 4800 | } |
| 4838 | } | 4801 | } |
| 4839 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4802 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4840 | INC_PC(sizeof(mrs_inst)); | 4803 | INC_PC(sizeof(mrs_inst)); |
| 4841 | FETCH_INST; | 4804 | FETCH_INST; |
| 4842 | GOTO_NEXT_INST; | 4805 | GOTO_NEXT_INST; |
| @@ -4859,7 +4822,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4859 | | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); | 4822 | | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); |
| 4860 | uint32_t mask = 0; | 4823 | uint32_t mask = 0; |
| 4861 | if (!inst_cream->R) { | 4824 | if (!inst_cream->R) { |
| 4862 | if (InAPrivilegedMode(cpu)) { | 4825 | if (cpu->InAPrivilegedMode()) { |
| 4863 | if ((operand & StateMask) != 0) { | 4826 | if ((operand & StateMask) != 0) { |
| 4864 | /// UNPREDICTABLE | 4827 | /// UNPREDICTABLE |
| 4865 | DEBUG_MSG; | 4828 | DEBUG_MSG; |
| @@ -4871,7 +4834,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4871 | SAVE_NZCVT; | 4834 | SAVE_NZCVT; |
| 4872 | 4835 | ||
| 4873 | cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); | 4836 | cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); |
| 4874 | switch_mode(cpu, cpu->Cpsr & 0x1f); | 4837 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); |
| 4875 | LOAD_NZCVT; | 4838 | LOAD_NZCVT; |
| 4876 | } else { | 4839 | } else { |
| 4877 | if (CurrentModeHasSPSR) { | 4840 | if (CurrentModeHasSPSR) { |
| @@ -4880,7 +4843,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4880 | } | 4843 | } |
| 4881 | } | 4844 | } |
| 4882 | } | 4845 | } |
| 4883 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4846 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4884 | INC_PC(sizeof(msr_inst)); | 4847 | INC_PC(sizeof(msr_inst)); |
| 4885 | FETCH_INST; | 4848 | FETCH_INST; |
| 4886 | GOTO_NEXT_INST; | 4849 | GOTO_NEXT_INST; |
| @@ -4902,7 +4865,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4902 | goto DISPATCH; | 4865 | goto DISPATCH; |
| 4903 | } | 4866 | } |
| 4904 | } | 4867 | } |
| 4905 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4868 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4906 | INC_PC(sizeof(mul_inst)); | 4869 | INC_PC(sizeof(mul_inst)); |
| 4907 | FETCH_INST; | 4870 | FETCH_INST; |
| 4908 | GOTO_NEXT_INST; | 4871 | GOTO_NEXT_INST; |
| @@ -4917,7 +4880,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4917 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 4880 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 4918 | if (CurrentModeHasSPSR) { | 4881 | if (CurrentModeHasSPSR) { |
| 4919 | cpu->Cpsr = cpu->Spsr_copy; | 4882 | cpu->Cpsr = cpu->Spsr_copy; |
| 4920 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 4883 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 4921 | LOAD_NZCVT; | 4884 | LOAD_NZCVT; |
| 4922 | } | 4885 | } |
| 4923 | } else if (inst_cream->S) { | 4886 | } else if (inst_cream->S) { |
| @@ -4930,7 +4893,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4930 | goto DISPATCH; | 4893 | goto DISPATCH; |
| 4931 | } | 4894 | } |
| 4932 | } | 4895 | } |
| 4933 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4896 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4934 | INC_PC(sizeof(mvn_inst)); | 4897 | INC_PC(sizeof(mvn_inst)); |
| 4935 | FETCH_INST; | 4898 | FETCH_INST; |
| 4936 | GOTO_NEXT_INST; | 4899 | GOTO_NEXT_INST; |
| @@ -4947,7 +4910,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4947 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 4910 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 4948 | if (CurrentModeHasSPSR) { | 4911 | if (CurrentModeHasSPSR) { |
| 4949 | cpu->Cpsr = cpu->Spsr_copy; | 4912 | cpu->Cpsr = cpu->Spsr_copy; |
| 4950 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 4913 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 4951 | LOAD_NZCVT; | 4914 | LOAD_NZCVT; |
| 4952 | } | 4915 | } |
| 4953 | } else if (inst_cream->S) { | 4916 | } else if (inst_cream->S) { |
| @@ -4960,7 +4923,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4960 | goto DISPATCH; | 4923 | goto DISPATCH; |
| 4961 | } | 4924 | } |
| 4962 | } | 4925 | } |
| 4963 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4926 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4964 | INC_PC(sizeof(orr_inst)); | 4927 | INC_PC(sizeof(orr_inst)); |
| 4965 | FETCH_INST; | 4928 | FETCH_INST; |
| 4966 | GOTO_NEXT_INST; | 4929 | GOTO_NEXT_INST; |
| @@ -4968,7 +4931,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4968 | 4931 | ||
| 4969 | NOP_INST: | 4932 | NOP_INST: |
| 4970 | { | 4933 | { |
| 4971 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4934 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4972 | INC_PC_STUB; | 4935 | INC_PC_STUB; |
| 4973 | FETCH_INST; | 4936 | FETCH_INST; |
| 4974 | GOTO_NEXT_INST; | 4937 | GOTO_NEXT_INST; |
| @@ -4980,7 +4943,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4980 | pkh_inst *inst_cream = (pkh_inst *)inst_base->component; | 4943 | pkh_inst *inst_cream = (pkh_inst *)inst_base->component; |
| 4981 | RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000); | 4944 | RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000); |
| 4982 | } | 4945 | } |
| 4983 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4946 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4984 | INC_PC(sizeof(pkh_inst)); | 4947 | INC_PC(sizeof(pkh_inst)); |
| 4985 | FETCH_INST; | 4948 | FETCH_INST; |
| 4986 | GOTO_NEXT_INST; | 4949 | GOTO_NEXT_INST; |
| @@ -4993,7 +4956,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4993 | int shift_imm = inst_cream->imm ? inst_cream->imm : 31; | 4956 | int shift_imm = inst_cream->imm ? inst_cream->imm : 31; |
| 4994 | RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000); | 4957 | RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000); |
| 4995 | } | 4958 | } |
| 4996 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4959 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4997 | INC_PC(sizeof(pkh_inst)); | 4960 | INC_PC(sizeof(pkh_inst)); |
| 4998 | FETCH_INST; | 4961 | FETCH_INST; |
| 4999 | GOTO_NEXT_INST; | 4962 | GOTO_NEXT_INST; |
| @@ -5003,7 +4966,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5003 | { | 4966 | { |
| 5004 | // Not implemented. PLD is a hint instruction, so it's optional. | 4967 | // Not implemented. PLD is a hint instruction, so it's optional. |
| 5005 | 4968 | ||
| 5006 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 4969 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5007 | INC_PC(sizeof(pld_inst)); | 4970 | INC_PC(sizeof(pld_inst)); |
| 5008 | FETCH_INST; | 4971 | FETCH_INST; |
| 5009 | GOTO_NEXT_INST; | 4972 | GOTO_NEXT_INST; |
| @@ -5076,7 +5039,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5076 | RD = result; | 5039 | RD = result; |
| 5077 | } | 5040 | } |
| 5078 | 5041 | ||
| 5079 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5042 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5080 | INC_PC(sizeof(generic_arm_inst)); | 5043 | INC_PC(sizeof(generic_arm_inst)); |
| 5081 | FETCH_INST; | 5044 | FETCH_INST; |
| 5082 | GOTO_NEXT_INST; | 5045 | GOTO_NEXT_INST; |
| @@ -5138,7 +5101,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5138 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | 5101 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); |
| 5139 | } | 5102 | } |
| 5140 | 5103 | ||
| 5141 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5104 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5142 | INC_PC(sizeof(generic_arm_inst)); | 5105 | INC_PC(sizeof(generic_arm_inst)); |
| 5143 | FETCH_INST; | 5106 | FETCH_INST; |
| 5144 | GOTO_NEXT_INST; | 5107 | GOTO_NEXT_INST; |
| @@ -5171,7 +5134,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5171 | } | 5134 | } |
| 5172 | } | 5135 | } |
| 5173 | 5136 | ||
| 5174 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5137 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5175 | INC_PC(sizeof(rev_inst)); | 5138 | INC_PC(sizeof(rev_inst)); |
| 5176 | FETCH_INST; | 5139 | FETCH_INST; |
| 5177 | GOTO_NEXT_INST; | 5140 | GOTO_NEXT_INST; |
| @@ -5185,8 +5148,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5185 | u32 address = 0; | 5148 | u32 address = 0; |
| 5186 | inst_cream->get_addr(cpu, inst_cream->inst, address); | 5149 | inst_cream->get_addr(cpu, inst_cream->inst, address); |
| 5187 | 5150 | ||
| 5188 | cpu->Cpsr = ReadMemory32(cpu, address); | 5151 | cpu->Cpsr = cpu->ReadMemory32(address); |
| 5189 | cpu->Reg[15] = ReadMemory32(cpu, address + 4); | 5152 | cpu->Reg[15] = cpu->ReadMemory32(address + 4); |
| 5190 | 5153 | ||
| 5191 | INC_PC(sizeof(ldst_inst)); | 5154 | INC_PC(sizeof(ldst_inst)); |
| 5192 | goto DISPATCH; | 5155 | goto DISPATCH; |
| @@ -5199,7 +5162,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5199 | 5162 | ||
| 5200 | u32 rn_val = RN; | 5163 | u32 rn_val = RN; |
| 5201 | if (inst_cream->Rn == 15) | 5164 | if (inst_cream->Rn == 15) |
| 5202 | rn_val += 2 * GET_INST_SIZE(cpu); | 5165 | rn_val += 2 * cpu->GetInstructionSize(); |
| 5203 | 5166 | ||
| 5204 | bool carry; | 5167 | bool carry; |
| 5205 | bool overflow; | 5168 | bool overflow; |
| @@ -5208,7 +5171,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5208 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 5171 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 5209 | if (CurrentModeHasSPSR) { | 5172 | if (CurrentModeHasSPSR) { |
| 5210 | cpu->Cpsr = cpu->Spsr_copy; | 5173 | cpu->Cpsr = cpu->Spsr_copy; |
| 5211 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 5174 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 5212 | LOAD_NZCVT; | 5175 | LOAD_NZCVT; |
| 5213 | } | 5176 | } |
| 5214 | } else if (inst_cream->S) { | 5177 | } else if (inst_cream->S) { |
| @@ -5222,7 +5185,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5222 | goto DISPATCH; | 5185 | goto DISPATCH; |
| 5223 | } | 5186 | } |
| 5224 | } | 5187 | } |
| 5225 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5188 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5226 | INC_PC(sizeof(rsb_inst)); | 5189 | INC_PC(sizeof(rsb_inst)); |
| 5227 | FETCH_INST; | 5190 | FETCH_INST; |
| 5228 | GOTO_NEXT_INST; | 5191 | GOTO_NEXT_INST; |
| @@ -5239,7 +5202,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5239 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 5202 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 5240 | if (CurrentModeHasSPSR) { | 5203 | if (CurrentModeHasSPSR) { |
| 5241 | cpu->Cpsr = cpu->Spsr_copy; | 5204 | cpu->Cpsr = cpu->Spsr_copy; |
| 5242 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 5205 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 5243 | LOAD_NZCVT; | 5206 | LOAD_NZCVT; |
| 5244 | } | 5207 | } |
| 5245 | } else if (inst_cream->S) { | 5208 | } else if (inst_cream->S) { |
| @@ -5253,7 +5216,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5253 | goto DISPATCH; | 5216 | goto DISPATCH; |
| 5254 | } | 5217 | } |
| 5255 | } | 5218 | } |
| 5256 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5219 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5257 | INC_PC(sizeof(rsc_inst)); | 5220 | INC_PC(sizeof(rsc_inst)); |
| 5258 | FETCH_INST; | 5221 | FETCH_INST; |
| 5259 | GOTO_NEXT_INST; | 5222 | GOTO_NEXT_INST; |
| @@ -5361,7 +5324,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5361 | } | 5324 | } |
| 5362 | } | 5325 | } |
| 5363 | 5326 | ||
| 5364 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5327 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5365 | INC_PC(sizeof(generic_arm_inst)); | 5328 | INC_PC(sizeof(generic_arm_inst)); |
| 5366 | FETCH_INST; | 5329 | FETCH_INST; |
| 5367 | GOTO_NEXT_INST; | 5330 | GOTO_NEXT_INST; |
| @@ -5379,7 +5342,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5379 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 5342 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 5380 | if (CurrentModeHasSPSR) { | 5343 | if (CurrentModeHasSPSR) { |
| 5381 | cpu->Cpsr = cpu->Spsr_copy; | 5344 | cpu->Cpsr = cpu->Spsr_copy; |
| 5382 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 5345 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 5383 | LOAD_NZCVT; | 5346 | LOAD_NZCVT; |
| 5384 | } | 5347 | } |
| 5385 | } else if (inst_cream->S) { | 5348 | } else if (inst_cream->S) { |
| @@ -5393,7 +5356,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5393 | goto DISPATCH; | 5356 | goto DISPATCH; |
| 5394 | } | 5357 | } |
| 5395 | } | 5358 | } |
| 5396 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5359 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5397 | INC_PC(sizeof(sbc_inst)); | 5360 | INC_PC(sizeof(sbc_inst)); |
| 5398 | FETCH_INST; | 5361 | FETCH_INST; |
| 5399 | GOTO_NEXT_INST; | 5362 | GOTO_NEXT_INST; |
| @@ -5432,7 +5395,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5432 | RD = result; | 5395 | RD = result; |
| 5433 | } | 5396 | } |
| 5434 | 5397 | ||
| 5435 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5398 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5436 | INC_PC(sizeof(generic_arm_inst)); | 5399 | INC_PC(sizeof(generic_arm_inst)); |
| 5437 | FETCH_INST; | 5400 | FETCH_INST; |
| 5438 | GOTO_NEXT_INST; | 5401 | GOTO_NEXT_INST; |
| @@ -5451,7 +5414,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5451 | 5414 | ||
| 5452 | LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE"); | 5415 | LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE"); |
| 5453 | 5416 | ||
| 5454 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5417 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5455 | INC_PC(sizeof(setend_inst)); | 5418 | INC_PC(sizeof(setend_inst)); |
| 5456 | FETCH_INST; | 5419 | FETCH_INST; |
| 5457 | GOTO_NEXT_INST; | 5420 | GOTO_NEXT_INST; |
| @@ -5464,7 +5427,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5464 | LOG_TRACE(Core_ARM11, "SEV executed."); | 5427 | LOG_TRACE(Core_ARM11, "SEV executed."); |
| 5465 | } | 5428 | } |
| 5466 | 5429 | ||
| 5467 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5430 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5468 | INC_PC_STUB; | 5431 | INC_PC_STUB; |
| 5469 | FETCH_INST; | 5432 | FETCH_INST; |
| 5470 | GOTO_NEXT_INST; | 5433 | GOTO_NEXT_INST; |
| @@ -5536,7 +5499,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5536 | } | 5499 | } |
| 5537 | } | 5500 | } |
| 5538 | 5501 | ||
| 5539 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5502 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5540 | INC_PC(sizeof(generic_arm_inst)); | 5503 | INC_PC(sizeof(generic_arm_inst)); |
| 5541 | FETCH_INST; | 5504 | FETCH_INST; |
| 5542 | GOTO_NEXT_INST; | 5505 | GOTO_NEXT_INST; |
| @@ -5561,7 +5524,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5561 | if (AddOverflow(operand1 * operand2, RN, RD)) | 5524 | if (AddOverflow(operand1 * operand2, RN, RD)) |
| 5562 | cpu->Cpsr |= (1 << 27); | 5525 | cpu->Cpsr |= (1 << 27); |
| 5563 | } | 5526 | } |
| 5564 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5527 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5565 | INC_PC(sizeof(smla_inst)); | 5528 | INC_PC(sizeof(smla_inst)); |
| 5566 | FETCH_INST; | 5529 | FETCH_INST; |
| 5567 | GOTO_NEXT_INST; | 5530 | GOTO_NEXT_INST; |
| @@ -5617,7 +5580,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5617 | } | 5580 | } |
| 5618 | } | 5581 | } |
| 5619 | 5582 | ||
| 5620 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5583 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5621 | INC_PC(sizeof(smlad_inst)); | 5584 | INC_PC(sizeof(smlad_inst)); |
| 5622 | FETCH_INST; | 5585 | FETCH_INST; |
| 5623 | GOTO_NEXT_INST; | 5586 | GOTO_NEXT_INST; |
| @@ -5646,7 +5609,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5646 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | 5609 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); |
| 5647 | } | 5610 | } |
| 5648 | } | 5611 | } |
| 5649 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5612 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5650 | INC_PC(sizeof(umlal_inst)); | 5613 | INC_PC(sizeof(umlal_inst)); |
| 5651 | FETCH_INST; | 5614 | FETCH_INST; |
| 5652 | GOTO_NEXT_INST; | 5615 | GOTO_NEXT_INST; |
| @@ -5676,7 +5639,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5676 | RDHI = ((dest >> 32) & 0xFFFFFFFF); | 5639 | RDHI = ((dest >> 32) & 0xFFFFFFFF); |
| 5677 | } | 5640 | } |
| 5678 | 5641 | ||
| 5679 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5642 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5680 | INC_PC(sizeof(smlalxy_inst)); | 5643 | INC_PC(sizeof(smlalxy_inst)); |
| 5681 | FETCH_INST; | 5644 | FETCH_INST; |
| 5682 | GOTO_NEXT_INST; | 5645 | GOTO_NEXT_INST; |
| @@ -5695,13 +5658,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5695 | const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF); | 5658 | const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF); |
| 5696 | const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16); | 5659 | const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16); |
| 5697 | 5660 | ||
| 5698 | RD = (result & (0xFFFFFFFFFFFFFFFFLL >> 15)) >> 16; | 5661 | RD = BITS(result, 16, 47); |
| 5699 | 5662 | ||
| 5700 | if ((result >> 16) != (s32)RD) | 5663 | if ((result >> 16) != (s32)RD) |
| 5701 | cpu->Cpsr |= (1 << 27); | 5664 | cpu->Cpsr |= (1 << 27); |
| 5702 | } | 5665 | } |
| 5703 | 5666 | ||
| 5704 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5667 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5705 | INC_PC(sizeof(smlad_inst)); | 5668 | INC_PC(sizeof(smlad_inst)); |
| 5706 | FETCH_INST; | 5669 | FETCH_INST; |
| 5707 | GOTO_NEXT_INST; | 5670 | GOTO_NEXT_INST; |
| @@ -5739,7 +5702,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5739 | RDHI = ((result >> 32) & 0xFFFFFFFF); | 5702 | RDHI = ((result >> 32) & 0xFFFFFFFF); |
| 5740 | } | 5703 | } |
| 5741 | 5704 | ||
| 5742 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5705 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5743 | INC_PC(sizeof(smlald_inst)); | 5706 | INC_PC(sizeof(smlald_inst)); |
| 5744 | FETCH_INST; | 5707 | FETCH_INST; |
| 5745 | GOTO_NEXT_INST; | 5708 | GOTO_NEXT_INST; |
| @@ -5775,7 +5738,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5775 | RD = ((result >> 32) & 0xFFFFFFFF); | 5738 | RD = ((result >> 32) & 0xFFFFFFFF); |
| 5776 | } | 5739 | } |
| 5777 | 5740 | ||
| 5778 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5741 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5779 | INC_PC(sizeof(smlad_inst)); | 5742 | INC_PC(sizeof(smlad_inst)); |
| 5780 | FETCH_INST; | 5743 | FETCH_INST; |
| 5781 | GOTO_NEXT_INST; | 5744 | GOTO_NEXT_INST; |
| @@ -5797,7 +5760,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5797 | operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); | 5760 | operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); |
| 5798 | RD = operand1 * operand2; | 5761 | RD = operand1 * operand2; |
| 5799 | } | 5762 | } |
| 5800 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5763 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5801 | INC_PC(sizeof(smul_inst)); | 5764 | INC_PC(sizeof(smul_inst)); |
| 5802 | FETCH_INST; | 5765 | FETCH_INST; |
| 5803 | GOTO_NEXT_INST; | 5766 | GOTO_NEXT_INST; |
| @@ -5823,7 +5786,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5823 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | 5786 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); |
| 5824 | } | 5787 | } |
| 5825 | } | 5788 | } |
| 5826 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5789 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5827 | INC_PC(sizeof(umull_inst)); | 5790 | INC_PC(sizeof(umull_inst)); |
| 5828 | FETCH_INST; | 5791 | FETCH_INST; |
| 5829 | GOTO_NEXT_INST; | 5792 | GOTO_NEXT_INST; |
| @@ -5839,7 +5802,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5839 | s64 result = (s64)rm * (s64)(s32)RN; | 5802 | s64 result = (s64)rm * (s64)(s32)RN; |
| 5840 | RD = BITS(result, 16, 47); | 5803 | RD = BITS(result, 16, 47); |
| 5841 | } | 5804 | } |
| 5842 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5805 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5843 | INC_PC(sizeof(smlad_inst)); | 5806 | INC_PC(sizeof(smlad_inst)); |
| 5844 | FETCH_INST; | 5807 | FETCH_INST; |
| 5845 | GOTO_NEXT_INST; | 5808 | GOTO_NEXT_INST; |
| @@ -5853,10 +5816,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5853 | u32 address = 0; | 5816 | u32 address = 0; |
| 5854 | inst_cream->get_addr(cpu, inst_cream->inst, address); | 5817 | inst_cream->get_addr(cpu, inst_cream->inst, address); |
| 5855 | 5818 | ||
| 5856 | WriteMemory32(cpu, address + 0, cpu->Reg[14]); | 5819 | cpu->WriteMemory32(address + 0, cpu->Reg[14]); |
| 5857 | WriteMemory32(cpu, address + 4, cpu->Spsr_copy); | 5820 | cpu->WriteMemory32(address + 4, cpu->Spsr_copy); |
| 5858 | 5821 | ||
| 5859 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5822 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5860 | INC_PC(sizeof(ldst_inst)); | 5823 | INC_PC(sizeof(ldst_inst)); |
| 5861 | FETCH_INST; | 5824 | FETCH_INST; |
| 5862 | GOTO_NEXT_INST; | 5825 | GOTO_NEXT_INST; |
| @@ -5889,7 +5852,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5889 | RD = rn_val; | 5852 | RD = rn_val; |
| 5890 | } | 5853 | } |
| 5891 | 5854 | ||
| 5892 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5855 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5893 | INC_PC(sizeof(ssat_inst)); | 5856 | INC_PC(sizeof(ssat_inst)); |
| 5894 | FETCH_INST; | 5857 | FETCH_INST; |
| 5895 | GOTO_NEXT_INST; | 5858 | GOTO_NEXT_INST; |
| @@ -5911,7 +5874,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5911 | cpu->Cpsr |= (1 << 27); | 5874 | cpu->Cpsr |= (1 << 27); |
| 5912 | } | 5875 | } |
| 5913 | 5876 | ||
| 5914 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5877 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5915 | INC_PC(sizeof(ssat_inst)); | 5878 | INC_PC(sizeof(ssat_inst)); |
| 5916 | FETCH_INST; | 5879 | FETCH_INST; |
| 5917 | GOTO_NEXT_INST; | 5880 | GOTO_NEXT_INST; |
| @@ -5921,7 +5884,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5921 | { | 5884 | { |
| 5922 | // Instruction not implemented | 5885 | // Instruction not implemented |
| 5923 | //LOG_CRITICAL(Core_ARM11, "unimplemented instruction"); | 5886 | //LOG_CRITICAL(Core_ARM11, "unimplemented instruction"); |
| 5924 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5887 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5925 | INC_PC(sizeof(stc_inst)); | 5888 | INC_PC(sizeof(stc_inst)); |
| 5926 | FETCH_INST; | 5889 | FETCH_INST; |
| 5927 | GOTO_NEXT_INST; | 5890 | GOTO_NEXT_INST; |
| @@ -5939,36 +5902,36 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5939 | if (BIT(inst_cream->inst, 22) == 1) { | 5902 | if (BIT(inst_cream->inst, 22) == 1) { |
| 5940 | for (int i = 0; i < 13; i++) { | 5903 | for (int i = 0; i < 13; i++) { |
| 5941 | if (BIT(inst_cream->inst, i)) { | 5904 | if (BIT(inst_cream->inst, i)) { |
| 5942 | WriteMemory32(cpu, addr, cpu->Reg[i]); | 5905 | cpu->WriteMemory32(addr, cpu->Reg[i]); |
| 5943 | addr += 4; | 5906 | addr += 4; |
| 5944 | } | 5907 | } |
| 5945 | } | 5908 | } |
| 5946 | if (BIT(inst_cream->inst, 13)) { | 5909 | if (BIT(inst_cream->inst, 13)) { |
| 5947 | if (cpu->Mode == USER32MODE) | 5910 | if (cpu->Mode == USER32MODE) |
| 5948 | WriteMemory32(cpu, addr, cpu->Reg[13]); | 5911 | cpu->WriteMemory32(addr, cpu->Reg[13]); |
| 5949 | else | 5912 | else |
| 5950 | WriteMemory32(cpu, addr, cpu->Reg_usr[0]); | 5913 | cpu->WriteMemory32(addr, cpu->Reg_usr[0]); |
| 5951 | 5914 | ||
| 5952 | addr += 4; | 5915 | addr += 4; |
| 5953 | } | 5916 | } |
| 5954 | if (BIT(inst_cream->inst, 14)) { | 5917 | if (BIT(inst_cream->inst, 14)) { |
| 5955 | if (cpu->Mode == USER32MODE) | 5918 | if (cpu->Mode == USER32MODE) |
| 5956 | WriteMemory32(cpu, addr, cpu->Reg[14]); | 5919 | cpu->WriteMemory32(addr, cpu->Reg[14]); |
| 5957 | else | 5920 | else |
| 5958 | WriteMemory32(cpu, addr, cpu->Reg_usr[1]); | 5921 | cpu->WriteMemory32(addr, cpu->Reg_usr[1]); |
| 5959 | 5922 | ||
| 5960 | addr += 4; | 5923 | addr += 4; |
| 5961 | } | 5924 | } |
| 5962 | if (BIT(inst_cream->inst, 15)) { | 5925 | if (BIT(inst_cream->inst, 15)) { |
| 5963 | WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8); | 5926 | cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8); |
| 5964 | } | 5927 | } |
| 5965 | } else { | 5928 | } else { |
| 5966 | for (int i = 0; i < 15; i++) { | 5929 | for (int i = 0; i < 15; i++) { |
| 5967 | if (BIT(inst_cream->inst, i)) { | 5930 | if (BIT(inst_cream->inst, i)) { |
| 5968 | if (i == Rn) | 5931 | if (i == Rn) |
| 5969 | WriteMemory32(cpu, addr, old_RN); | 5932 | cpu->WriteMemory32(addr, old_RN); |
| 5970 | else | 5933 | else |
| 5971 | WriteMemory32(cpu, addr, cpu->Reg[i]); | 5934 | cpu->WriteMemory32(addr, cpu->Reg[i]); |
| 5972 | 5935 | ||
| 5973 | addr += 4; | 5936 | addr += 4; |
| 5974 | } | 5937 | } |
| @@ -5976,10 +5939,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5976 | 5939 | ||
| 5977 | // Check PC reg | 5940 | // Check PC reg |
| 5978 | if (BIT(inst_cream->inst, 15)) | 5941 | if (BIT(inst_cream->inst, 15)) |
| 5979 | WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8); | 5942 | cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8); |
| 5980 | } | 5943 | } |
| 5981 | } | 5944 | } |
| 5982 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5945 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 5983 | INC_PC(sizeof(ldst_inst)); | 5946 | INC_PC(sizeof(ldst_inst)); |
| 5984 | FETCH_INST; | 5947 | FETCH_INST; |
| 5985 | GOTO_NEXT_INST; | 5948 | GOTO_NEXT_INST; |
| @@ -5997,7 +5960,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 5997 | } | 5960 | } |
| 5998 | RD = operand2; | 5961 | RD = operand2; |
| 5999 | } | 5962 | } |
| 6000 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5963 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6001 | INC_PC(sizeof(sxtb_inst)); | 5964 | INC_PC(sizeof(sxtb_inst)); |
| 6002 | FETCH_INST; | 5965 | FETCH_INST; |
| 6003 | GOTO_NEXT_INST; | 5966 | GOTO_NEXT_INST; |
| @@ -6009,9 +5972,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6009 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 5972 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 6010 | 5973 | ||
| 6011 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; | 5974 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; |
| 6012 | WriteMemory32(cpu, addr, value); | 5975 | cpu->WriteMemory32(addr, value); |
| 6013 | } | 5976 | } |
| 6014 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5977 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6015 | INC_PC(sizeof(ldst_inst)); | 5978 | INC_PC(sizeof(ldst_inst)); |
| 6016 | FETCH_INST; | 5979 | FETCH_INST; |
| 6017 | GOTO_NEXT_INST; | 5980 | GOTO_NEXT_INST; |
| @@ -6022,7 +5985,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6022 | uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component; | 5985 | uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component; |
| 6023 | RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; | 5986 | RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; |
| 6024 | } | 5987 | } |
| 6025 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 5988 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6026 | INC_PC(sizeof(uxtb_inst)); | 5989 | INC_PC(sizeof(uxtb_inst)); |
| 6027 | FETCH_INST; | 5990 | FETCH_INST; |
| 6028 | GOTO_NEXT_INST; | 5991 | GOTO_NEXT_INST; |
| @@ -6035,7 +5998,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6035 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; | 5998 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; |
| 6036 | RD = RN + operand2; | 5999 | RD = RN + operand2; |
| 6037 | } | 6000 | } |
| 6038 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6001 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6039 | INC_PC(sizeof(uxtab_inst)); | 6002 | INC_PC(sizeof(uxtab_inst)); |
| 6040 | FETCH_INST; | 6003 | FETCH_INST; |
| 6041 | GOTO_NEXT_INST; | 6004 | GOTO_NEXT_INST; |
| @@ -6048,7 +6011,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6048 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | 6011 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; |
| 6049 | Memory::Write8(addr, value); | 6012 | Memory::Write8(addr, value); |
| 6050 | } | 6013 | } |
| 6051 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6014 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6052 | INC_PC(sizeof(ldst_inst)); | 6015 | INC_PC(sizeof(ldst_inst)); |
| 6053 | FETCH_INST; | 6016 | FETCH_INST; |
| 6054 | GOTO_NEXT_INST; | 6017 | GOTO_NEXT_INST; |
| @@ -6061,7 +6024,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6061 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | 6024 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; |
| 6062 | Memory::Write8(addr, value); | 6025 | Memory::Write8(addr, value); |
| 6063 | } | 6026 | } |
| 6064 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6027 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6065 | INC_PC(sizeof(ldst_inst)); | 6028 | INC_PC(sizeof(ldst_inst)); |
| 6066 | FETCH_INST; | 6029 | FETCH_INST; |
| 6067 | GOTO_NEXT_INST; | 6030 | GOTO_NEXT_INST; |
| @@ -6074,10 +6037,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6074 | 6037 | ||
| 6075 | // The 3DS doesn't have the Large Physical Access Extension (LPAE) | 6038 | // The 3DS doesn't have the Large Physical Access Extension (LPAE) |
| 6076 | // so STRD wouldn't store these as a single write. | 6039 | // so STRD wouldn't store these as a single write. |
| 6077 | WriteMemory32(cpu, addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]); | 6040 | cpu->WriteMemory32(addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]); |
| 6078 | WriteMemory32(cpu, addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]); | 6041 | cpu->WriteMemory32(addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]); |
| 6079 | } | 6042 | } |
| 6080 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6043 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6081 | INC_PC(sizeof(ldst_inst)); | 6044 | INC_PC(sizeof(ldst_inst)); |
| 6082 | FETCH_INST; | 6045 | FETCH_INST; |
| 6083 | GOTO_NEXT_INST; | 6046 | GOTO_NEXT_INST; |
| @@ -6088,18 +6051,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6088 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6051 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6089 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6052 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6090 | 6053 | ||
| 6091 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6054 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6092 | remove_exclusive(cpu, write_addr); | 6055 | cpu->UnsetExclusiveMemoryAddress(); |
| 6093 | cpu->exclusive_state = 0; | 6056 | cpu->WriteMemory32(write_addr, RM); |
| 6094 | |||
| 6095 | WriteMemory32(cpu, write_addr, RM); | ||
| 6096 | RD = 0; | 6057 | RD = 0; |
| 6097 | } else { | 6058 | } else { |
| 6098 | // Failed to write due to mutex access | 6059 | // Failed to write due to mutex access |
| 6099 | RD = 1; | 6060 | RD = 1; |
| 6100 | } | 6061 | } |
| 6101 | } | 6062 | } |
| 6102 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6063 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6103 | INC_PC(sizeof(generic_arm_inst)); | 6064 | INC_PC(sizeof(generic_arm_inst)); |
| 6104 | FETCH_INST; | 6065 | FETCH_INST; |
| 6105 | GOTO_NEXT_INST; | 6066 | GOTO_NEXT_INST; |
| @@ -6110,10 +6071,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6110 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6071 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6111 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6072 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6112 | 6073 | ||
| 6113 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6074 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6114 | remove_exclusive(cpu, write_addr); | 6075 | cpu->UnsetExclusiveMemoryAddress(); |
| 6115 | cpu->exclusive_state = 0; | ||
| 6116 | |||
| 6117 | Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]); | 6076 | Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]); |
| 6118 | RD = 0; | 6077 | RD = 0; |
| 6119 | } else { | 6078 | } else { |
| @@ -6121,7 +6080,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6121 | RD = 1; | 6080 | RD = 1; |
| 6122 | } | 6081 | } |
| 6123 | } | 6082 | } |
| 6124 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6083 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6125 | INC_PC(sizeof(generic_arm_inst)); | 6084 | INC_PC(sizeof(generic_arm_inst)); |
| 6126 | FETCH_INST; | 6085 | FETCH_INST; |
| 6127 | GOTO_NEXT_INST; | 6086 | GOTO_NEXT_INST; |
| @@ -6132,20 +6091,19 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6132 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6091 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6133 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6092 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6134 | 6093 | ||
| 6135 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6094 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6136 | remove_exclusive(cpu, write_addr); | 6095 | cpu->UnsetExclusiveMemoryAddress(); |
| 6137 | cpu->exclusive_state = 0; | ||
| 6138 | 6096 | ||
| 6139 | const u32 rt = cpu->Reg[inst_cream->Rm + 0]; | 6097 | const u32 rt = cpu->Reg[inst_cream->Rm + 0]; |
| 6140 | const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; | 6098 | const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; |
| 6141 | u64 value; | 6099 | u64 value; |
| 6142 | 6100 | ||
| 6143 | if (InBigEndianMode(cpu)) | 6101 | if (cpu->InBigEndianMode()) |
| 6144 | value = (((u64)rt << 32) | rt2); | 6102 | value = (((u64)rt << 32) | rt2); |
| 6145 | else | 6103 | else |
| 6146 | value = (((u64)rt2 << 32) | rt); | 6104 | value = (((u64)rt2 << 32) | rt); |
| 6147 | 6105 | ||
| 6148 | WriteMemory64(cpu, write_addr, value); | 6106 | cpu->WriteMemory64(write_addr, value); |
| 6149 | RD = 0; | 6107 | RD = 0; |
| 6150 | } | 6108 | } |
| 6151 | else { | 6109 | else { |
| @@ -6153,7 +6111,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6153 | RD = 1; | 6111 | RD = 1; |
| 6154 | } | 6112 | } |
| 6155 | } | 6113 | } |
| 6156 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6114 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6157 | INC_PC(sizeof(generic_arm_inst)); | 6115 | INC_PC(sizeof(generic_arm_inst)); |
| 6158 | FETCH_INST; | 6116 | FETCH_INST; |
| 6159 | GOTO_NEXT_INST; | 6117 | GOTO_NEXT_INST; |
| @@ -6164,18 +6122,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6164 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | 6122 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; |
| 6165 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | 6123 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; |
| 6166 | 6124 | ||
| 6167 | if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { | 6125 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6168 | remove_exclusive(cpu, write_addr); | 6126 | cpu->UnsetExclusiveMemoryAddress(); |
| 6169 | cpu->exclusive_state = 0; | 6127 | cpu->WriteMemory16(write_addr, RM); |
| 6170 | |||
| 6171 | WriteMemory16(cpu, write_addr, RM); | ||
| 6172 | RD = 0; | 6128 | RD = 0; |
| 6173 | } else { | 6129 | } else { |
| 6174 | // Failed to write due to mutex access | 6130 | // Failed to write due to mutex access |
| 6175 | RD = 1; | 6131 | RD = 1; |
| 6176 | } | 6132 | } |
| 6177 | } | 6133 | } |
| 6178 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6134 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6179 | INC_PC(sizeof(generic_arm_inst)); | 6135 | INC_PC(sizeof(generic_arm_inst)); |
| 6180 | FETCH_INST; | 6136 | FETCH_INST; |
| 6181 | GOTO_NEXT_INST; | 6137 | GOTO_NEXT_INST; |
| @@ -6187,9 +6143,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6187 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 6143 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 6188 | 6144 | ||
| 6189 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; | 6145 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; |
| 6190 | WriteMemory16(cpu, addr, value); | 6146 | cpu->WriteMemory16(addr, value); |
| 6191 | } | 6147 | } |
| 6192 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6148 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6193 | INC_PC(sizeof(ldst_inst)); | 6149 | INC_PC(sizeof(ldst_inst)); |
| 6194 | FETCH_INST; | 6150 | FETCH_INST; |
| 6195 | GOTO_NEXT_INST; | 6151 | GOTO_NEXT_INST; |
| @@ -6201,9 +6157,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6201 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 6157 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 6202 | 6158 | ||
| 6203 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; | 6159 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; |
| 6204 | WriteMemory32(cpu, addr, value); | 6160 | cpu->WriteMemory32(addr, value); |
| 6205 | } | 6161 | } |
| 6206 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6162 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6207 | INC_PC(sizeof(ldst_inst)); | 6163 | INC_PC(sizeof(ldst_inst)); |
| 6208 | FETCH_INST; | 6164 | FETCH_INST; |
| 6209 | GOTO_NEXT_INST; | 6165 | GOTO_NEXT_INST; |
| @@ -6224,7 +6180,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6224 | if (inst_cream->S && (inst_cream->Rd == 15)) { | 6180 | if (inst_cream->S && (inst_cream->Rd == 15)) { |
| 6225 | if (CurrentModeHasSPSR) { | 6181 | if (CurrentModeHasSPSR) { |
| 6226 | cpu->Cpsr = cpu->Spsr_copy; | 6182 | cpu->Cpsr = cpu->Spsr_copy; |
| 6227 | switch_mode(cpu, cpu->Spsr_copy & 0x1f); | 6183 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); |
| 6228 | LOAD_NZCVT; | 6184 | LOAD_NZCVT; |
| 6229 | } | 6185 | } |
| 6230 | } else if (inst_cream->S) { | 6186 | } else if (inst_cream->S) { |
| @@ -6238,7 +6194,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6238 | goto DISPATCH; | 6194 | goto DISPATCH; |
| 6239 | } | 6195 | } |
| 6240 | } | 6196 | } |
| 6241 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6197 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6242 | INC_PC(sizeof(sub_inst)); | 6198 | INC_PC(sizeof(sub_inst)); |
| 6243 | FETCH_INST; | 6199 | FETCH_INST; |
| 6244 | GOTO_NEXT_INST; | 6200 | GOTO_NEXT_INST; |
| @@ -6246,10 +6202,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6246 | SWI_INST: | 6202 | SWI_INST: |
| 6247 | { | 6203 | { |
| 6248 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { | 6204 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { |
| 6249 | SVC::CallSVC(Memory::Read32(cpu->Reg[15])); | 6205 | swi_inst* const inst_cream = (swi_inst*)inst_base->component; |
| 6206 | SVC::CallSVC(inst_cream->num & 0xFFFF); | ||
| 6250 | } | 6207 | } |
| 6251 | 6208 | ||
| 6252 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6209 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6253 | INC_PC(sizeof(swi_inst)); | 6210 | INC_PC(sizeof(swi_inst)); |
| 6254 | FETCH_INST; | 6211 | FETCH_INST; |
| 6255 | GOTO_NEXT_INST; | 6212 | GOTO_NEXT_INST; |
| @@ -6260,12 +6217,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6260 | swp_inst* inst_cream = (swp_inst*)inst_base->component; | 6217 | swp_inst* inst_cream = (swp_inst*)inst_base->component; |
| 6261 | 6218 | ||
| 6262 | addr = RN; | 6219 | addr = RN; |
| 6263 | unsigned int value = ReadMemory32(cpu, addr); | 6220 | unsigned int value = cpu->ReadMemory32(addr); |
| 6264 | WriteMemory32(cpu, addr, RM); | 6221 | cpu->WriteMemory32(addr, RM); |
| 6265 | 6222 | ||
| 6266 | RD = value; | 6223 | RD = value; |
| 6267 | } | 6224 | } |
| 6268 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6225 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6269 | INC_PC(sizeof(swp_inst)); | 6226 | INC_PC(sizeof(swp_inst)); |
| 6270 | FETCH_INST; | 6227 | FETCH_INST; |
| 6271 | GOTO_NEXT_INST; | 6228 | GOTO_NEXT_INST; |
| @@ -6279,7 +6236,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6279 | Memory::Write8(addr, (RM & 0xFF)); | 6236 | Memory::Write8(addr, (RM & 0xFF)); |
| 6280 | RD = value; | 6237 | RD = value; |
| 6281 | } | 6238 | } |
| 6282 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6239 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6283 | INC_PC(sizeof(swp_inst)); | 6240 | INC_PC(sizeof(swp_inst)); |
| 6284 | FETCH_INST; | 6241 | FETCH_INST; |
| 6285 | GOTO_NEXT_INST; | 6242 | GOTO_NEXT_INST; |
| @@ -6295,7 +6252,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6295 | operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2; | 6252 | operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2; |
| 6296 | RD = RN + operand2; | 6253 | RD = RN + operand2; |
| 6297 | } | 6254 | } |
| 6298 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6255 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6299 | INC_PC(sizeof(uxtab_inst)); | 6256 | INC_PC(sizeof(uxtab_inst)); |
| 6300 | FETCH_INST; | 6257 | FETCH_INST; |
| 6301 | GOTO_NEXT_INST; | 6258 | GOTO_NEXT_INST; |
| @@ -6328,7 +6285,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6328 | } | 6285 | } |
| 6329 | } | 6286 | } |
| 6330 | 6287 | ||
| 6331 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6288 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6332 | INC_PC(sizeof(sxtab_inst)); | 6289 | INC_PC(sizeof(sxtab_inst)); |
| 6333 | FETCH_INST; | 6290 | FETCH_INST; |
| 6334 | GOTO_NEXT_INST; | 6291 | GOTO_NEXT_INST; |
| @@ -6344,7 +6301,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6344 | operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2; | 6301 | operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2; |
| 6345 | RD = RN + operand2; | 6302 | RD = RN + operand2; |
| 6346 | } | 6303 | } |
| 6347 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6304 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6348 | INC_PC(sizeof(sxtah_inst)); | 6305 | INC_PC(sizeof(sxtah_inst)); |
| 6349 | FETCH_INST; | 6306 | FETCH_INST; |
| 6350 | GOTO_NEXT_INST; | 6307 | GOTO_NEXT_INST; |
| @@ -6359,7 +6316,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6359 | u32 rop = SHIFTER_OPERAND; | 6316 | u32 rop = SHIFTER_OPERAND; |
| 6360 | 6317 | ||
| 6361 | if (inst_cream->Rn == 15) | 6318 | if (inst_cream->Rn == 15) |
| 6362 | lop += GET_INST_SIZE(cpu) * 2; | 6319 | lop += cpu->GetInstructionSize() * 2; |
| 6363 | 6320 | ||
| 6364 | u32 result = lop ^ rop; | 6321 | u32 result = lop ^ rop; |
| 6365 | 6322 | ||
| @@ -6367,7 +6324,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6367 | UPDATE_ZFLAG(result); | 6324 | UPDATE_ZFLAG(result); |
| 6368 | UPDATE_CFLAG_WITH_SC; | 6325 | UPDATE_CFLAG_WITH_SC; |
| 6369 | } | 6326 | } |
| 6370 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6327 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6371 | INC_PC(sizeof(teq_inst)); | 6328 | INC_PC(sizeof(teq_inst)); |
| 6372 | FETCH_INST; | 6329 | FETCH_INST; |
| 6373 | GOTO_NEXT_INST; | 6330 | GOTO_NEXT_INST; |
| @@ -6381,7 +6338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6381 | u32 rop = SHIFTER_OPERAND; | 6338 | u32 rop = SHIFTER_OPERAND; |
| 6382 | 6339 | ||
| 6383 | if (inst_cream->Rn == 15) | 6340 | if (inst_cream->Rn == 15) |
| 6384 | lop += GET_INST_SIZE(cpu) * 2; | 6341 | lop += cpu->GetInstructionSize() * 2; |
| 6385 | 6342 | ||
| 6386 | u32 result = lop & rop; | 6343 | u32 result = lop & rop; |
| 6387 | 6344 | ||
| @@ -6389,7 +6346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6389 | UPDATE_ZFLAG(result); | 6346 | UPDATE_ZFLAG(result); |
| 6390 | UPDATE_CFLAG_WITH_SC; | 6347 | UPDATE_CFLAG_WITH_SC; |
| 6391 | } | 6348 | } |
| 6392 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6349 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6393 | INC_PC(sizeof(tst_inst)); | 6350 | INC_PC(sizeof(tst_inst)); |
| 6394 | FETCH_INST; | 6351 | FETCH_INST; |
| 6395 | GOTO_NEXT_INST; | 6352 | GOTO_NEXT_INST; |
| @@ -6560,7 +6517,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6560 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | 6517 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); |
| 6561 | } | 6518 | } |
| 6562 | 6519 | ||
| 6563 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6520 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6564 | INC_PC(sizeof(generic_arm_inst)); | 6521 | INC_PC(sizeof(generic_arm_inst)); |
| 6565 | FETCH_INST; | 6522 | FETCH_INST; |
| 6566 | GOTO_NEXT_INST; | 6523 | GOTO_NEXT_INST; |
| @@ -6640,7 +6597,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6640 | } | 6597 | } |
| 6641 | } | 6598 | } |
| 6642 | 6599 | ||
| 6643 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6600 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6644 | INC_PC(sizeof(generic_arm_inst)); | 6601 | INC_PC(sizeof(generic_arm_inst)); |
| 6645 | FETCH_INST; | 6602 | FETCH_INST; |
| 6646 | GOTO_NEXT_INST; | 6603 | GOTO_NEXT_INST; |
| @@ -6659,7 +6616,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6659 | RDLO = (result & 0xFFFFFFFF); | 6616 | RDLO = (result & 0xFFFFFFFF); |
| 6660 | RDHI = ((result >> 32) & 0xFFFFFFFF); | 6617 | RDHI = ((result >> 32) & 0xFFFFFFFF); |
| 6661 | } | 6618 | } |
| 6662 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6619 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6663 | INC_PC(sizeof(umaal_inst)); | 6620 | INC_PC(sizeof(umaal_inst)); |
| 6664 | FETCH_INST; | 6621 | FETCH_INST; |
| 6665 | GOTO_NEXT_INST; | 6622 | GOTO_NEXT_INST; |
| @@ -6682,7 +6639,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6682 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | 6639 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); |
| 6683 | } | 6640 | } |
| 6684 | } | 6641 | } |
| 6685 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6642 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6686 | INC_PC(sizeof(umlal_inst)); | 6643 | INC_PC(sizeof(umlal_inst)); |
| 6687 | FETCH_INST; | 6644 | FETCH_INST; |
| 6688 | GOTO_NEXT_INST; | 6645 | GOTO_NEXT_INST; |
| @@ -6702,7 +6659,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6702 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | 6659 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); |
| 6703 | } | 6660 | } |
| 6704 | } | 6661 | } |
| 6705 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6662 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6706 | INC_PC(sizeof(umull_inst)); | 6663 | INC_PC(sizeof(umull_inst)); |
| 6707 | FETCH_INST; | 6664 | FETCH_INST; |
| 6708 | GOTO_NEXT_INST; | 6665 | GOTO_NEXT_INST; |
| @@ -6730,7 +6687,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6730 | { | 6687 | { |
| 6731 | bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component; | 6688 | bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component; |
| 6732 | cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; | 6689 | cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; |
| 6733 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6690 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6734 | INC_PC(sizeof(bl_1_thumb)); | 6691 | INC_PC(sizeof(bl_1_thumb)); |
| 6735 | FETCH_INST; | 6692 | FETCH_INST; |
| 6736 | GOTO_NEXT_INST; | 6693 | GOTO_NEXT_INST; |
| @@ -6811,7 +6768,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6811 | RD = ((lo_val & 0xFFFF) | hi_val << 16); | 6768 | RD = ((lo_val & 0xFFFF) | hi_val << 16); |
| 6812 | } | 6769 | } |
| 6813 | 6770 | ||
| 6814 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6771 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6815 | INC_PC(sizeof(generic_arm_inst)); | 6772 | INC_PC(sizeof(generic_arm_inst)); |
| 6816 | FETCH_INST; | 6773 | FETCH_INST; |
| 6817 | GOTO_NEXT_INST; | 6774 | GOTO_NEXT_INST; |
| @@ -6841,7 +6798,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6841 | RD = finalDif; | 6798 | RD = finalDif; |
| 6842 | } | 6799 | } |
| 6843 | 6800 | ||
| 6844 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6801 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6845 | INC_PC(sizeof(generic_arm_inst)); | 6802 | INC_PC(sizeof(generic_arm_inst)); |
| 6846 | FETCH_INST; | 6803 | FETCH_INST; |
| 6847 | GOTO_NEXT_INST; | 6804 | GOTO_NEXT_INST; |
| @@ -6874,7 +6831,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6874 | RD = rn_val; | 6831 | RD = rn_val; |
| 6875 | } | 6832 | } |
| 6876 | 6833 | ||
| 6877 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6834 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6878 | INC_PC(sizeof(ssat_inst)); | 6835 | INC_PC(sizeof(ssat_inst)); |
| 6879 | FETCH_INST; | 6836 | FETCH_INST; |
| 6880 | GOTO_NEXT_INST; | 6837 | GOTO_NEXT_INST; |
| @@ -6896,7 +6853,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6896 | cpu->Cpsr |= (1 << 27); | 6853 | cpu->Cpsr |= (1 << 27); |
| 6897 | } | 6854 | } |
| 6898 | 6855 | ||
| 6899 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6856 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6900 | INC_PC(sizeof(ssat_inst)); | 6857 | INC_PC(sizeof(ssat_inst)); |
| 6901 | FETCH_INST; | 6858 | FETCH_INST; |
| 6902 | GOTO_NEXT_INST; | 6859 | GOTO_NEXT_INST; |
| @@ -6927,7 +6884,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6927 | } | 6884 | } |
| 6928 | } | 6885 | } |
| 6929 | 6886 | ||
| 6930 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6887 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6931 | INC_PC(sizeof(uxtab_inst)); | 6888 | INC_PC(sizeof(uxtab_inst)); |
| 6932 | FETCH_INST; | 6889 | FETCH_INST; |
| 6933 | GOTO_NEXT_INST; | 6890 | GOTO_NEXT_INST; |
| @@ -6940,7 +6897,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6940 | LOG_TRACE(Core_ARM11, "WFE executed."); | 6897 | LOG_TRACE(Core_ARM11, "WFE executed."); |
| 6941 | } | 6898 | } |
| 6942 | 6899 | ||
| 6943 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6900 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6944 | INC_PC_STUB; | 6901 | INC_PC_STUB; |
| 6945 | FETCH_INST; | 6902 | FETCH_INST; |
| 6946 | GOTO_NEXT_INST; | 6903 | GOTO_NEXT_INST; |
| @@ -6953,7 +6910,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6953 | LOG_TRACE(Core_ARM11, "WFI executed."); | 6910 | LOG_TRACE(Core_ARM11, "WFI executed."); |
| 6954 | } | 6911 | } |
| 6955 | 6912 | ||
| 6956 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6913 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6957 | INC_PC_STUB; | 6914 | INC_PC_STUB; |
| 6958 | FETCH_INST; | 6915 | FETCH_INST; |
| 6959 | GOTO_NEXT_INST; | 6916 | GOTO_NEXT_INST; |
| @@ -6966,7 +6923,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6966 | LOG_TRACE(Core_ARM11, "YIELD executed."); | 6923 | LOG_TRACE(Core_ARM11, "YIELD executed."); |
| 6967 | } | 6924 | } |
| 6968 | 6925 | ||
| 6969 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 6926 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6970 | INC_PC_STUB; | 6927 | INC_PC_STUB; |
| 6971 | FETCH_INST; | 6928 | FETCH_INST; |
| 6972 | GOTO_NEXT_INST; | 6929 | GOTO_NEXT_INST; |
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h index 1c324d29c..7a46dcc94 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.h +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h | |||
| @@ -4,6 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/arm/skyeye_common/armdefs.h" | 7 | struct ARMul_State; |
| 8 | 8 | ||
| 9 | unsigned InterpreterMainLoop(ARMul_State* state); | 9 | unsigned InterpreterMainLoop(ARMul_State* state); |
diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp deleted file mode 100644 index 5a9a6a788..000000000 --- a/src/core/arm/dyncom/arm_dyncom_run.cpp +++ /dev/null | |||
| @@ -1,93 +0,0 @@ | |||
| 1 | // Copyright 2012 Michael Kang, 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/arm/dyncom/arm_dyncom_run.h" | ||
| 6 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 7 | |||
| 8 | void switch_mode(ARMul_State* core, uint32_t mode) { | ||
| 9 | if (core->Mode == mode) | ||
| 10 | return; | ||
| 11 | |||
| 12 | if (mode != USERBANK) { | ||
| 13 | switch (core->Mode) { | ||
| 14 | case SYSTEM32MODE: // Shares registers with user mode | ||
| 15 | case USER32MODE: | ||
| 16 | core->Reg_usr[0] = core->Reg[13]; | ||
| 17 | core->Reg_usr[1] = core->Reg[14]; | ||
| 18 | break; | ||
| 19 | case IRQ32MODE: | ||
| 20 | core->Reg_irq[0] = core->Reg[13]; | ||
| 21 | core->Reg_irq[1] = core->Reg[14]; | ||
| 22 | core->Spsr[IRQBANK] = core->Spsr_copy; | ||
| 23 | break; | ||
| 24 | case SVC32MODE: | ||
| 25 | core->Reg_svc[0] = core->Reg[13]; | ||
| 26 | core->Reg_svc[1] = core->Reg[14]; | ||
| 27 | core->Spsr[SVCBANK] = core->Spsr_copy; | ||
| 28 | break; | ||
| 29 | case ABORT32MODE: | ||
| 30 | core->Reg_abort[0] = core->Reg[13]; | ||
| 31 | core->Reg_abort[1] = core->Reg[14]; | ||
| 32 | core->Spsr[ABORTBANK] = core->Spsr_copy; | ||
| 33 | break; | ||
| 34 | case UNDEF32MODE: | ||
| 35 | core->Reg_undef[0] = core->Reg[13]; | ||
| 36 | core->Reg_undef[1] = core->Reg[14]; | ||
| 37 | core->Spsr[UNDEFBANK] = core->Spsr_copy; | ||
| 38 | break; | ||
| 39 | case FIQ32MODE: | ||
| 40 | core->Reg_firq[0] = core->Reg[13]; | ||
| 41 | core->Reg_firq[1] = core->Reg[14]; | ||
| 42 | core->Spsr[FIQBANK] = core->Spsr_copy; | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | |||
| 46 | switch (mode) { | ||
| 47 | case USER32MODE: | ||
| 48 | core->Reg[13] = core->Reg_usr[0]; | ||
| 49 | core->Reg[14] = core->Reg_usr[1]; | ||
| 50 | core->Bank = USERBANK; | ||
| 51 | break; | ||
| 52 | case IRQ32MODE: | ||
| 53 | core->Reg[13] = core->Reg_irq[0]; | ||
| 54 | core->Reg[14] = core->Reg_irq[1]; | ||
| 55 | core->Spsr_copy = core->Spsr[IRQBANK]; | ||
| 56 | core->Bank = IRQBANK; | ||
| 57 | break; | ||
| 58 | case SVC32MODE: | ||
| 59 | core->Reg[13] = core->Reg_svc[0]; | ||
| 60 | core->Reg[14] = core->Reg_svc[1]; | ||
| 61 | core->Spsr_copy = core->Spsr[SVCBANK]; | ||
| 62 | core->Bank = SVCBANK; | ||
| 63 | break; | ||
| 64 | case ABORT32MODE: | ||
| 65 | core->Reg[13] = core->Reg_abort[0]; | ||
| 66 | core->Reg[14] = core->Reg_abort[1]; | ||
| 67 | core->Spsr_copy = core->Spsr[ABORTBANK]; | ||
| 68 | core->Bank = ABORTBANK; | ||
| 69 | break; | ||
| 70 | case UNDEF32MODE: | ||
| 71 | core->Reg[13] = core->Reg_undef[0]; | ||
| 72 | core->Reg[14] = core->Reg_undef[1]; | ||
| 73 | core->Spsr_copy = core->Spsr[UNDEFBANK]; | ||
| 74 | core->Bank = UNDEFBANK; | ||
| 75 | break; | ||
| 76 | case FIQ32MODE: | ||
| 77 | core->Reg[13] = core->Reg_firq[0]; | ||
| 78 | core->Reg[14] = core->Reg_firq[1]; | ||
| 79 | core->Spsr_copy = core->Spsr[FIQBANK]; | ||
| 80 | core->Bank = FIQBANK; | ||
| 81 | break; | ||
| 82 | case SYSTEM32MODE: // Shares registers with user mode. | ||
| 83 | core->Reg[13] = core->Reg_usr[0]; | ||
| 84 | core->Reg[14] = core->Reg_usr[1]; | ||
| 85 | core->Bank = SYSTEMBANK; | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | |||
| 89 | // Set the mode bits in the APSR | ||
| 90 | core->Cpsr = (core->Cpsr & ~core->Mode) | mode; | ||
| 91 | core->Mode = mode; | ||
| 92 | } | ||
| 93 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h index 85774c565..13bef17fc 100644 --- a/src/core/arm/dyncom/arm_dyncom_run.h +++ b/src/core/arm/dyncom/arm_dyncom_run.h | |||
| @@ -18,40 +18,31 @@ | |||
| 18 | 18 | ||
| 19 | #pragma once | 19 | #pragma once |
| 20 | 20 | ||
| 21 | #include "core/arm/skyeye_common/armdefs.h" | 21 | #include "core/arm/skyeye_common/armstate.h" |
| 22 | |||
| 23 | void switch_mode(ARMul_State* core, uint32_t mode); | ||
| 24 | |||
| 25 | // Note that for the 3DS, a Thumb instruction will only ever be | ||
| 26 | // two bytes in size. Thus we don't need to worry about ThumbEE | ||
| 27 | // or Thumb-2 where instructions can be 4 bytes in length. | ||
| 28 | static inline u32 GET_INST_SIZE(ARMul_State* core) { | ||
| 29 | return core->TFlag? 2 : 4; | ||
| 30 | } | ||
| 31 | 22 | ||
| 32 | /** | 23 | /** |
| 33 | * Checks if the PC is being read, and if so, word-aligns it. | 24 | * Checks if the PC is being read, and if so, word-aligns it. |
| 34 | * Used with address calculations. | 25 | * Used with address calculations. |
| 35 | * | 26 | * |
| 36 | * @param core The ARM CPU state instance. | 27 | * @param cpu The ARM CPU state instance. |
| 37 | * @param Rn The register being read. | 28 | * @param Rn The register being read. |
| 38 | * | 29 | * |
| 39 | * @return If the PC is being read, then the word-aligned PC value is returned. | 30 | * @return If the PC is being read, then the word-aligned PC value is returned. |
| 40 | * If the PC is not being read, then the value stored in the register is returned. | 31 | * If the PC is not being read, then the value stored in the register is returned. |
| 41 | */ | 32 | */ |
| 42 | static inline u32 CHECK_READ_REG15_WA(ARMul_State* core, int Rn) { | 33 | static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) { |
| 43 | return (Rn == 15) ? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; | 34 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; |
| 44 | } | 35 | } |
| 45 | 36 | ||
| 46 | /** | 37 | /** |
| 47 | * Reads the PC. Used for data processing operations that use the PC. | 38 | * Reads the PC. Used for data processing operations that use the PC. |
| 48 | * | 39 | * |
| 49 | * @param core The ARM CPU state instance. | 40 | * @param cpu The ARM CPU state instance. |
| 50 | * @param Rn The register being read. | 41 | * @param Rn The register being read. |
| 51 | * | 42 | * |
| 52 | * @return If the PC is being read, then the incremented PC value is returned. | 43 | * @return If the PC is being read, then the incremented PC value is returned. |
| 53 | * If the PC is not being read, then the values stored in the register is returned. | 44 | * If the PC is not being read, then the values stored in the register is returned. |
| 54 | */ | 45 | */ |
| 55 | static inline u32 CHECK_READ_REG15(ARMul_State* core, int Rn) { | 46 | static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int Rn) { |
| 56 | return (Rn == 15) ? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; | 47 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; |
| 57 | } | 48 | } |
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp index 3e79c44c0..29272fd5d 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp | |||
| @@ -6,20 +6,15 @@ | |||
| 6 | // ARM instruction, and using the existing ARM simulator. | 6 | // ARM instruction, and using the existing ARM simulator. |
| 7 | 7 | ||
| 8 | #include "core/arm/dyncom/arm_dyncom_thumb.h" | 8 | #include "core/arm/dyncom/arm_dyncom_thumb.h" |
| 9 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 9 | 10 | ||
| 10 | // Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field, | 11 | // Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field, |
| 11 | // with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions | 12 | // with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions |
| 12 | // allows easier simulation of the special dual BL instruction. | 13 | // allows easier simulation of the special dual BL instruction. |
| 13 | 14 | ||
| 14 | tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | 15 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { |
| 15 | tdstate valid = t_uninitialized; | 16 | ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED; |
| 16 | ARMword tinstr = instr; | 17 | u32 tinstr = GetThumbInstruction(instr, addr); |
| 17 | |||
| 18 | // The endian should be judge here | ||
| 19 | if((addr & 0x3) != 0) | ||
| 20 | tinstr = instr >> 16; | ||
| 21 | else | ||
| 22 | tinstr &= 0xFFFF; | ||
| 23 | 18 | ||
| 24 | *ainstr = 0xDEADC0DE; // Debugging to catch non updates | 19 | *ainstr = 0xDEADC0DE; // Debugging to catch non updates |
| 25 | 20 | ||
| @@ -36,7 +31,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 36 | 31 | ||
| 37 | case 3: // ADD/SUB | 32 | case 3: // ADD/SUB |
| 38 | { | 33 | { |
| 39 | static const ARMword subset[4] = { | 34 | static const u32 subset[4] = { |
| 40 | 0xE0900000, // ADDS Rd,Rs,Rn | 35 | 0xE0900000, // ADDS Rd,Rs,Rn |
| 41 | 0xE0500000, // SUBS Rd,Rs,Rn | 36 | 0xE0500000, // SUBS Rd,Rs,Rn |
| 42 | 0xE2900000, // ADDS Rd,Rs,#imm3 | 37 | 0xE2900000, // ADDS Rd,Rs,#imm3 |
| @@ -55,7 +50,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 55 | case 6: // ADD | 50 | case 6: // ADD |
| 56 | case 7: // SUB | 51 | case 7: // SUB |
| 57 | { | 52 | { |
| 58 | static const ARMword subset[4] = { | 53 | static const u32 subset[4] = { |
| 59 | 0xE3B00000, // MOVS Rd,#imm8 | 54 | 0xE3B00000, // MOVS Rd,#imm8 |
| 60 | 0xE3500000, // CMP Rd,#imm8 | 55 | 0xE3500000, // CMP Rd,#imm8 |
| 61 | 0xE2900000, // ADDS Rd,Rd,#imm8 | 56 | 0xE2900000, // ADDS Rd,Rd,#imm8 |
| @@ -84,7 +79,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 84 | }; | 79 | }; |
| 85 | 80 | ||
| 86 | static const struct { | 81 | static const struct { |
| 87 | ARMword opcode; | 82 | u32 opcode; |
| 88 | otype type; | 83 | otype type; |
| 89 | } subset[16] = { | 84 | } subset[16] = { |
| 90 | { 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs | 85 | { 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs |
| @@ -129,15 +124,14 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 129 | break; | 124 | break; |
| 130 | } | 125 | } |
| 131 | } else { | 126 | } else { |
| 132 | ARMword Rd = ((tinstr & 0x0007) >> 0); | 127 | u32 Rd = ((tinstr & 0x0007) >> 0); |
| 133 | ARMword Rs = ((tinstr & 0x0038) >> 3); | 128 | u32 Rs = ((tinstr & 0x0078) >> 3); |
| 134 | 129 | ||
| 135 | if (tinstr & (1 << 7)) | 130 | if (tinstr & (1 << 7)) |
| 136 | Rd += 8; | 131 | Rd += 8; |
| 137 | if (tinstr & (1 << 6)) | ||
| 138 | Rs += 8; | ||
| 139 | 132 | ||
| 140 | switch ((tinstr & 0x03C0) >> 6) { | 133 | switch ((tinstr & 0x03C0) >> 6) { |
| 134 | case 0x0: // ADD Rd,Rd,Rs | ||
| 141 | case 0x1: // ADD Rd,Rd,Hs | 135 | case 0x1: // ADD Rd,Rd,Hs |
| 142 | case 0x2: // ADD Hd,Hd,Rs | 136 | case 0x2: // ADD Hd,Hd,Rs |
| 143 | case 0x3: // ADD Hd,Hd,Hs | 137 | case 0x3: // ADD Hd,Hd,Hs |
| @@ -146,19 +140,19 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 146 | |(Rd << 12) // Rd | 140 | |(Rd << 12) // Rd |
| 147 | |(Rs << 0); // Rm | 141 | |(Rs << 0); // Rm |
| 148 | break; | 142 | break; |
| 143 | case 0x4: // CMP Rd,Rs | ||
| 149 | case 0x5: // CMP Rd,Hs | 144 | case 0x5: // CMP Rd,Hs |
| 150 | case 0x6: // CMP Hd,Rs | 145 | case 0x6: // CMP Hd,Rs |
| 151 | case 0x7: // CMP Hd,Hs | 146 | case 0x7: // CMP Hd,Hs |
| 152 | *ainstr = 0xE1500000 // base | 147 | *ainstr = 0xE1500000 // base |
| 153 | | (Rd << 16) // Rn | 148 | | (Rd << 16) // Rn |
| 154 | |(Rd << 12) // Rd | ||
| 155 | |(Rs << 0); // Rm | 149 | |(Rs << 0); // Rm |
| 156 | break; | 150 | break; |
| 151 | case 0x8: // MOV Rd,Rs | ||
| 157 | case 0x9: // MOV Rd,Hs | 152 | case 0x9: // MOV Rd,Hs |
| 158 | case 0xA: // MOV Hd,Rs | 153 | case 0xA: // MOV Hd,Rs |
| 159 | case 0xB: // MOV Hd,Hs | 154 | case 0xB: // MOV Hd,Hs |
| 160 | *ainstr = 0xE1A00000 // base | 155 | *ainstr = 0xE1A00000 // base |
| 161 | | (Rd << 16) // Rn | ||
| 162 | |(Rd << 12) // Rd | 156 | |(Rd << 12) // Rd |
| 163 | |(Rs << 0); // Rm | 157 | |(Rs << 0); // Rm |
| 164 | break; | 158 | break; |
| @@ -167,11 +161,6 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 167 | *ainstr = 0xE12FFF10 // base | 161 | *ainstr = 0xE12FFF10 // base |
| 168 | | ((tinstr & 0x0078) >> 3); // Rd | 162 | | ((tinstr & 0x0078) >> 3); // Rd |
| 169 | break; | 163 | break; |
| 170 | case 0x0: // UNDEFINED | ||
| 171 | case 0x4: // UNDEFINED | ||
| 172 | case 0x8: // UNDEFINED | ||
| 173 | valid = t_undefined; | ||
| 174 | break; | ||
| 175 | case 0xE: // BLX | 164 | case 0xE: // BLX |
| 176 | case 0xF: // BLX | 165 | case 0xF: // BLX |
| 177 | *ainstr = 0xE1200030 // base | 166 | *ainstr = 0xE1200030 // base |
| @@ -190,7 +179,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 190 | case 10: | 179 | case 10: |
| 191 | case 11: | 180 | case 11: |
| 192 | { | 181 | { |
| 193 | static const ARMword subset[8] = { | 182 | static const u32 subset[8] = { |
| 194 | 0xE7800000, // STR Rd,[Rb,Ro] | 183 | 0xE7800000, // STR Rd,[Rb,Ro] |
| 195 | 0xE18000B0, // STRH Rd,[Rb,Ro] | 184 | 0xE18000B0, // STRH Rd,[Rb,Ro] |
| 196 | 0xE7C00000, // STRB Rd,[Rb,Ro] | 185 | 0xE7C00000, // STRB Rd,[Rb,Ro] |
| @@ -213,7 +202,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 213 | case 14: // STRB Rd,[Rb,#imm5] | 202 | case 14: // STRB Rd,[Rb,#imm5] |
| 214 | case 15: // LDRB Rd,[Rb,#imm5] | 203 | case 15: // LDRB Rd,[Rb,#imm5] |
| 215 | { | 204 | { |
| 216 | static const ARMword subset[4] = { | 205 | static const u32 subset[4] = { |
| 217 | 0xE5800000, // STR Rd,[Rb,#imm5] | 206 | 0xE5800000, // STR Rd,[Rb,#imm5] |
| 218 | 0xE5900000, // LDR Rd,[Rb,#imm5] | 207 | 0xE5900000, // LDR Rd,[Rb,#imm5] |
| 219 | 0xE5C00000, // STRB Rd,[Rb,#imm5] | 208 | 0xE5C00000, // STRB Rd,[Rb,#imm5] |
| @@ -280,7 +269,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 280 | | BITS(tinstr, 0, 3) // imm4 field; | 269 | | BITS(tinstr, 0, 3) // imm4 field; |
| 281 | | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12 | 270 | | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12 |
| 282 | } else if ((tinstr & 0x0F00) == 0x0200) { | 271 | } else if ((tinstr & 0x0F00) == 0x0200) { |
| 283 | static const ARMword subset[4] = { | 272 | static const u32 subset[4] = { |
| 284 | 0xE6BF0070, // SXTH | 273 | 0xE6BF0070, // SXTH |
| 285 | 0xE6AF0070, // SXTB | 274 | 0xE6AF0070, // SXTB |
| 286 | 0xE6FF0070, // UXTH | 275 | 0xE6FF0070, // UXTH |
| @@ -304,7 +293,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 304 | | (BIT(tinstr, 4) << 18); // enable bit | 293 | | (BIT(tinstr, 4) << 18); // enable bit |
| 305 | } | 294 | } |
| 306 | } else if ((tinstr & 0x0F00) == 0x0a00) { | 295 | } else if ((tinstr & 0x0F00) == 0x0a00) { |
| 307 | static const ARMword subset[3] = { | 296 | static const u32 subset[3] = { |
| 308 | 0xE6BF0F30, // REV | 297 | 0xE6BF0F30, // REV |
| 309 | 0xE6BF0FB0, // REV16 | 298 | 0xE6BF0FB0, // REV16 |
| 310 | 0xE6FF0FB0, // REVSH | 299 | 0xE6FF0FB0, // REVSH |
| @@ -314,7 +303,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 314 | | (BITS(tinstr, 0, 2) << 12) // Rd | 303 | | (BITS(tinstr, 0, 2) << 12) // Rd |
| 315 | | BITS(tinstr, 3, 5); // Rm | 304 | | BITS(tinstr, 3, 5); // Rm |
| 316 | } else { | 305 | } else { |
| 317 | static const ARMword subset[4] = { | 306 | static const u32 subset[4] = { |
| 318 | 0xE92D0000, // STMDB sp!,{rlist} | 307 | 0xE92D0000, // STMDB sp!,{rlist} |
| 319 | 0xE92D4000, // STMDB sp!,{rlist,lr} | 308 | 0xE92D4000, // STMDB sp!,{rlist,lr} |
| 320 | 0xE8BD0000, // LDMIA sp!,{rlist} | 309 | 0xE8BD0000, // LDMIA sp!,{rlist} |
| @@ -362,21 +351,21 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 362 | else | 351 | else |
| 363 | *ainstr |= (tinstr & 0x00FF); | 352 | *ainstr |= (tinstr & 0x00FF); |
| 364 | } else if ((tinstr & 0x0F00) != 0x0E00) | 353 | } else if ((tinstr & 0x0F00) != 0x0E00) |
| 365 | valid = t_branch; | 354 | valid = ThumbDecodeStatus::BRANCH; |
| 366 | else // UNDEFINED : cc=1110(AL) uses different format | 355 | else // UNDEFINED : cc=1110(AL) uses different format |
| 367 | valid = t_undefined; | 356 | valid = ThumbDecodeStatus::UNDEFINED; |
| 368 | 357 | ||
| 369 | break; | 358 | break; |
| 370 | 359 | ||
| 371 | case 28: // B | 360 | case 28: // B |
| 372 | valid = t_branch; | 361 | valid = ThumbDecodeStatus::BRANCH; |
| 373 | break; | 362 | break; |
| 374 | 363 | ||
| 375 | case 29: | 364 | case 29: |
| 376 | if(tinstr & 0x1) | 365 | if (tinstr & 0x1) |
| 377 | valid = t_undefined; | 366 | valid = ThumbDecodeStatus::UNDEFINED; |
| 378 | else | 367 | else |
| 379 | valid = t_branch; | 368 | valid = ThumbDecodeStatus::BRANCH; |
| 380 | break; | 369 | break; |
| 381 | 370 | ||
| 382 | case 30: // BL instruction 1 | 371 | case 30: // BL instruction 1 |
| @@ -385,7 +374,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 385 | // simulation simple (from the user perspective) we check if the following instruction is | 374 | // simulation simple (from the user perspective) we check if the following instruction is |
| 386 | // the second half of this BL, and if it is we simulate it immediately | 375 | // the second half of this BL, and if it is we simulate it immediately |
| 387 | 376 | ||
| 388 | valid = t_branch; | 377 | valid = ThumbDecodeStatus::BRANCH; |
| 389 | break; | 378 | break; |
| 390 | 379 | ||
| 391 | case 31: // BL instruction 2 | 380 | case 31: // BL instruction 2 |
| @@ -394,7 +383,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | |||
| 394 | // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the | 383 | // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the |
| 395 | // simulation of it on its own, with undefined results if r14 is not suitably initialised. | 384 | // simulation of it on its own, with undefined results if r14 is not suitably initialised. |
| 396 | 385 | ||
| 397 | valid = t_branch; | 386 | valid = ThumbDecodeStatus::BRANCH; |
| 398 | break; | 387 | break; |
| 399 | } | 388 | } |
| 400 | 389 | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h index 8394ff156..447974363 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.h +++ b/src/core/arm/dyncom/arm_dyncom_thumb.h | |||
| @@ -26,22 +26,24 @@ | |||
| 26 | 26 | ||
| 27 | #pragma once | 27 | #pragma once |
| 28 | 28 | ||
| 29 | #include "core/arm/skyeye_common/armdefs.h" | 29 | #include "common/common_types.h" |
| 30 | 30 | ||
| 31 | enum tdstate { | 31 | enum class ThumbDecodeStatus { |
| 32 | t_undefined, // Undefined Thumb instruction | 32 | UNDEFINED, // Undefined Thumb instruction |
| 33 | t_decoded, // Instruction decoded to ARM equivalent | 33 | DECODED, // Instruction decoded to ARM equivalent |
| 34 | t_branch, // Thumb branch (already processed) | 34 | BRANCH, // Thumb branch (already processed) |
| 35 | t_uninitialized, | 35 | UNINITIALIZED, |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size); | 38 | // Translates a Thumb mode instruction into its ARM equivalent. |
| 39 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); | ||
| 39 | 40 | ||
| 40 | static inline u32 get_thumb_instr(u32 instr, u32 pc) { | 41 | static inline u32 GetThumbInstruction(u32 instr, u32 address) { |
| 41 | u32 tinstr; | 42 | // Normally you would need to handle instruction endianness, |
| 42 | if ((pc & 0x3) != 0) | 43 | // however, it is fixed to little-endian on the MPCore, so |
| 43 | tinstr = instr >> 16; | 44 | // there's no need to check for this beforehand. |
| 44 | else | 45 | if ((address & 0x3) != 0) |
| 45 | tinstr = instr & 0xFFFF; | 46 | return instr >> 16; |
| 46 | return tinstr; | 47 | |
| 48 | return instr & 0xFFFF; | ||
| 47 | } | 49 | } |
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp deleted file mode 100644 index 4f7a48fab..000000000 --- a/src/core/arm/interpreter/arminit.cpp +++ /dev/null | |||
| @@ -1,128 +0,0 @@ | |||
| 1 | /* arminit.c -- ARMulator initialization: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #include <cstring> | ||
| 19 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 20 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 21 | |||
| 22 | /***************************************************************************\ | ||
| 23 | * Returns a new instantiation of the ARMulator's state * | ||
| 24 | \***************************************************************************/ | ||
| 25 | ARMul_State* ARMul_NewState(ARMul_State* state) | ||
| 26 | { | ||
| 27 | state->Emulate = RUN; | ||
| 28 | state->Mode = USER32MODE; | ||
| 29 | |||
| 30 | state->lateabtSig = HIGH; | ||
| 31 | state->bigendSig = LOW; | ||
| 32 | |||
| 33 | return state; | ||
| 34 | } | ||
| 35 | |||
| 36 | /***************************************************************************\ | ||
| 37 | * Call this routine to set ARMulator to model a certain processor * | ||
| 38 | \***************************************************************************/ | ||
| 39 | |||
| 40 | void ARMul_SelectProcessor(ARMul_State* state, unsigned properties) | ||
| 41 | { | ||
| 42 | state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0; | ||
| 43 | state->is_v5 = (properties & ARM_v5_Prop) != 0; | ||
| 44 | state->is_v5e = (properties & ARM_v5e_Prop) != 0; | ||
| 45 | state->is_v6 = (properties & ARM_v6_Prop) != 0; | ||
| 46 | state->is_v7 = (properties & ARM_v7_Prop) != 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | // Resets certain MPCore CP15 values to their ARM-defined reset values. | ||
| 50 | static void ResetMPCoreCP15Registers(ARMul_State* cpu) | ||
| 51 | { | ||
| 52 | // c0 | ||
| 53 | cpu->CP15[CP15_MAIN_ID] = 0x410FB024; | ||
| 54 | cpu->CP15[CP15_TLB_TYPE] = 0x00000800; | ||
| 55 | cpu->CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; | ||
| 56 | cpu->CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; | ||
| 57 | cpu->CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; | ||
| 58 | cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; | ||
| 59 | cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; | ||
| 60 | cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; | ||
| 61 | cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; | ||
| 62 | cpu->CP15[CP15_ISA_FEATURE_0] = 0x00100011; | ||
| 63 | cpu->CP15[CP15_ISA_FEATURE_1] = 0x12002111; | ||
| 64 | cpu->CP15[CP15_ISA_FEATURE_2] = 0x11221011; | ||
| 65 | cpu->CP15[CP15_ISA_FEATURE_3] = 0x01102131; | ||
| 66 | cpu->CP15[CP15_ISA_FEATURE_4] = 0x00000141; | ||
| 67 | |||
| 68 | // c1 | ||
| 69 | cpu->CP15[CP15_CONTROL] = 0x00054078; | ||
| 70 | cpu->CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; | ||
| 71 | cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; | ||
| 72 | |||
| 73 | // c2 | ||
| 74 | cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; | ||
| 75 | cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; | ||
| 76 | cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; | ||
| 77 | |||
| 78 | // c3 | ||
| 79 | cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; | ||
| 80 | |||
| 81 | // c7 | ||
| 82 | cpu->CP15[CP15_PHYS_ADDRESS] = 0x00000000; | ||
| 83 | |||
| 84 | // c9 | ||
| 85 | cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; | ||
| 86 | |||
| 87 | // c10 | ||
| 88 | cpu->CP15[CP15_TLB_LOCKDOWN] = 0x00000000; | ||
| 89 | cpu->CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; | ||
| 90 | cpu->CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0; | ||
| 91 | |||
| 92 | // c13 | ||
| 93 | cpu->CP15[CP15_PID] = 0x00000000; | ||
| 94 | cpu->CP15[CP15_CONTEXT_ID] = 0x00000000; | ||
| 95 | cpu->CP15[CP15_THREAD_UPRW] = 0x00000000; | ||
| 96 | cpu->CP15[CP15_THREAD_URO] = 0x00000000; | ||
| 97 | cpu->CP15[CP15_THREAD_PRW] = 0x00000000; | ||
| 98 | |||
| 99 | // c15 | ||
| 100 | cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000; | ||
| 101 | cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; | ||
| 102 | cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; | ||
| 103 | cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; | ||
| 104 | cpu->CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; | ||
| 105 | } | ||
| 106 | |||
| 107 | /***************************************************************************\ | ||
| 108 | * Call this routine to set up the initial machine state (or perform a RESET * | ||
| 109 | \***************************************************************************/ | ||
| 110 | void ARMul_Reset(ARMul_State* state) | ||
| 111 | { | ||
| 112 | VFPInit(state); | ||
| 113 | |||
| 114 | state->Reg[15] = 0; | ||
| 115 | state->Cpsr = INTBITS | SVC32MODE; | ||
| 116 | state->Mode = SVC32MODE; | ||
| 117 | state->Bank = SVCBANK; | ||
| 118 | |||
| 119 | ResetMPCoreCP15Registers(state); | ||
| 120 | |||
| 121 | state->NresetSig = HIGH; | ||
| 122 | state->NfiqSig = HIGH; | ||
| 123 | state->NirqSig = HIGH; | ||
| 124 | state->NtransSig = (state->Mode & 3) ? HIGH : LOW; | ||
| 125 | state->abortSig = LOW; | ||
| 126 | |||
| 127 | state->NumInstrs = 0; | ||
| 128 | } | ||
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp deleted file mode 100644 index 83f7f3e2c..000000000 --- a/src/core/arm/interpreter/armsupp.cpp +++ /dev/null | |||
| @@ -1,637 +0,0 @@ | |||
| 1 | /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #include "common/logging/log.h" | ||
| 19 | |||
| 20 | #include "core/mem_map.h" | ||
| 21 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 22 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 23 | |||
| 24 | // Unsigned sum of absolute difference | ||
| 25 | u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) | ||
| 26 | { | ||
| 27 | if (left > right) | ||
| 28 | return left - right; | ||
| 29 | |||
| 30 | return right - left; | ||
| 31 | } | ||
| 32 | |||
| 33 | // Add with carry, indicates if a carry-out or signed overflow occurred. | ||
| 34 | u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred) | ||
| 35 | { | ||
| 36 | u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in; | ||
| 37 | s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in; | ||
| 38 | u64 result = (unsigned_sum & 0xFFFFFFFF); | ||
| 39 | |||
| 40 | if (carry_out_occurred) | ||
| 41 | *carry_out_occurred = (result != unsigned_sum); | ||
| 42 | |||
| 43 | if (overflow_occurred) | ||
| 44 | *overflow_occurred = ((s64)(s32)result != signed_sum); | ||
| 45 | |||
| 46 | return (u32)result; | ||
| 47 | } | ||
| 48 | |||
| 49 | // Compute whether an addition of A and B, giving RESULT, overflowed. | ||
| 50 | bool AddOverflow(ARMword a, ARMword b, ARMword result) | ||
| 51 | { | ||
| 52 | return ((NEG(a) && NEG(b) && POS(result)) || | ||
| 53 | (POS(a) && POS(b) && NEG(result))); | ||
| 54 | } | ||
| 55 | |||
| 56 | // Compute whether a subtraction of A and B, giving RESULT, overflowed. | ||
| 57 | bool SubOverflow(ARMword a, ARMword b, ARMword result) | ||
| 58 | { | ||
| 59 | return ((NEG(a) && POS(b) && POS(result)) || | ||
| 60 | (POS(a) && NEG(b) && NEG(result))); | ||
| 61 | } | ||
| 62 | |||
| 63 | // Returns true if the Q flag should be set as a result of overflow. | ||
| 64 | bool ARMul_AddOverflowQ(ARMword a, ARMword b) | ||
| 65 | { | ||
| 66 | u32 result = a + b; | ||
| 67 | if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0) | ||
| 68 | return true; | ||
| 69 | |||
| 70 | return false; | ||
| 71 | } | ||
| 72 | |||
| 73 | // 8-bit signed saturated addition | ||
| 74 | u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) | ||
| 75 | { | ||
| 76 | u8 result = left + right; | ||
| 77 | |||
| 78 | if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) { | ||
| 79 | if (left & 0x80) | ||
| 80 | result = 0x80; | ||
| 81 | else | ||
| 82 | result = 0x7F; | ||
| 83 | } | ||
| 84 | |||
| 85 | return result; | ||
| 86 | } | ||
| 87 | |||
| 88 | // 8-bit signed saturated subtraction | ||
| 89 | u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) | ||
| 90 | { | ||
| 91 | u8 result = left - right; | ||
| 92 | |||
| 93 | if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) { | ||
| 94 | if (left & 0x80) | ||
| 95 | result = 0x80; | ||
| 96 | else | ||
| 97 | result = 0x7F; | ||
| 98 | } | ||
| 99 | |||
| 100 | return result; | ||
| 101 | } | ||
| 102 | |||
| 103 | // 16-bit signed saturated addition | ||
| 104 | u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) | ||
| 105 | { | ||
| 106 | u16 result = left + right; | ||
| 107 | |||
| 108 | if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) { | ||
| 109 | if (left & 0x8000) | ||
| 110 | result = 0x8000; | ||
| 111 | else | ||
| 112 | result = 0x7FFF; | ||
| 113 | } | ||
| 114 | |||
| 115 | return result; | ||
| 116 | } | ||
| 117 | |||
| 118 | // 16-bit signed saturated subtraction | ||
| 119 | u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) | ||
| 120 | { | ||
| 121 | u16 result = left - right; | ||
| 122 | |||
| 123 | if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) { | ||
| 124 | if (left & 0x8000) | ||
| 125 | result = 0x8000; | ||
| 126 | else | ||
| 127 | result = 0x7FFF; | ||
| 128 | } | ||
| 129 | |||
| 130 | return result; | ||
| 131 | } | ||
| 132 | |||
| 133 | // 8-bit unsigned saturated addition | ||
| 134 | u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) | ||
| 135 | { | ||
| 136 | u8 result = left + right; | ||
| 137 | |||
| 138 | if (result < left) | ||
| 139 | result = 0xFF; | ||
| 140 | |||
| 141 | return result; | ||
| 142 | } | ||
| 143 | |||
| 144 | // 16-bit unsigned saturated addition | ||
| 145 | u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) | ||
| 146 | { | ||
| 147 | u16 result = left + right; | ||
| 148 | |||
| 149 | if (result < left) | ||
| 150 | result = 0xFFFF; | ||
| 151 | |||
| 152 | return result; | ||
| 153 | } | ||
| 154 | |||
| 155 | // 8-bit unsigned saturated subtraction | ||
| 156 | u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) | ||
| 157 | { | ||
| 158 | if (left <= right) | ||
| 159 | return 0; | ||
| 160 | |||
| 161 | return left - right; | ||
| 162 | } | ||
| 163 | |||
| 164 | // 16-bit unsigned saturated subtraction | ||
| 165 | u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) | ||
| 166 | { | ||
| 167 | if (left <= right) | ||
| 168 | return 0; | ||
| 169 | |||
| 170 | return left - right; | ||
| 171 | } | ||
| 172 | |||
| 173 | // Signed saturation. | ||
| 174 | u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||
| 175 | { | ||
| 176 | const u32 max = (1 << shift) - 1; | ||
| 177 | const s32 top = (value >> shift); | ||
| 178 | |||
| 179 | if (top > 0) { | ||
| 180 | *saturation_occurred = true; | ||
| 181 | return max; | ||
| 182 | } | ||
| 183 | else if (top < -1) { | ||
| 184 | *saturation_occurred = true; | ||
| 185 | return ~max; | ||
| 186 | } | ||
| 187 | |||
| 188 | *saturation_occurred = false; | ||
| 189 | return (u32)value; | ||
| 190 | } | ||
| 191 | |||
| 192 | // Unsigned saturation | ||
| 193 | u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||
| 194 | { | ||
| 195 | const u32 max = (1 << shift) - 1; | ||
| 196 | |||
| 197 | if (value < 0) { | ||
| 198 | *saturation_occurred = true; | ||
| 199 | return 0; | ||
| 200 | } else if ((u32)value > max) { | ||
| 201 | *saturation_occurred = true; | ||
| 202 | return max; | ||
| 203 | } | ||
| 204 | |||
| 205 | *saturation_occurred = false; | ||
| 206 | return (u32)value; | ||
| 207 | } | ||
| 208 | |||
| 209 | // Whether or not the given CPU is in big endian mode (E bit is set) | ||
| 210 | bool InBigEndianMode(ARMul_State* cpu) | ||
| 211 | { | ||
| 212 | return (cpu->Cpsr & (1 << 9)) != 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | // Whether or not the given CPU is in a mode other than user mode. | ||
| 216 | bool InAPrivilegedMode(ARMul_State* cpu) | ||
| 217 | { | ||
| 218 | return (cpu->Mode != USER32MODE); | ||
| 219 | } | ||
| 220 | |||
| 221 | // Reads from the CP15 registers. Used with implementation of the MRC instruction. | ||
| 222 | // Note that since the 3DS does not have the hypervisor extensions, these registers | ||
| 223 | // are not implemented. | ||
| 224 | u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) | ||
| 225 | { | ||
| 226 | // Unprivileged registers | ||
| 227 | if (crn == 13 && opcode_1 == 0 && crm == 0) | ||
| 228 | { | ||
| 229 | if (opcode_2 == 2) | ||
| 230 | return cpu->CP15[CP15_THREAD_UPRW]; | ||
| 231 | |||
| 232 | if (opcode_2 == 3) | ||
| 233 | return cpu->CP15[CP15_THREAD_URO]; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (InAPrivilegedMode(cpu)) | ||
| 237 | { | ||
| 238 | if (crn == 0 && opcode_1 == 0) | ||
| 239 | { | ||
| 240 | if (crm == 0) | ||
| 241 | { | ||
| 242 | if (opcode_2 == 0) | ||
| 243 | return cpu->CP15[CP15_MAIN_ID]; | ||
| 244 | |||
| 245 | if (opcode_2 == 1) | ||
| 246 | return cpu->CP15[CP15_CACHE_TYPE]; | ||
| 247 | |||
| 248 | if (opcode_2 == 3) | ||
| 249 | return cpu->CP15[CP15_TLB_TYPE]; | ||
| 250 | |||
| 251 | if (opcode_2 == 5) | ||
| 252 | return cpu->CP15[CP15_CPU_ID]; | ||
| 253 | } | ||
| 254 | else if (crm == 1) | ||
| 255 | { | ||
| 256 | if (opcode_2 == 0) | ||
| 257 | return cpu->CP15[CP15_PROCESSOR_FEATURE_0]; | ||
| 258 | |||
| 259 | if (opcode_2 == 1) | ||
| 260 | return cpu->CP15[CP15_PROCESSOR_FEATURE_1]; | ||
| 261 | |||
| 262 | if (opcode_2 == 2) | ||
| 263 | return cpu->CP15[CP15_DEBUG_FEATURE_0]; | ||
| 264 | |||
| 265 | if (opcode_2 == 4) | ||
| 266 | return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0]; | ||
| 267 | |||
| 268 | if (opcode_2 == 5) | ||
| 269 | return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1]; | ||
| 270 | |||
| 271 | if (opcode_2 == 6) | ||
| 272 | return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2]; | ||
| 273 | |||
| 274 | if (opcode_2 == 7) | ||
| 275 | return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3]; | ||
| 276 | } | ||
| 277 | else if (crm == 2) | ||
| 278 | { | ||
| 279 | if (opcode_2 == 0) | ||
| 280 | return cpu->CP15[CP15_ISA_FEATURE_0]; | ||
| 281 | |||
| 282 | if (opcode_2 == 1) | ||
| 283 | return cpu->CP15[CP15_ISA_FEATURE_1]; | ||
| 284 | |||
| 285 | if (opcode_2 == 2) | ||
| 286 | return cpu->CP15[CP15_ISA_FEATURE_2]; | ||
| 287 | |||
| 288 | if (opcode_2 == 3) | ||
| 289 | return cpu->CP15[CP15_ISA_FEATURE_3]; | ||
| 290 | |||
| 291 | if (opcode_2 == 4) | ||
| 292 | return cpu->CP15[CP15_ISA_FEATURE_4]; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | if (crn == 1 && opcode_1 == 0 && crm == 0) | ||
| 297 | { | ||
| 298 | if (opcode_2 == 0) | ||
| 299 | return cpu->CP15[CP15_CONTROL]; | ||
| 300 | |||
| 301 | if (opcode_2 == 1) | ||
| 302 | return cpu->CP15[CP15_AUXILIARY_CONTROL]; | ||
| 303 | |||
| 304 | if (opcode_2 == 2) | ||
| 305 | return cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; | ||
| 306 | } | ||
| 307 | |||
| 308 | if (crn == 2 && opcode_1 == 0 && crm == 0) | ||
| 309 | { | ||
| 310 | if (opcode_2 == 0) | ||
| 311 | return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0]; | ||
| 312 | |||
| 313 | if (opcode_2 == 1) | ||
| 314 | return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1]; | ||
| 315 | |||
| 316 | if (opcode_2 == 2) | ||
| 317 | return cpu->CP15[CP15_TRANSLATION_BASE_CONTROL]; | ||
| 318 | } | ||
| 319 | |||
| 320 | if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 321 | return cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL]; | ||
| 322 | |||
| 323 | if (crn == 5 && opcode_1 == 0 && crm == 0) | ||
| 324 | { | ||
| 325 | if (opcode_2 == 0) | ||
| 326 | return cpu->CP15[CP15_FAULT_STATUS]; | ||
| 327 | |||
| 328 | if (opcode_2 == 1) | ||
| 329 | return cpu->CP15[CP15_INSTR_FAULT_STATUS]; | ||
| 330 | } | ||
| 331 | |||
| 332 | if (crn == 6 && opcode_1 == 0 && crm == 0) | ||
| 333 | { | ||
| 334 | if (opcode_2 == 0) | ||
| 335 | return cpu->CP15[CP15_FAULT_ADDRESS]; | ||
| 336 | |||
| 337 | if (opcode_2 == 1) | ||
| 338 | return cpu->CP15[CP15_WFAR]; | ||
| 339 | } | ||
| 340 | |||
| 341 | if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) | ||
| 342 | return cpu->CP15[CP15_PHYS_ADDRESS]; | ||
| 343 | |||
| 344 | if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 345 | return cpu->CP15[CP15_DATA_CACHE_LOCKDOWN]; | ||
| 346 | |||
| 347 | if (crn == 10 && opcode_1 == 0) | ||
| 348 | { | ||
| 349 | if (crm == 0 && opcode_2 == 0) | ||
| 350 | return cpu->CP15[CP15_TLB_LOCKDOWN]; | ||
| 351 | |||
| 352 | if (crm == 2) | ||
| 353 | { | ||
| 354 | if (opcode_2 == 0) | ||
| 355 | return cpu->CP15[CP15_PRIMARY_REGION_REMAP]; | ||
| 356 | |||
| 357 | if (opcode_2 == 1) | ||
| 358 | return cpu->CP15[CP15_NORMAL_REGION_REMAP]; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | if (crn == 13 && crm == 0) | ||
| 363 | { | ||
| 364 | if (opcode_2 == 0) | ||
| 365 | return cpu->CP15[CP15_PID]; | ||
| 366 | |||
| 367 | if (opcode_2 == 1) | ||
| 368 | return cpu->CP15[CP15_CONTEXT_ID]; | ||
| 369 | |||
| 370 | if (opcode_2 == 4) | ||
| 371 | return cpu->CP15[CP15_THREAD_PRW]; | ||
| 372 | } | ||
| 373 | |||
| 374 | if (crn == 15) | ||
| 375 | { | ||
| 376 | if (opcode_1 == 0 && crm == 12) | ||
| 377 | { | ||
| 378 | if (opcode_2 == 0) | ||
| 379 | return cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; | ||
| 380 | |||
| 381 | if (opcode_2 == 1) | ||
| 382 | return cpu->CP15[CP15_CYCLE_COUNTER]; | ||
| 383 | |||
| 384 | if (opcode_2 == 2) | ||
| 385 | return cpu->CP15[CP15_COUNT_0]; | ||
| 386 | |||
| 387 | if (opcode_2 == 3) | ||
| 388 | return cpu->CP15[CP15_COUNT_1]; | ||
| 389 | } | ||
| 390 | |||
| 391 | if (opcode_1 == 5 && opcode_2 == 2) | ||
| 392 | { | ||
| 393 | if (crm == 5) | ||
| 394 | return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; | ||
| 395 | |||
| 396 | if (crm == 6) | ||
| 397 | return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; | ||
| 398 | |||
| 399 | if (crm == 7) | ||
| 400 | return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||
| 404 | return cpu->CP15[CP15_TLB_DEBUG_CONTROL]; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 408 | LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2); | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | // Write to the CP15 registers. Used with implementation of the MCR instruction. | ||
| 413 | // Note that since the 3DS does not have the hypervisor extensions, these registers | ||
| 414 | // are not implemented. | ||
| 415 | void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) | ||
| 416 | { | ||
| 417 | if (InAPrivilegedMode(cpu)) | ||
| 418 | { | ||
| 419 | if (crn == 1 && opcode_1 == 0 && crm == 0) | ||
| 420 | { | ||
| 421 | if (opcode_2 == 0) | ||
| 422 | cpu->CP15[CP15_CONTROL] = value; | ||
| 423 | else if (opcode_2 == 1) | ||
| 424 | cpu->CP15[CP15_AUXILIARY_CONTROL] = value; | ||
| 425 | else if (opcode_2 == 2) | ||
| 426 | cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; | ||
| 427 | } | ||
| 428 | else if (crn == 2 && opcode_1 == 0 && crm == 0) | ||
| 429 | { | ||
| 430 | if (opcode_2 == 0) | ||
| 431 | cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; | ||
| 432 | else if (opcode_2 == 1) | ||
| 433 | cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; | ||
| 434 | else if (opcode_2 == 2) | ||
| 435 | cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = value; | ||
| 436 | } | ||
| 437 | else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 438 | { | ||
| 439 | cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; | ||
| 440 | } | ||
| 441 | else if (crn == 5 && opcode_1 == 0 && crm == 0) | ||
| 442 | { | ||
| 443 | if (opcode_2 == 0) | ||
| 444 | cpu->CP15[CP15_FAULT_STATUS] = value; | ||
| 445 | else if (opcode_2 == 1) | ||
| 446 | cpu->CP15[CP15_INSTR_FAULT_STATUS] = value; | ||
| 447 | } | ||
| 448 | else if (crn == 6 && opcode_1 == 0 && crm == 0) | ||
| 449 | { | ||
| 450 | if (opcode_2 == 0) | ||
| 451 | cpu->CP15[CP15_FAULT_ADDRESS] = value; | ||
| 452 | else if (opcode_2 == 1) | ||
| 453 | cpu->CP15[CP15_WFAR] = value; | ||
| 454 | } | ||
| 455 | else if (crn == 7 && opcode_1 == 0) | ||
| 456 | { | ||
| 457 | if (crm == 0 && opcode_2 == 4) | ||
| 458 | { | ||
| 459 | cpu->CP15[CP15_WAIT_FOR_INTERRUPT] = value; | ||
| 460 | } | ||
| 461 | else if (crm == 4 && opcode_2 == 0) | ||
| 462 | { | ||
| 463 | // NOTE: Not entirely accurate. This should do permission checks. | ||
| 464 | cpu->CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); | ||
| 465 | } | ||
| 466 | else if (crm == 5) | ||
| 467 | { | ||
| 468 | if (opcode_2 == 0) | ||
| 469 | cpu->CP15[CP15_INVALIDATE_INSTR_CACHE] = value; | ||
| 470 | else if (opcode_2 == 1) | ||
| 471 | cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; | ||
| 472 | else if (opcode_2 == 2) | ||
| 473 | cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; | ||
| 474 | else if (opcode_2 == 6) | ||
| 475 | cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; | ||
| 476 | else if (opcode_2 == 7) | ||
| 477 | cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; | ||
| 478 | } | ||
| 479 | else if (crm == 6) | ||
| 480 | { | ||
| 481 | if (opcode_2 == 0) | ||
| 482 | cpu->CP15[CP15_INVALIDATE_DATA_CACHE] = value; | ||
| 483 | else if (opcode_2 == 1) | ||
| 484 | cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 485 | else if (opcode_2 == 2) | ||
| 486 | cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 487 | } | ||
| 488 | else if (crm == 7 && opcode_2 == 0) | ||
| 489 | { | ||
| 490 | cpu->CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; | ||
| 491 | } | ||
| 492 | else if (crm == 10) | ||
| 493 | { | ||
| 494 | if (opcode_2 == 0) | ||
| 495 | cpu->CP15[CP15_CLEAN_DATA_CACHE] = value; | ||
| 496 | else if (opcode_2 == 1) | ||
| 497 | cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 498 | else if (opcode_2 == 2) | ||
| 499 | cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 500 | } | ||
| 501 | else if (crm == 14) | ||
| 502 | { | ||
| 503 | if (opcode_2 == 0) | ||
| 504 | cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; | ||
| 505 | else if (opcode_2 == 1) | ||
| 506 | cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 507 | else if (opcode_2 == 2) | ||
| 508 | cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | else if (crn == 8 && opcode_1 == 0) | ||
| 512 | { | ||
| 513 | LOG_WARNING(Core_ARM11, "TLB operations not fully implemented."); | ||
| 514 | |||
| 515 | if (crm == 5) | ||
| 516 | { | ||
| 517 | if (opcode_2 == 0) | ||
| 518 | cpu->CP15[CP15_INVALIDATE_ITLB] = value; | ||
| 519 | else if (opcode_2 == 1) | ||
| 520 | cpu->CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; | ||
| 521 | else if (opcode_2 == 2) | ||
| 522 | cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 523 | else if (opcode_2 == 3) | ||
| 524 | cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; | ||
| 525 | } | ||
| 526 | else if (crm == 6) | ||
| 527 | { | ||
| 528 | if (opcode_2 == 0) | ||
| 529 | cpu->CP15[CP15_INVALIDATE_DTLB] = value; | ||
| 530 | else if (opcode_2 == 1) | ||
| 531 | cpu->CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; | ||
| 532 | else if (opcode_2 == 2) | ||
| 533 | cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 534 | else if (opcode_2 == 3) | ||
| 535 | cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; | ||
| 536 | } | ||
| 537 | else if (crm == 7) | ||
| 538 | { | ||
| 539 | if (opcode_2 == 0) | ||
| 540 | cpu->CP15[CP15_INVALIDATE_UTLB] = value; | ||
| 541 | else if (opcode_2 == 1) | ||
| 542 | cpu->CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; | ||
| 543 | else if (opcode_2 == 2) | ||
| 544 | cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 545 | else if (opcode_2 == 3) | ||
| 546 | cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 550 | { | ||
| 551 | cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = value; | ||
| 552 | } | ||
| 553 | else if (crn == 10 && opcode_1 == 0) | ||
| 554 | { | ||
| 555 | if (crm == 0 && opcode_2 == 0) | ||
| 556 | { | ||
| 557 | cpu->CP15[CP15_TLB_LOCKDOWN] = value; | ||
| 558 | } | ||
| 559 | else if (crm == 2) | ||
| 560 | { | ||
| 561 | if (opcode_2 == 0) | ||
| 562 | cpu->CP15[CP15_PRIMARY_REGION_REMAP] = value; | ||
| 563 | else if (opcode_2 == 1) | ||
| 564 | cpu->CP15[CP15_NORMAL_REGION_REMAP] = value; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | else if (crn == 13 && opcode_1 == 0 && crm == 0) | ||
| 568 | { | ||
| 569 | if (opcode_2 == 0) | ||
| 570 | cpu->CP15[CP15_PID] = value; | ||
| 571 | else if (opcode_2 == 1) | ||
| 572 | cpu->CP15[CP15_CONTEXT_ID] = value; | ||
| 573 | else if (opcode_2 == 3) | ||
| 574 | cpu->CP15[CP15_THREAD_URO] = value; | ||
| 575 | else if (opcode_2 == 4) | ||
| 576 | cpu->CP15[CP15_THREAD_PRW] = value; | ||
| 577 | } | ||
| 578 | else if (crn == 15) | ||
| 579 | { | ||
| 580 | if (opcode_1 == 0 && crm == 12) | ||
| 581 | { | ||
| 582 | if (opcode_2 == 0) | ||
| 583 | cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; | ||
| 584 | else if (opcode_2 == 1) | ||
| 585 | cpu->CP15[CP15_CYCLE_COUNTER] = value; | ||
| 586 | else if (opcode_2 == 2) | ||
| 587 | cpu->CP15[CP15_COUNT_0] = value; | ||
| 588 | else if (opcode_2 == 3) | ||
| 589 | cpu->CP15[CP15_COUNT_1] = value; | ||
| 590 | } | ||
| 591 | else if (opcode_1 == 5) | ||
| 592 | { | ||
| 593 | if (crm == 4) | ||
| 594 | { | ||
| 595 | if (opcode_2 == 2) | ||
| 596 | cpu->CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||
| 597 | else if (opcode_2 == 4) | ||
| 598 | cpu->CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||
| 599 | } | ||
| 600 | else if (crm == 5 && opcode_2 == 2) | ||
| 601 | { | ||
| 602 | cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; | ||
| 603 | } | ||
| 604 | else if (crm == 6 && opcode_2 == 2) | ||
| 605 | { | ||
| 606 | cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; | ||
| 607 | } | ||
| 608 | else if (crm == 7 && opcode_2 == 2) | ||
| 609 | { | ||
| 610 | cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; | ||
| 611 | } | ||
| 612 | } | ||
| 613 | else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||
| 614 | { | ||
| 615 | cpu->CP15[CP15_TLB_DEBUG_CONTROL] = value; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | } | ||
| 619 | |||
| 620 | // Unprivileged registers | ||
| 621 | if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) | ||
| 622 | { | ||
| 623 | cpu->CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; | ||
| 624 | } | ||
| 625 | else if (crn == 7 && opcode_1 == 0 && crm == 10) | ||
| 626 | { | ||
| 627 | if (opcode_2 == 4) | ||
| 628 | cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; | ||
| 629 | else if (opcode_2 == 5) | ||
| 630 | cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; | ||
| 631 | |||
| 632 | } | ||
| 633 | else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) | ||
| 634 | { | ||
| 635 | cpu->CP15[CP15_THREAD_UPRW] = value; | ||
| 636 | } | ||
| 637 | } | ||
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index a92effbb4..d1c721809 100644 --- a/src/core/arm/skyeye_common/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h | |||
| @@ -59,6 +59,8 @@ enum { | |||
| 59 | VFP_FPSID, | 59 | VFP_FPSID, |
| 60 | VFP_FPSCR, | 60 | VFP_FPSCR, |
| 61 | VFP_FPEXC, | 61 | VFP_FPEXC, |
| 62 | VFP_FPINST, | ||
| 63 | VFP_FPINST2, | ||
| 62 | VFP_MVFR0, | 64 | VFP_MVFR0, |
| 63 | VFP_MVFR1, | 65 | VFP_MVFR1, |
| 64 | 66 | ||
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h deleted file mode 100644 index d2c901100..000000000 --- a/src/core/arm/skyeye_common/armdefs.h +++ /dev/null | |||
| @@ -1,318 +0,0 @@ | |||
| 1 | /* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <unordered_map> | ||
| 21 | |||
| 22 | #include "common/common_types.h" | ||
| 23 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 24 | |||
| 25 | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | ||
| 26 | #define BIT(s, n) ((s >> (n)) & 1) | ||
| 27 | |||
| 28 | // Signal levels | ||
| 29 | enum { | ||
| 30 | LOW = 0, | ||
| 31 | HIGH = 1, | ||
| 32 | LOWHIGH = 1, | ||
| 33 | HIGHLOW = 2 | ||
| 34 | }; | ||
| 35 | |||
| 36 | // Cache types | ||
| 37 | enum { | ||
| 38 | NONCACHE = 0, | ||
| 39 | DATACACHE = 1, | ||
| 40 | INSTCACHE = 2, | ||
| 41 | }; | ||
| 42 | |||
| 43 | // Abort models | ||
| 44 | enum { | ||
| 45 | ABORT_BASE_RESTORED = 0, | ||
| 46 | ABORT_EARLY = 1, | ||
| 47 | ABORT_BASE_UPDATED = 2 | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define POS(i) ( (~(i)) >> 31 ) | ||
| 51 | #define NEG(i) ( (i) >> 31 ) | ||
| 52 | |||
| 53 | typedef u64 ARMdword; // must be 64 bits wide | ||
| 54 | typedef u32 ARMword; // must be 32 bits wide | ||
| 55 | typedef u16 ARMhword; // must be 16 bits wide | ||
| 56 | typedef u8 ARMbyte; // must be 8 bits wide | ||
| 57 | |||
| 58 | #define VFP_REG_NUM 64 | ||
| 59 | struct ARMul_State | ||
| 60 | { | ||
| 61 | ARMword Emulate; // To start and stop emulation | ||
| 62 | |||
| 63 | // Order of the following register should not be modified | ||
| 64 | ARMword Reg[16]; // The current register file | ||
| 65 | ARMword Cpsr; // The current PSR | ||
| 66 | ARMword Spsr_copy; | ||
| 67 | ARMword phys_pc; | ||
| 68 | ARMword Reg_usr[2]; | ||
| 69 | ARMword Reg_svc[2]; // R13_SVC R14_SVC | ||
| 70 | ARMword Reg_abort[2]; // R13_ABORT R14_ABORT | ||
| 71 | ARMword Reg_undef[2]; // R13 UNDEF R14 UNDEF | ||
| 72 | ARMword Reg_irq[2]; // R13_IRQ R14_IRQ | ||
| 73 | ARMword Reg_firq[7]; // R8---R14 FIRQ | ||
| 74 | ARMword Spsr[7]; // The exception psr's | ||
| 75 | ARMword Mode; // The current mode | ||
| 76 | ARMword Bank; // The current register bank | ||
| 77 | ARMword exclusive_tag; // The address for which the local monitor is in exclusive access mode | ||
| 78 | ARMword exclusive_state; | ||
| 79 | ARMword exclusive_result; | ||
| 80 | ARMword CP15[CP15_REGISTER_COUNT]; | ||
| 81 | |||
| 82 | // FPSID, FPSCR, and FPEXC | ||
| 83 | ARMword VFP[VFP_SYSTEM_REGISTER_COUNT]; | ||
| 84 | // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). | ||
| 85 | // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), | ||
| 86 | // and only 32 singleword registers are accessible (S0-S31). | ||
| 87 | ARMword ExtReg[VFP_REG_NUM]; | ||
| 88 | /* ---- End of the ordered registers ---- */ | ||
| 89 | |||
| 90 | ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed | ||
| 91 | unsigned int shifter_carry_out; | ||
| 92 | |||
| 93 | // Add armv6 flags dyf:2010-08-09 | ||
| 94 | ARMword GEFlag, EFlag, AFlag, QFlag; | ||
| 95 | |||
| 96 | ARMword TFlag; // Thumb state | ||
| 97 | |||
| 98 | unsigned long long NumInstrs; // The number of instructions executed | ||
| 99 | unsigned NumInstrsToExecute; | ||
| 100 | |||
| 101 | unsigned NresetSig; // Reset the processor | ||
| 102 | unsigned NfiqSig; | ||
| 103 | unsigned NirqSig; | ||
| 104 | |||
| 105 | unsigned abortSig; | ||
| 106 | unsigned NtransSig; | ||
| 107 | unsigned bigendSig; | ||
| 108 | unsigned syscallSig; | ||
| 109 | |||
| 110 | /* 2004-05-09 chy | ||
| 111 | ---------------------------------------------------------- | ||
| 112 | read ARM Architecture Reference Manual | ||
| 113 | 2.6.5 Data Abort | ||
| 114 | There are three Abort Model in ARM arch. | ||
| 115 | |||
| 116 | Early Abort Model: used in some ARMv3 and earlier implementations. In this | ||
| 117 | model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and | ||
| 118 | the base register was unchanged for all other instructions. (oldest) | ||
| 119 | |||
| 120 | Base Restored Abort Model: If a Data Abort occurs in an instruction which | ||
| 121 | specifies base register writeback, the value in the base register is | ||
| 122 | unchanged. (strongarm, xscale) | ||
| 123 | |||
| 124 | Base Updated Abort Model: If a Data Abort occurs in an instruction which | ||
| 125 | specifies base register writeback, the base register writeback still occurs. | ||
| 126 | (arm720T) | ||
| 127 | |||
| 128 | read PART B | ||
| 129 | chap2 The System Control Coprocessor CP15 | ||
| 130 | 2.4 Register1:control register | ||
| 131 | L(bit 6): in some ARMv3 and earlier implementations, the abort model of the | ||
| 132 | processor could be configured: | ||
| 133 | 0=early Abort Model Selected(now obsolete) | ||
| 134 | 1=Late Abort Model selceted(same as Base Updated Abort Model) | ||
| 135 | |||
| 136 | on later processors, this bit reads as 1 and ignores writes. | ||
| 137 | ------------------------------------------------------------- | ||
| 138 | So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) | ||
| 139 | if lateabtSig=0, then it means Base Restored Abort Model | ||
| 140 | */ | ||
| 141 | unsigned lateabtSig; | ||
| 142 | |||
| 143 | // For differentiating ARM core emulaiton. | ||
| 144 | bool is_v4; // Are we emulating a v4 architecture (or higher)? | ||
| 145 | bool is_v5; // Are we emulating a v5 architecture? | ||
| 146 | bool is_v5e; // Are we emulating a v5e architecture? | ||
| 147 | bool is_v6; // Are we emulating a v6 architecture? | ||
| 148 | bool is_v7; // Are we emulating a v7 architecture? | ||
| 149 | |||
| 150 | // ARM_ARM A2-18 | ||
| 151 | // 0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model | ||
| 152 | int abort_model; | ||
| 153 | |||
| 154 | // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per | ||
| 155 | // process for our purposes), not per ARMul_State (which tracks CPU core state). | ||
| 156 | std::unordered_map<u32, int> instruction_cache; | ||
| 157 | }; | ||
| 158 | |||
| 159 | /***************************************************************************\ | ||
| 160 | * Types of ARM we know about * | ||
| 161 | \***************************************************************************/ | ||
| 162 | |||
| 163 | enum { | ||
| 164 | ARM_v4_Prop = 0x01, | ||
| 165 | ARM_v5_Prop = 0x02, | ||
| 166 | ARM_v5e_Prop = 0x04, | ||
| 167 | ARM_v6_Prop = 0x08, | ||
| 168 | ARM_v7_Prop = 0x10, | ||
| 169 | }; | ||
| 170 | |||
| 171 | /***************************************************************************\ | ||
| 172 | * The hardware vector addresses * | ||
| 173 | \***************************************************************************/ | ||
| 174 | |||
| 175 | enum { | ||
| 176 | ARMResetV = 0, | ||
| 177 | ARMUndefinedInstrV = 4, | ||
| 178 | ARMSWIV = 8, | ||
| 179 | ARMPrefetchAbortV = 12, | ||
| 180 | ARMDataAbortV = 16, | ||
| 181 | ARMAddrExceptnV = 20, | ||
| 182 | ARMIRQV = 24, | ||
| 183 | ARMFIQV = 28, | ||
| 184 | ARMErrorV = 32, // This is an offset, not an address! | ||
| 185 | |||
| 186 | ARMul_ResetV = ARMResetV, | ||
| 187 | ARMul_UndefinedInstrV = ARMUndefinedInstrV, | ||
| 188 | ARMul_SWIV = ARMSWIV, | ||
| 189 | ARMul_PrefetchAbortV = ARMPrefetchAbortV, | ||
| 190 | ARMul_DataAbortV = ARMDataAbortV, | ||
| 191 | ARMul_AddrExceptnV = ARMAddrExceptnV, | ||
| 192 | ARMul_IRQV = ARMIRQV, | ||
| 193 | ARMul_FIQV = ARMFIQV | ||
| 194 | }; | ||
| 195 | |||
| 196 | /***************************************************************************\ | ||
| 197 | * Mode and Bank Constants * | ||
| 198 | \***************************************************************************/ | ||
| 199 | |||
| 200 | enum PrivilegeMode { | ||
| 201 | USER32MODE = 16, | ||
| 202 | FIQ32MODE = 17, | ||
| 203 | IRQ32MODE = 18, | ||
| 204 | SVC32MODE = 19, | ||
| 205 | ABORT32MODE = 23, | ||
| 206 | UNDEF32MODE = 27, | ||
| 207 | SYSTEM32MODE = 31 | ||
| 208 | }; | ||
| 209 | |||
| 210 | enum { | ||
| 211 | USERBANK = 0, | ||
| 212 | FIQBANK = 1, | ||
| 213 | IRQBANK = 2, | ||
| 214 | SVCBANK = 3, | ||
| 215 | ABORTBANK = 4, | ||
| 216 | UNDEFBANK = 5, | ||
| 217 | DUMMYBANK = 6, | ||
| 218 | SYSTEMBANK = 7 | ||
| 219 | }; | ||
| 220 | |||
| 221 | /***************************************************************************\ | ||
| 222 | * Definitons of things in the emulator * | ||
| 223 | \***************************************************************************/ | ||
| 224 | extern void ARMul_Reset(ARMul_State* state); | ||
| 225 | extern ARMul_State* ARMul_NewState(ARMul_State* state); | ||
| 226 | |||
| 227 | /***************************************************************************\ | ||
| 228 | * Definitons of things in the co-processor interface * | ||
| 229 | \***************************************************************************/ | ||
| 230 | |||
| 231 | enum { | ||
| 232 | ARMul_FIRST = 0, | ||
| 233 | ARMul_TRANSFER = 1, | ||
| 234 | ARMul_BUSY = 2, | ||
| 235 | ARMul_DATA = 3, | ||
| 236 | ARMul_INTERRUPT = 4, | ||
| 237 | ARMul_DONE = 0, | ||
| 238 | ARMul_CANT = 1, | ||
| 239 | ARMul_INC = 3 | ||
| 240 | }; | ||
| 241 | |||
| 242 | /***************************************************************************\ | ||
| 243 | * Definitons of things in the host environment * | ||
| 244 | \***************************************************************************/ | ||
| 245 | |||
| 246 | enum ConditionCode { | ||
| 247 | EQ = 0, | ||
| 248 | NE = 1, | ||
| 249 | CS = 2, | ||
| 250 | CC = 3, | ||
| 251 | MI = 4, | ||
| 252 | PL = 5, | ||
| 253 | VS = 6, | ||
| 254 | VC = 7, | ||
| 255 | HI = 8, | ||
| 256 | LS = 9, | ||
| 257 | GE = 10, | ||
| 258 | LT = 11, | ||
| 259 | GT = 12, | ||
| 260 | LE = 13, | ||
| 261 | AL = 14, | ||
| 262 | NV = 15, | ||
| 263 | }; | ||
| 264 | |||
| 265 | // Flags for use with the APSR. | ||
| 266 | enum : u32 { | ||
| 267 | NBIT = (1U << 31U), | ||
| 268 | ZBIT = (1 << 30), | ||
| 269 | CBIT = (1 << 29), | ||
| 270 | VBIT = (1 << 28), | ||
| 271 | QBIT = (1 << 27), | ||
| 272 | JBIT = (1 << 24), | ||
| 273 | EBIT = (1 << 9), | ||
| 274 | ABIT = (1 << 8), | ||
| 275 | IBIT = (1 << 7), | ||
| 276 | FBIT = (1 << 6), | ||
| 277 | TBIT = (1 << 5), | ||
| 278 | |||
| 279 | // Masks for groups of bits in the APSR. | ||
| 280 | MODEBITS = 0x1F, | ||
| 281 | INTBITS = 0x1C0, | ||
| 282 | }; | ||
| 283 | |||
| 284 | // Values for Emulate. | ||
| 285 | enum { | ||
| 286 | STOP = 0, // Stop | ||
| 287 | CHANGEMODE = 1, // Change mode | ||
| 288 | ONCE = 2, // Execute just one iteration | ||
| 289 | RUN = 3 // Continuous execution | ||
| 290 | }; | ||
| 291 | |||
| 292 | |||
| 293 | extern bool AddOverflow(ARMword, ARMword, ARMword); | ||
| 294 | extern bool SubOverflow(ARMword, ARMword, ARMword); | ||
| 295 | |||
| 296 | extern void ARMul_SelectProcessor(ARMul_State*, unsigned); | ||
| 297 | |||
| 298 | extern u32 AddWithCarry(u32, u32, u32, bool*, bool*); | ||
| 299 | extern bool ARMul_AddOverflowQ(ARMword, ARMword); | ||
| 300 | |||
| 301 | extern u8 ARMul_SignedSaturatedAdd8(u8, u8); | ||
| 302 | extern u8 ARMul_SignedSaturatedSub8(u8, u8); | ||
| 303 | extern u16 ARMul_SignedSaturatedAdd16(u16, u16); | ||
| 304 | extern u16 ARMul_SignedSaturatedSub16(u16, u16); | ||
| 305 | |||
| 306 | extern u8 ARMul_UnsignedSaturatedAdd8(u8, u8); | ||
| 307 | extern u16 ARMul_UnsignedSaturatedAdd16(u16, u16); | ||
| 308 | extern u8 ARMul_UnsignedSaturatedSub8(u8, u8); | ||
| 309 | extern u16 ARMul_UnsignedSaturatedSub16(u16, u16); | ||
| 310 | extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8); | ||
| 311 | extern u32 ARMul_SignedSatQ(s32, u8, bool*); | ||
| 312 | extern u32 ARMul_UnsignedSatQ(s32, u8, bool*); | ||
| 313 | |||
| 314 | extern bool InBigEndianMode(ARMul_State*); | ||
| 315 | extern bool InAPrivilegedMode(ARMul_State*); | ||
| 316 | |||
| 317 | extern u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); | ||
| 318 | extern void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); | ||
diff --git a/src/core/arm/skyeye_common/armmmu.h b/src/core/arm/skyeye_common/armmmu.h deleted file mode 100644 index c67d7209b..000000000 --- a/src/core/arm/skyeye_common/armmmu.h +++ /dev/null | |||
| @@ -1,103 +0,0 @@ | |||
| 1 | /* | ||
| 2 | armmmu.c - Memory Management Unit emulation. | ||
| 3 | ARMulator extensions for the ARM7100 family. | ||
| 4 | Copyright (C) 1999 Ben Williamson | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #pragma once | ||
| 22 | |||
| 23 | #include "common/swap.h" | ||
| 24 | |||
| 25 | #include "core/memory.h" | ||
| 26 | #include "core/arm/skyeye_common/armdefs.h" | ||
| 27 | |||
| 28 | // Register numbers in the MMU | ||
| 29 | enum | ||
| 30 | { | ||
| 31 | MMU_ID = 0, | ||
| 32 | MMU_CONTROL = 1, | ||
| 33 | MMU_TRANSLATION_TABLE_BASE = 2, | ||
| 34 | MMU_DOMAIN_ACCESS_CONTROL = 3, | ||
| 35 | MMU_FAULT_STATUS = 5, | ||
| 36 | MMU_FAULT_ADDRESS = 6, | ||
| 37 | MMU_CACHE_OPS = 7, | ||
| 38 | MMU_TLB_OPS = 8, | ||
| 39 | MMU_CACHE_LOCKDOWN = 9, | ||
| 40 | MMU_TLB_LOCKDOWN = 10, | ||
| 41 | MMU_PID = 13, | ||
| 42 | |||
| 43 | // MMU_V4 | ||
| 44 | MMU_V4_CACHE_OPS = 7, | ||
| 45 | MMU_V4_TLB_OPS = 8, | ||
| 46 | |||
| 47 | // MMU_V3 | ||
| 48 | MMU_V3_FLUSH_TLB = 5, | ||
| 49 | MMU_V3_FLUSH_TLB_ENTRY = 6, | ||
| 50 | MMU_V3_FLUSH_CACHE = 7, | ||
| 51 | }; | ||
| 52 | |||
| 53 | // Reads data in big/little endian format based on the | ||
| 54 | // state of the E (endian) bit in the emulated CPU's APSR. | ||
| 55 | inline u16 ReadMemory16(ARMul_State* cpu, u32 address) { | ||
| 56 | u16 data = Memory::Read16(address); | ||
| 57 | |||
| 58 | if (InBigEndianMode(cpu)) | ||
| 59 | data = Common::swap16(data); | ||
| 60 | |||
| 61 | return data; | ||
| 62 | } | ||
| 63 | |||
| 64 | inline u32 ReadMemory32(ARMul_State* cpu, u32 address) { | ||
| 65 | u32 data = Memory::Read32(address); | ||
| 66 | |||
| 67 | if (InBigEndianMode(cpu)) | ||
| 68 | data = Common::swap32(data); | ||
| 69 | |||
| 70 | return data; | ||
| 71 | } | ||
| 72 | |||
| 73 | inline u64 ReadMemory64(ARMul_State* cpu, u32 address) { | ||
| 74 | u64 data = Memory::Read64(address); | ||
| 75 | |||
| 76 | if (InBigEndianMode(cpu)) | ||
| 77 | data = Common::swap64(data); | ||
| 78 | |||
| 79 | return data; | ||
| 80 | } | ||
| 81 | |||
| 82 | // Writes data in big/little endian format based on the | ||
| 83 | // state of the E (endian) bit in the emulated CPU's APSR. | ||
| 84 | inline void WriteMemory16(ARMul_State* cpu, u32 address, u16 data) { | ||
| 85 | if (InBigEndianMode(cpu)) | ||
| 86 | data = Common::swap16(data); | ||
| 87 | |||
| 88 | Memory::Write16(address, data); | ||
| 89 | } | ||
| 90 | |||
| 91 | inline void WriteMemory32(ARMul_State* cpu, u32 address, u32 data) { | ||
| 92 | if (InBigEndianMode(cpu)) | ||
| 93 | data = Common::swap32(data); | ||
| 94 | |||
| 95 | Memory::Write32(address, data); | ||
| 96 | } | ||
| 97 | |||
| 98 | inline void WriteMemory64(ARMul_State* cpu, u32 address, u64 data) { | ||
| 99 | if (InBigEndianMode(cpu)) | ||
| 100 | data = Common::swap64(data); | ||
| 101 | |||
| 102 | Memory::Write64(address, data); | ||
| 103 | } | ||
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp new file mode 100644 index 000000000..ccb2eb0eb --- /dev/null +++ b/src/core/arm/skyeye_common/armstate.cpp | |||
| @@ -0,0 +1,657 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/swap.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/mem_map.h" | ||
| 8 | #include "core/memory.h" | ||
| 9 | #include "core/arm/skyeye_common/armstate.h" | ||
| 10 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 11 | |||
| 12 | ARMul_State::ARMul_State(PrivilegeMode initial_mode) | ||
| 13 | { | ||
| 14 | Reset(); | ||
| 15 | ChangePrivilegeMode(initial_mode); | ||
| 16 | } | ||
| 17 | |||
| 18 | void ARMul_State::ChangePrivilegeMode(u32 new_mode) | ||
| 19 | { | ||
| 20 | if (Mode == new_mode) | ||
| 21 | return; | ||
| 22 | |||
| 23 | if (new_mode != USERBANK) { | ||
| 24 | switch (Mode) { | ||
| 25 | case SYSTEM32MODE: // Shares registers with user mode | ||
| 26 | case USER32MODE: | ||
| 27 | Reg_usr[0] = Reg[13]; | ||
| 28 | Reg_usr[1] = Reg[14]; | ||
| 29 | break; | ||
| 30 | case IRQ32MODE: | ||
| 31 | Reg_irq[0] = Reg[13]; | ||
| 32 | Reg_irq[1] = Reg[14]; | ||
| 33 | Spsr[IRQBANK] = Spsr_copy; | ||
| 34 | break; | ||
| 35 | case SVC32MODE: | ||
| 36 | Reg_svc[0] = Reg[13]; | ||
| 37 | Reg_svc[1] = Reg[14]; | ||
| 38 | Spsr[SVCBANK] = Spsr_copy; | ||
| 39 | break; | ||
| 40 | case ABORT32MODE: | ||
| 41 | Reg_abort[0] = Reg[13]; | ||
| 42 | Reg_abort[1] = Reg[14]; | ||
| 43 | Spsr[ABORTBANK] = Spsr_copy; | ||
| 44 | break; | ||
| 45 | case UNDEF32MODE: | ||
| 46 | Reg_undef[0] = Reg[13]; | ||
| 47 | Reg_undef[1] = Reg[14]; | ||
| 48 | Spsr[UNDEFBANK] = Spsr_copy; | ||
| 49 | break; | ||
| 50 | case FIQ32MODE: | ||
| 51 | Reg_firq[0] = Reg[13]; | ||
| 52 | Reg_firq[1] = Reg[14]; | ||
| 53 | Spsr[FIQBANK] = Spsr_copy; | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | |||
| 57 | switch (new_mode) { | ||
| 58 | case USER32MODE: | ||
| 59 | Reg[13] = Reg_usr[0]; | ||
| 60 | Reg[14] = Reg_usr[1]; | ||
| 61 | Bank = USERBANK; | ||
| 62 | break; | ||
| 63 | case IRQ32MODE: | ||
| 64 | Reg[13] = Reg_irq[0]; | ||
| 65 | Reg[14] = Reg_irq[1]; | ||
| 66 | Spsr_copy = Spsr[IRQBANK]; | ||
| 67 | Bank = IRQBANK; | ||
| 68 | break; | ||
| 69 | case SVC32MODE: | ||
| 70 | Reg[13] = Reg_svc[0]; | ||
| 71 | Reg[14] = Reg_svc[1]; | ||
| 72 | Spsr_copy = Spsr[SVCBANK]; | ||
| 73 | Bank = SVCBANK; | ||
| 74 | break; | ||
| 75 | case ABORT32MODE: | ||
| 76 | Reg[13] = Reg_abort[0]; | ||
| 77 | Reg[14] = Reg_abort[1]; | ||
| 78 | Spsr_copy = Spsr[ABORTBANK]; | ||
| 79 | Bank = ABORTBANK; | ||
| 80 | break; | ||
| 81 | case UNDEF32MODE: | ||
| 82 | Reg[13] = Reg_undef[0]; | ||
| 83 | Reg[14] = Reg_undef[1]; | ||
| 84 | Spsr_copy = Spsr[UNDEFBANK]; | ||
| 85 | Bank = UNDEFBANK; | ||
| 86 | break; | ||
| 87 | case FIQ32MODE: | ||
| 88 | Reg[13] = Reg_firq[0]; | ||
| 89 | Reg[14] = Reg_firq[1]; | ||
| 90 | Spsr_copy = Spsr[FIQBANK]; | ||
| 91 | Bank = FIQBANK; | ||
| 92 | break; | ||
| 93 | case SYSTEM32MODE: // Shares registers with user mode. | ||
| 94 | Reg[13] = Reg_usr[0]; | ||
| 95 | Reg[14] = Reg_usr[1]; | ||
| 96 | Bank = SYSTEMBANK; | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | // Set the mode bits in the APSR | ||
| 101 | Cpsr = (Cpsr & ~Mode) | new_mode; | ||
| 102 | Mode = new_mode; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | // Performs a reset | ||
| 107 | void ARMul_State::Reset() | ||
| 108 | { | ||
| 109 | VFPInit(this); | ||
| 110 | |||
| 111 | // Set stack pointer to the top of the stack | ||
| 112 | Reg[13] = 0x10000000; | ||
| 113 | Reg[15] = 0; | ||
| 114 | |||
| 115 | Cpsr = INTBITS | SVC32MODE; | ||
| 116 | Mode = SVC32MODE; | ||
| 117 | Bank = SVCBANK; | ||
| 118 | |||
| 119 | ResetMPCoreCP15Registers(); | ||
| 120 | |||
| 121 | NresetSig = HIGH; | ||
| 122 | NfiqSig = HIGH; | ||
| 123 | NirqSig = HIGH; | ||
| 124 | NtransSig = (Mode & 3) ? HIGH : LOW; | ||
| 125 | abortSig = LOW; | ||
| 126 | |||
| 127 | NumInstrs = 0; | ||
| 128 | Emulate = RUN; | ||
| 129 | } | ||
| 130 | |||
| 131 | // Resets certain MPCore CP15 values to their ARM-defined reset values. | ||
| 132 | void ARMul_State::ResetMPCoreCP15Registers() | ||
| 133 | { | ||
| 134 | // c0 | ||
| 135 | CP15[CP15_MAIN_ID] = 0x410FB024; | ||
| 136 | CP15[CP15_TLB_TYPE] = 0x00000800; | ||
| 137 | CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; | ||
| 138 | CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; | ||
| 139 | CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; | ||
| 140 | CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; | ||
| 141 | CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; | ||
| 142 | CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; | ||
| 143 | CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; | ||
| 144 | CP15[CP15_ISA_FEATURE_0] = 0x00100011; | ||
| 145 | CP15[CP15_ISA_FEATURE_1] = 0x12002111; | ||
| 146 | CP15[CP15_ISA_FEATURE_2] = 0x11221011; | ||
| 147 | CP15[CP15_ISA_FEATURE_3] = 0x01102131; | ||
| 148 | CP15[CP15_ISA_FEATURE_4] = 0x00000141; | ||
| 149 | |||
| 150 | // c1 | ||
| 151 | CP15[CP15_CONTROL] = 0x00054078; | ||
| 152 | CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; | ||
| 153 | CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; | ||
| 154 | |||
| 155 | // c2 | ||
| 156 | CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; | ||
| 157 | CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; | ||
| 158 | CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; | ||
| 159 | |||
| 160 | // c3 | ||
| 161 | CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; | ||
| 162 | |||
| 163 | // c7 | ||
| 164 | CP15[CP15_PHYS_ADDRESS] = 0x00000000; | ||
| 165 | |||
| 166 | // c9 | ||
| 167 | CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; | ||
| 168 | |||
| 169 | // c10 | ||
| 170 | CP15[CP15_TLB_LOCKDOWN] = 0x00000000; | ||
| 171 | CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; | ||
| 172 | CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0; | ||
| 173 | |||
| 174 | // c13 | ||
| 175 | CP15[CP15_PID] = 0x00000000; | ||
| 176 | CP15[CP15_CONTEXT_ID] = 0x00000000; | ||
| 177 | CP15[CP15_THREAD_UPRW] = 0x00000000; | ||
| 178 | CP15[CP15_THREAD_URO] = 0x00000000; | ||
| 179 | CP15[CP15_THREAD_PRW] = 0x00000000; | ||
| 180 | |||
| 181 | // c15 | ||
| 182 | CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000; | ||
| 183 | CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; | ||
| 184 | CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; | ||
| 185 | CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; | ||
| 186 | CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; | ||
| 187 | } | ||
| 188 | |||
| 189 | u16 ARMul_State::ReadMemory16(u32 address) const | ||
| 190 | { | ||
| 191 | u16 data = Memory::Read16(address); | ||
| 192 | |||
| 193 | if (InBigEndianMode()) | ||
| 194 | data = Common::swap16(data); | ||
| 195 | |||
| 196 | return data; | ||
| 197 | } | ||
| 198 | |||
| 199 | u32 ARMul_State::ReadMemory32(u32 address) const | ||
| 200 | { | ||
| 201 | u32 data = Memory::Read32(address); | ||
| 202 | |||
| 203 | if (InBigEndianMode()) | ||
| 204 | data = Common::swap32(data); | ||
| 205 | |||
| 206 | return data; | ||
| 207 | } | ||
| 208 | |||
| 209 | u64 ARMul_State::ReadMemory64(u32 address) const | ||
| 210 | { | ||
| 211 | u64 data = Memory::Read64(address); | ||
| 212 | |||
| 213 | if (InBigEndianMode()) | ||
| 214 | data = Common::swap64(data); | ||
| 215 | |||
| 216 | return data; | ||
| 217 | } | ||
| 218 | |||
| 219 | void ARMul_State::WriteMemory16(u32 address, u16 data) | ||
| 220 | { | ||
| 221 | if (InBigEndianMode()) | ||
| 222 | data = Common::swap16(data); | ||
| 223 | |||
| 224 | Memory::Write16(address, data); | ||
| 225 | } | ||
| 226 | |||
| 227 | void ARMul_State::WriteMemory32(u32 address, u32 data) | ||
| 228 | { | ||
| 229 | if (InBigEndianMode()) | ||
| 230 | data = Common::swap32(data); | ||
| 231 | |||
| 232 | Memory::Write32(address, data); | ||
| 233 | } | ||
| 234 | |||
| 235 | void ARMul_State::WriteMemory64(u32 address, u64 data) | ||
| 236 | { | ||
| 237 | if (InBigEndianMode()) | ||
| 238 | data = Common::swap64(data); | ||
| 239 | |||
| 240 | Memory::Write64(address, data); | ||
| 241 | } | ||
| 242 | |||
| 243 | |||
| 244 | // Reads from the CP15 registers. Used with implementation of the MRC instruction. | ||
| 245 | // Note that since the 3DS does not have the hypervisor extensions, these registers | ||
| 246 | // are not implemented. | ||
| 247 | u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const | ||
| 248 | { | ||
| 249 | // Unprivileged registers | ||
| 250 | if (crn == 13 && opcode_1 == 0 && crm == 0) | ||
| 251 | { | ||
| 252 | if (opcode_2 == 2) | ||
| 253 | return CP15[CP15_THREAD_UPRW]; | ||
| 254 | |||
| 255 | if (opcode_2 == 3) | ||
| 256 | return CP15[CP15_THREAD_URO]; | ||
| 257 | } | ||
| 258 | |||
| 259 | if (InAPrivilegedMode()) | ||
| 260 | { | ||
| 261 | if (crn == 0 && opcode_1 == 0) | ||
| 262 | { | ||
| 263 | if (crm == 0) | ||
| 264 | { | ||
| 265 | if (opcode_2 == 0) | ||
| 266 | return CP15[CP15_MAIN_ID]; | ||
| 267 | |||
| 268 | if (opcode_2 == 1) | ||
| 269 | return CP15[CP15_CACHE_TYPE]; | ||
| 270 | |||
| 271 | if (opcode_2 == 3) | ||
| 272 | return CP15[CP15_TLB_TYPE]; | ||
| 273 | |||
| 274 | if (opcode_2 == 5) | ||
| 275 | return CP15[CP15_CPU_ID]; | ||
| 276 | } | ||
| 277 | else if (crm == 1) | ||
| 278 | { | ||
| 279 | if (opcode_2 == 0) | ||
| 280 | return CP15[CP15_PROCESSOR_FEATURE_0]; | ||
| 281 | |||
| 282 | if (opcode_2 == 1) | ||
| 283 | return CP15[CP15_PROCESSOR_FEATURE_1]; | ||
| 284 | |||
| 285 | if (opcode_2 == 2) | ||
| 286 | return CP15[CP15_DEBUG_FEATURE_0]; | ||
| 287 | |||
| 288 | if (opcode_2 == 4) | ||
| 289 | return CP15[CP15_MEMORY_MODEL_FEATURE_0]; | ||
| 290 | |||
| 291 | if (opcode_2 == 5) | ||
| 292 | return CP15[CP15_MEMORY_MODEL_FEATURE_1]; | ||
| 293 | |||
| 294 | if (opcode_2 == 6) | ||
| 295 | return CP15[CP15_MEMORY_MODEL_FEATURE_2]; | ||
| 296 | |||
| 297 | if (opcode_2 == 7) | ||
| 298 | return CP15[CP15_MEMORY_MODEL_FEATURE_3]; | ||
| 299 | } | ||
| 300 | else if (crm == 2) | ||
| 301 | { | ||
| 302 | if (opcode_2 == 0) | ||
| 303 | return CP15[CP15_ISA_FEATURE_0]; | ||
| 304 | |||
| 305 | if (opcode_2 == 1) | ||
| 306 | return CP15[CP15_ISA_FEATURE_1]; | ||
| 307 | |||
| 308 | if (opcode_2 == 2) | ||
| 309 | return CP15[CP15_ISA_FEATURE_2]; | ||
| 310 | |||
| 311 | if (opcode_2 == 3) | ||
| 312 | return CP15[CP15_ISA_FEATURE_3]; | ||
| 313 | |||
| 314 | if (opcode_2 == 4) | ||
| 315 | return CP15[CP15_ISA_FEATURE_4]; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | if (crn == 1 && opcode_1 == 0 && crm == 0) | ||
| 320 | { | ||
| 321 | if (opcode_2 == 0) | ||
| 322 | return CP15[CP15_CONTROL]; | ||
| 323 | |||
| 324 | if (opcode_2 == 1) | ||
| 325 | return CP15[CP15_AUXILIARY_CONTROL]; | ||
| 326 | |||
| 327 | if (opcode_2 == 2) | ||
| 328 | return CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; | ||
| 329 | } | ||
| 330 | |||
| 331 | if (crn == 2 && opcode_1 == 0 && crm == 0) | ||
| 332 | { | ||
| 333 | if (opcode_2 == 0) | ||
| 334 | return CP15[CP15_TRANSLATION_BASE_TABLE_0]; | ||
| 335 | |||
| 336 | if (opcode_2 == 1) | ||
| 337 | return CP15[CP15_TRANSLATION_BASE_TABLE_1]; | ||
| 338 | |||
| 339 | if (opcode_2 == 2) | ||
| 340 | return CP15[CP15_TRANSLATION_BASE_CONTROL]; | ||
| 341 | } | ||
| 342 | |||
| 343 | if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 344 | return CP15[CP15_DOMAIN_ACCESS_CONTROL]; | ||
| 345 | |||
| 346 | if (crn == 5 && opcode_1 == 0 && crm == 0) | ||
| 347 | { | ||
| 348 | if (opcode_2 == 0) | ||
| 349 | return CP15[CP15_FAULT_STATUS]; | ||
| 350 | |||
| 351 | if (opcode_2 == 1) | ||
| 352 | return CP15[CP15_INSTR_FAULT_STATUS]; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (crn == 6 && opcode_1 == 0 && crm == 0) | ||
| 356 | { | ||
| 357 | if (opcode_2 == 0) | ||
| 358 | return CP15[CP15_FAULT_ADDRESS]; | ||
| 359 | |||
| 360 | if (opcode_2 == 1) | ||
| 361 | return CP15[CP15_WFAR]; | ||
| 362 | } | ||
| 363 | |||
| 364 | if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) | ||
| 365 | return CP15[CP15_PHYS_ADDRESS]; | ||
| 366 | |||
| 367 | if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 368 | return CP15[CP15_DATA_CACHE_LOCKDOWN]; | ||
| 369 | |||
| 370 | if (crn == 10 && opcode_1 == 0) | ||
| 371 | { | ||
| 372 | if (crm == 0 && opcode_2 == 0) | ||
| 373 | return CP15[CP15_TLB_LOCKDOWN]; | ||
| 374 | |||
| 375 | if (crm == 2) | ||
| 376 | { | ||
| 377 | if (opcode_2 == 0) | ||
| 378 | return CP15[CP15_PRIMARY_REGION_REMAP]; | ||
| 379 | |||
| 380 | if (opcode_2 == 1) | ||
| 381 | return CP15[CP15_NORMAL_REGION_REMAP]; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | if (crn == 13 && crm == 0) | ||
| 386 | { | ||
| 387 | if (opcode_2 == 0) | ||
| 388 | return CP15[CP15_PID]; | ||
| 389 | |||
| 390 | if (opcode_2 == 1) | ||
| 391 | return CP15[CP15_CONTEXT_ID]; | ||
| 392 | |||
| 393 | if (opcode_2 == 4) | ||
| 394 | return CP15[CP15_THREAD_PRW]; | ||
| 395 | } | ||
| 396 | |||
| 397 | if (crn == 15) | ||
| 398 | { | ||
| 399 | if (opcode_1 == 0 && crm == 12) | ||
| 400 | { | ||
| 401 | if (opcode_2 == 0) | ||
| 402 | return CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; | ||
| 403 | |||
| 404 | if (opcode_2 == 1) | ||
| 405 | return CP15[CP15_CYCLE_COUNTER]; | ||
| 406 | |||
| 407 | if (opcode_2 == 2) | ||
| 408 | return CP15[CP15_COUNT_0]; | ||
| 409 | |||
| 410 | if (opcode_2 == 3) | ||
| 411 | return CP15[CP15_COUNT_1]; | ||
| 412 | } | ||
| 413 | |||
| 414 | if (opcode_1 == 5 && opcode_2 == 2) | ||
| 415 | { | ||
| 416 | if (crm == 5) | ||
| 417 | return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; | ||
| 418 | |||
| 419 | if (crm == 6) | ||
| 420 | return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; | ||
| 421 | |||
| 422 | if (crm == 7) | ||
| 423 | return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; | ||
| 424 | } | ||
| 425 | |||
| 426 | if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||
| 427 | return CP15[CP15_TLB_DEBUG_CONTROL]; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2); | ||
| 432 | return 0; | ||
| 433 | } | ||
| 434 | |||
| 435 | // Write to the CP15 registers. Used with implementation of the MCR instruction. | ||
| 436 | // Note that since the 3DS does not have the hypervisor extensions, these registers | ||
| 437 | // are not implemented. | ||
| 438 | void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) | ||
| 439 | { | ||
| 440 | if (InAPrivilegedMode()) | ||
| 441 | { | ||
| 442 | if (crn == 1 && opcode_1 == 0 && crm == 0) | ||
| 443 | { | ||
| 444 | if (opcode_2 == 0) | ||
| 445 | CP15[CP15_CONTROL] = value; | ||
| 446 | else if (opcode_2 == 1) | ||
| 447 | CP15[CP15_AUXILIARY_CONTROL] = value; | ||
| 448 | else if (opcode_2 == 2) | ||
| 449 | CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; | ||
| 450 | } | ||
| 451 | else if (crn == 2 && opcode_1 == 0 && crm == 0) | ||
| 452 | { | ||
| 453 | if (opcode_2 == 0) | ||
| 454 | CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; | ||
| 455 | else if (opcode_2 == 1) | ||
| 456 | CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; | ||
| 457 | else if (opcode_2 == 2) | ||
| 458 | CP15[CP15_TRANSLATION_BASE_CONTROL] = value; | ||
| 459 | } | ||
| 460 | else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 461 | { | ||
| 462 | CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; | ||
| 463 | } | ||
| 464 | else if (crn == 5 && opcode_1 == 0 && crm == 0) | ||
| 465 | { | ||
| 466 | if (opcode_2 == 0) | ||
| 467 | CP15[CP15_FAULT_STATUS] = value; | ||
| 468 | else if (opcode_2 == 1) | ||
| 469 | CP15[CP15_INSTR_FAULT_STATUS] = value; | ||
| 470 | } | ||
| 471 | else if (crn == 6 && opcode_1 == 0 && crm == 0) | ||
| 472 | { | ||
| 473 | if (opcode_2 == 0) | ||
| 474 | CP15[CP15_FAULT_ADDRESS] = value; | ||
| 475 | else if (opcode_2 == 1) | ||
| 476 | CP15[CP15_WFAR] = value; | ||
| 477 | } | ||
| 478 | else if (crn == 7 && opcode_1 == 0) | ||
| 479 | { | ||
| 480 | if (crm == 0 && opcode_2 == 4) | ||
| 481 | { | ||
| 482 | CP15[CP15_WAIT_FOR_INTERRUPT] = value; | ||
| 483 | } | ||
| 484 | else if (crm == 4 && opcode_2 == 0) | ||
| 485 | { | ||
| 486 | // NOTE: Not entirely accurate. This should do permission checks. | ||
| 487 | CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); | ||
| 488 | } | ||
| 489 | else if (crm == 5) | ||
| 490 | { | ||
| 491 | if (opcode_2 == 0) | ||
| 492 | CP15[CP15_INVALIDATE_INSTR_CACHE] = value; | ||
| 493 | else if (opcode_2 == 1) | ||
| 494 | CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; | ||
| 495 | else if (opcode_2 == 2) | ||
| 496 | CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; | ||
| 497 | else if (opcode_2 == 6) | ||
| 498 | CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; | ||
| 499 | else if (opcode_2 == 7) | ||
| 500 | CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; | ||
| 501 | } | ||
| 502 | else if (crm == 6) | ||
| 503 | { | ||
| 504 | if (opcode_2 == 0) | ||
| 505 | CP15[CP15_INVALIDATE_DATA_CACHE] = value; | ||
| 506 | else if (opcode_2 == 1) | ||
| 507 | CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 508 | else if (opcode_2 == 2) | ||
| 509 | CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 510 | } | ||
| 511 | else if (crm == 7 && opcode_2 == 0) | ||
| 512 | { | ||
| 513 | CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; | ||
| 514 | } | ||
| 515 | else if (crm == 10) | ||
| 516 | { | ||
| 517 | if (opcode_2 == 0) | ||
| 518 | CP15[CP15_CLEAN_DATA_CACHE] = value; | ||
| 519 | else if (opcode_2 == 1) | ||
| 520 | CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 521 | else if (opcode_2 == 2) | ||
| 522 | CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 523 | } | ||
| 524 | else if (crm == 14) | ||
| 525 | { | ||
| 526 | if (opcode_2 == 0) | ||
| 527 | CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; | ||
| 528 | else if (opcode_2 == 1) | ||
| 529 | CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 530 | else if (opcode_2 == 2) | ||
| 531 | CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 532 | } | ||
| 533 | } | ||
| 534 | else if (crn == 8 && opcode_1 == 0) | ||
| 535 | { | ||
| 536 | if (crm == 5) | ||
| 537 | { | ||
| 538 | if (opcode_2 == 0) | ||
| 539 | CP15[CP15_INVALIDATE_ITLB] = value; | ||
| 540 | else if (opcode_2 == 1) | ||
| 541 | CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; | ||
| 542 | else if (opcode_2 == 2) | ||
| 543 | CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 544 | else if (opcode_2 == 3) | ||
| 545 | CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; | ||
| 546 | } | ||
| 547 | else if (crm == 6) | ||
| 548 | { | ||
| 549 | if (opcode_2 == 0) | ||
| 550 | CP15[CP15_INVALIDATE_DTLB] = value; | ||
| 551 | else if (opcode_2 == 1) | ||
| 552 | CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; | ||
| 553 | else if (opcode_2 == 2) | ||
| 554 | CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 555 | else if (opcode_2 == 3) | ||
| 556 | CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; | ||
| 557 | } | ||
| 558 | else if (crm == 7) | ||
| 559 | { | ||
| 560 | if (opcode_2 == 0) | ||
| 561 | CP15[CP15_INVALIDATE_UTLB] = value; | ||
| 562 | else if (opcode_2 == 1) | ||
| 563 | CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; | ||
| 564 | else if (opcode_2 == 2) | ||
| 565 | CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 566 | else if (opcode_2 == 3) | ||
| 567 | CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 571 | { | ||
| 572 | CP15[CP15_DATA_CACHE_LOCKDOWN] = value; | ||
| 573 | } | ||
| 574 | else if (crn == 10 && opcode_1 == 0) | ||
| 575 | { | ||
| 576 | if (crm == 0 && opcode_2 == 0) | ||
| 577 | { | ||
| 578 | CP15[CP15_TLB_LOCKDOWN] = value; | ||
| 579 | } | ||
| 580 | else if (crm == 2) | ||
| 581 | { | ||
| 582 | if (opcode_2 == 0) | ||
| 583 | CP15[CP15_PRIMARY_REGION_REMAP] = value; | ||
| 584 | else if (opcode_2 == 1) | ||
| 585 | CP15[CP15_NORMAL_REGION_REMAP] = value; | ||
| 586 | } | ||
| 587 | } | ||
| 588 | else if (crn == 13 && opcode_1 == 0 && crm == 0) | ||
| 589 | { | ||
| 590 | if (opcode_2 == 0) | ||
| 591 | CP15[CP15_PID] = value; | ||
| 592 | else if (opcode_2 == 1) | ||
| 593 | CP15[CP15_CONTEXT_ID] = value; | ||
| 594 | else if (opcode_2 == 3) | ||
| 595 | CP15[CP15_THREAD_URO] = value; | ||
| 596 | else if (opcode_2 == 4) | ||
| 597 | CP15[CP15_THREAD_PRW] = value; | ||
| 598 | } | ||
| 599 | else if (crn == 15) | ||
| 600 | { | ||
| 601 | if (opcode_1 == 0 && crm == 12) | ||
| 602 | { | ||
| 603 | if (opcode_2 == 0) | ||
| 604 | CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; | ||
| 605 | else if (opcode_2 == 1) | ||
| 606 | CP15[CP15_CYCLE_COUNTER] = value; | ||
| 607 | else if (opcode_2 == 2) | ||
| 608 | CP15[CP15_COUNT_0] = value; | ||
| 609 | else if (opcode_2 == 3) | ||
| 610 | CP15[CP15_COUNT_1] = value; | ||
| 611 | } | ||
| 612 | else if (opcode_1 == 5) | ||
| 613 | { | ||
| 614 | if (crm == 4) | ||
| 615 | { | ||
| 616 | if (opcode_2 == 2) | ||
| 617 | CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||
| 618 | else if (opcode_2 == 4) | ||
| 619 | CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||
| 620 | } | ||
| 621 | else if (crm == 5 && opcode_2 == 2) | ||
| 622 | { | ||
| 623 | CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; | ||
| 624 | } | ||
| 625 | else if (crm == 6 && opcode_2 == 2) | ||
| 626 | { | ||
| 627 | CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; | ||
| 628 | } | ||
| 629 | else if (crm == 7 && opcode_2 == 2) | ||
| 630 | { | ||
| 631 | CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; | ||
| 632 | } | ||
| 633 | } | ||
| 634 | else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||
| 635 | { | ||
| 636 | CP15[CP15_TLB_DEBUG_CONTROL] = value; | ||
| 637 | } | ||
| 638 | } | ||
| 639 | } | ||
| 640 | |||
| 641 | // Unprivileged registers | ||
| 642 | if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) | ||
| 643 | { | ||
| 644 | CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; | ||
| 645 | } | ||
| 646 | else if (crn == 7 && opcode_1 == 0 && crm == 10) | ||
| 647 | { | ||
| 648 | if (opcode_2 == 4) | ||
| 649 | CP15[CP15_DATA_SYNC_BARRIER] = value; | ||
| 650 | else if (opcode_2 == 5) | ||
| 651 | CP15[CP15_DATA_MEMORY_BARRIER] = value; | ||
| 652 | } | ||
| 653 | else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) | ||
| 654 | { | ||
| 655 | CP15[CP15_THREAD_UPRW] = value; | ||
| 656 | } | ||
| 657 | } | ||
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h new file mode 100644 index 000000000..b364e2621 --- /dev/null +++ b/src/core/arm/skyeye_common/armstate.h | |||
| @@ -0,0 +1,252 @@ | |||
| 1 | /* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <array> | ||
| 21 | #include <unordered_map> | ||
| 22 | |||
| 23 | #include "common/common_types.h" | ||
| 24 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 25 | |||
| 26 | // Signal levels | ||
| 27 | enum { | ||
| 28 | LOW = 0, | ||
| 29 | HIGH = 1, | ||
| 30 | LOWHIGH = 1, | ||
| 31 | HIGHLOW = 2 | ||
| 32 | }; | ||
| 33 | |||
| 34 | // Cache types | ||
| 35 | enum { | ||
| 36 | NONCACHE = 0, | ||
| 37 | DATACACHE = 1, | ||
| 38 | INSTCACHE = 2, | ||
| 39 | }; | ||
| 40 | |||
| 41 | // ARM privilege modes | ||
| 42 | enum PrivilegeMode { | ||
| 43 | USER32MODE = 16, | ||
| 44 | FIQ32MODE = 17, | ||
| 45 | IRQ32MODE = 18, | ||
| 46 | SVC32MODE = 19, | ||
| 47 | ABORT32MODE = 23, | ||
| 48 | UNDEF32MODE = 27, | ||
| 49 | SYSTEM32MODE = 31 | ||
| 50 | }; | ||
| 51 | |||
| 52 | // ARM privilege mode register banks | ||
| 53 | enum { | ||
| 54 | USERBANK = 0, | ||
| 55 | FIQBANK = 1, | ||
| 56 | IRQBANK = 2, | ||
| 57 | SVCBANK = 3, | ||
| 58 | ABORTBANK = 4, | ||
| 59 | UNDEFBANK = 5, | ||
| 60 | DUMMYBANK = 6, | ||
| 61 | SYSTEMBANK = 7 | ||
| 62 | }; | ||
| 63 | |||
| 64 | // Hardware vector addresses | ||
| 65 | enum { | ||
| 66 | ARMResetV = 0, | ||
| 67 | ARMUndefinedInstrV = 4, | ||
| 68 | ARMSWIV = 8, | ||
| 69 | ARMPrefetchAbortV = 12, | ||
| 70 | ARMDataAbortV = 16, | ||
| 71 | ARMAddrExceptnV = 20, | ||
| 72 | ARMIRQV = 24, | ||
| 73 | ARMFIQV = 28, | ||
| 74 | ARMErrorV = 32, // This is an offset, not an address! | ||
| 75 | |||
| 76 | ARMul_ResetV = ARMResetV, | ||
| 77 | ARMul_UndefinedInstrV = ARMUndefinedInstrV, | ||
| 78 | ARMul_SWIV = ARMSWIV, | ||
| 79 | ARMul_PrefetchAbortV = ARMPrefetchAbortV, | ||
| 80 | ARMul_DataAbortV = ARMDataAbortV, | ||
| 81 | ARMul_AddrExceptnV = ARMAddrExceptnV, | ||
| 82 | ARMul_IRQV = ARMIRQV, | ||
| 83 | ARMul_FIQV = ARMFIQV | ||
| 84 | }; | ||
| 85 | |||
| 86 | // Coprocessor status values | ||
| 87 | enum { | ||
| 88 | ARMul_FIRST = 0, | ||
| 89 | ARMul_TRANSFER = 1, | ||
| 90 | ARMul_BUSY = 2, | ||
| 91 | ARMul_DATA = 3, | ||
| 92 | ARMul_INTERRUPT = 4, | ||
| 93 | ARMul_DONE = 0, | ||
| 94 | ARMul_CANT = 1, | ||
| 95 | ARMul_INC = 3 | ||
| 96 | }; | ||
| 97 | |||
| 98 | // Instruction condition codes | ||
| 99 | enum ConditionCode { | ||
| 100 | EQ = 0, | ||
| 101 | NE = 1, | ||
| 102 | CS = 2, | ||
| 103 | CC = 3, | ||
| 104 | MI = 4, | ||
| 105 | PL = 5, | ||
| 106 | VS = 6, | ||
| 107 | VC = 7, | ||
| 108 | HI = 8, | ||
| 109 | LS = 9, | ||
| 110 | GE = 10, | ||
| 111 | LT = 11, | ||
| 112 | GT = 12, | ||
| 113 | LE = 13, | ||
| 114 | AL = 14, | ||
| 115 | NV = 15, | ||
| 116 | }; | ||
| 117 | |||
| 118 | // Flags for use with the APSR. | ||
| 119 | enum : u32 { | ||
| 120 | NBIT = (1U << 31U), | ||
| 121 | ZBIT = (1 << 30), | ||
| 122 | CBIT = (1 << 29), | ||
| 123 | VBIT = (1 << 28), | ||
| 124 | QBIT = (1 << 27), | ||
| 125 | JBIT = (1 << 24), | ||
| 126 | EBIT = (1 << 9), | ||
| 127 | ABIT = (1 << 8), | ||
| 128 | IBIT = (1 << 7), | ||
| 129 | FBIT = (1 << 6), | ||
| 130 | TBIT = (1 << 5), | ||
| 131 | |||
| 132 | // Masks for groups of bits in the APSR. | ||
| 133 | MODEBITS = 0x1F, | ||
| 134 | INTBITS = 0x1C0, | ||
| 135 | }; | ||
| 136 | |||
| 137 | // Values for Emulate. | ||
| 138 | enum { | ||
| 139 | STOP = 0, // Stop | ||
| 140 | CHANGEMODE = 1, // Change mode | ||
| 141 | ONCE = 2, // Execute just one iteration | ||
| 142 | RUN = 3 // Continuous execution | ||
| 143 | }; | ||
| 144 | |||
| 145 | |||
| 146 | struct ARMul_State final | ||
| 147 | { | ||
| 148 | public: | ||
| 149 | explicit ARMul_State(PrivilegeMode initial_mode); | ||
| 150 | |||
| 151 | void ChangePrivilegeMode(u32 new_mode); | ||
| 152 | void Reset(); | ||
| 153 | |||
| 154 | // Reads/writes data in big/little endian format based on the | ||
| 155 | // state of the E (endian) bit in the APSR. | ||
| 156 | u16 ReadMemory16(u32 address) const; | ||
| 157 | u32 ReadMemory32(u32 address) const; | ||
| 158 | u64 ReadMemory64(u32 address) const; | ||
| 159 | void WriteMemory16(u32 address, u16 data); | ||
| 160 | void WriteMemory32(u32 address, u32 data); | ||
| 161 | void WriteMemory64(u32 address, u64 data); | ||
| 162 | |||
| 163 | u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; | ||
| 164 | void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); | ||
| 165 | |||
| 166 | // Exclusive memory access functions | ||
| 167 | bool IsExclusiveMemoryAccess(u32 address) const { | ||
| 168 | return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK); | ||
| 169 | } | ||
| 170 | void SetExclusiveMemoryAddress(u32 address) { | ||
| 171 | exclusive_tag = address & RESERVATION_GRANULE_MASK; | ||
| 172 | exclusive_state = true; | ||
| 173 | } | ||
| 174 | void UnsetExclusiveMemoryAddress() { | ||
| 175 | exclusive_tag = 0xFFFFFFFF; | ||
| 176 | exclusive_state = false; | ||
| 177 | } | ||
| 178 | |||
| 179 | // Whether or not the given CPU is in big endian mode (E bit is set) | ||
| 180 | bool InBigEndianMode() const { | ||
| 181 | return (Cpsr & (1 << 9)) != 0; | ||
| 182 | } | ||
| 183 | // Whether or not the given CPU is in a mode other than user mode. | ||
| 184 | bool InAPrivilegedMode() const { | ||
| 185 | return (Mode != USER32MODE); | ||
| 186 | } | ||
| 187 | // Note that for the 3DS, a Thumb instruction will only ever be | ||
| 188 | // two bytes in size. Thus we don't need to worry about ThumbEE | ||
| 189 | // or Thumb-2 where instructions can be 4 bytes in length. | ||
| 190 | u32 GetInstructionSize() const { | ||
| 191 | return TFlag ? 2 : 4; | ||
| 192 | } | ||
| 193 | |||
| 194 | std::array<u32, 16> Reg; // The current register file | ||
| 195 | std::array<u32, 2> Reg_usr; | ||
| 196 | std::array<u32, 2> Reg_svc; // R13_SVC R14_SVC | ||
| 197 | std::array<u32, 2> Reg_abort; // R13_ABORT R14_ABORT | ||
| 198 | std::array<u32, 2> Reg_undef; // R13 UNDEF R14 UNDEF | ||
| 199 | std::array<u32, 2> Reg_irq; // R13_IRQ R14_IRQ | ||
| 200 | std::array<u32, 7> Reg_firq; // R8---R14 FIRQ | ||
| 201 | std::array<u32, 7> Spsr; // The exception psr's | ||
| 202 | std::array<u32, CP15_REGISTER_COUNT> CP15; | ||
| 203 | |||
| 204 | // FPSID, FPSCR, and FPEXC | ||
| 205 | std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP; | ||
| 206 | |||
| 207 | // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). | ||
| 208 | // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), | ||
| 209 | // and only 32 singleword registers are accessible (S0-S31). | ||
| 210 | std::array<u32, 64> ExtReg; | ||
| 211 | |||
| 212 | u32 Emulate; // To start and stop emulation | ||
| 213 | u32 Cpsr; // The current PSR | ||
| 214 | u32 Spsr_copy; | ||
| 215 | u32 phys_pc; | ||
| 216 | |||
| 217 | u32 Mode; // The current mode | ||
| 218 | u32 Bank; // The current register bank | ||
| 219 | |||
| 220 | u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed | ||
| 221 | unsigned int shifter_carry_out; | ||
| 222 | |||
| 223 | u32 TFlag; // Thumb state | ||
| 224 | |||
| 225 | unsigned long long NumInstrs; // The number of instructions executed | ||
| 226 | unsigned NumInstrsToExecute; | ||
| 227 | |||
| 228 | unsigned NresetSig; // Reset the processor | ||
| 229 | unsigned NfiqSig; | ||
| 230 | unsigned NirqSig; | ||
| 231 | |||
| 232 | unsigned abortSig; | ||
| 233 | unsigned NtransSig; | ||
| 234 | unsigned bigendSig; | ||
| 235 | unsigned syscallSig; | ||
| 236 | |||
| 237 | // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per | ||
| 238 | // process for our purposes), not per ARMul_State (which tracks CPU core state). | ||
| 239 | std::unordered_map<u32, int> instruction_cache; | ||
| 240 | |||
| 241 | private: | ||
| 242 | void ResetMPCoreCP15Registers(); | ||
| 243 | |||
| 244 | // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag. | ||
| 245 | // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to | ||
| 246 | // support LDR/STREXD. | ||
| 247 | static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; | ||
| 248 | |||
| 249 | u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode | ||
| 250 | u32 exclusive_result; | ||
| 251 | bool exclusive_state; | ||
| 252 | }; | ||
diff --git a/src/core/arm/skyeye_common/armsupp.cpp b/src/core/arm/skyeye_common/armsupp.cpp new file mode 100644 index 000000000..d31fb9449 --- /dev/null +++ b/src/core/arm/skyeye_common/armsupp.cpp | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #include "common/logging/log.h" | ||
| 19 | |||
| 20 | #include "core/mem_map.h" | ||
| 21 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 22 | #include "core/arm/skyeye_common/armstate.h" | ||
| 23 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 24 | |||
| 25 | // Unsigned sum of absolute difference | ||
| 26 | u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) | ||
| 27 | { | ||
| 28 | if (left > right) | ||
| 29 | return left - right; | ||
| 30 | |||
| 31 | return right - left; | ||
| 32 | } | ||
| 33 | |||
| 34 | // Add with carry, indicates if a carry-out or signed overflow occurred. | ||
| 35 | u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred) | ||
| 36 | { | ||
| 37 | u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in; | ||
| 38 | s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in; | ||
| 39 | u64 result = (unsigned_sum & 0xFFFFFFFF); | ||
| 40 | |||
| 41 | if (carry_out_occurred) | ||
| 42 | *carry_out_occurred = (result != unsigned_sum); | ||
| 43 | |||
| 44 | if (overflow_occurred) | ||
| 45 | *overflow_occurred = ((s64)(s32)result != signed_sum); | ||
| 46 | |||
| 47 | return (u32)result; | ||
| 48 | } | ||
| 49 | |||
| 50 | // Compute whether an addition of A and B, giving RESULT, overflowed. | ||
| 51 | bool AddOverflow(u32 a, u32 b, u32 result) | ||
| 52 | { | ||
| 53 | return ((NEG(a) && NEG(b) && POS(result)) || | ||
| 54 | (POS(a) && POS(b) && NEG(result))); | ||
| 55 | } | ||
| 56 | |||
| 57 | // Compute whether a subtraction of A and B, giving RESULT, overflowed. | ||
| 58 | bool SubOverflow(u32 a, u32 b, u32 result) | ||
| 59 | { | ||
| 60 | return ((NEG(a) && POS(b) && POS(result)) || | ||
| 61 | (POS(a) && NEG(b) && NEG(result))); | ||
| 62 | } | ||
| 63 | |||
| 64 | // Returns true if the Q flag should be set as a result of overflow. | ||
| 65 | bool ARMul_AddOverflowQ(u32 a, u32 b) | ||
| 66 | { | ||
| 67 | u32 result = a + b; | ||
| 68 | if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0) | ||
| 69 | return true; | ||
| 70 | |||
| 71 | return false; | ||
| 72 | } | ||
| 73 | |||
| 74 | // 8-bit signed saturated addition | ||
| 75 | u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) | ||
| 76 | { | ||
| 77 | u8 result = left + right; | ||
| 78 | |||
| 79 | if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) { | ||
| 80 | if (left & 0x80) | ||
| 81 | result = 0x80; | ||
| 82 | else | ||
| 83 | result = 0x7F; | ||
| 84 | } | ||
| 85 | |||
| 86 | return result; | ||
| 87 | } | ||
| 88 | |||
| 89 | // 8-bit signed saturated subtraction | ||
| 90 | u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) | ||
| 91 | { | ||
| 92 | u8 result = left - right; | ||
| 93 | |||
| 94 | if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) { | ||
| 95 | if (left & 0x80) | ||
| 96 | result = 0x80; | ||
| 97 | else | ||
| 98 | result = 0x7F; | ||
| 99 | } | ||
| 100 | |||
| 101 | return result; | ||
| 102 | } | ||
| 103 | |||
| 104 | // 16-bit signed saturated addition | ||
| 105 | u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) | ||
| 106 | { | ||
| 107 | u16 result = left + right; | ||
| 108 | |||
| 109 | if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) { | ||
| 110 | if (left & 0x8000) | ||
| 111 | result = 0x8000; | ||
| 112 | else | ||
| 113 | result = 0x7FFF; | ||
| 114 | } | ||
| 115 | |||
| 116 | return result; | ||
| 117 | } | ||
| 118 | |||
| 119 | // 16-bit signed saturated subtraction | ||
| 120 | u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) | ||
| 121 | { | ||
| 122 | u16 result = left - right; | ||
| 123 | |||
| 124 | if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) { | ||
| 125 | if (left & 0x8000) | ||
| 126 | result = 0x8000; | ||
| 127 | else | ||
| 128 | result = 0x7FFF; | ||
| 129 | } | ||
| 130 | |||
| 131 | return result; | ||
| 132 | } | ||
| 133 | |||
| 134 | // 8-bit unsigned saturated addition | ||
| 135 | u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) | ||
| 136 | { | ||
| 137 | u8 result = left + right; | ||
| 138 | |||
| 139 | if (result < left) | ||
| 140 | result = 0xFF; | ||
| 141 | |||
| 142 | return result; | ||
| 143 | } | ||
| 144 | |||
| 145 | // 16-bit unsigned saturated addition | ||
| 146 | u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) | ||
| 147 | { | ||
| 148 | u16 result = left + right; | ||
| 149 | |||
| 150 | if (result < left) | ||
| 151 | result = 0xFFFF; | ||
| 152 | |||
| 153 | return result; | ||
| 154 | } | ||
| 155 | |||
| 156 | // 8-bit unsigned saturated subtraction | ||
| 157 | u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) | ||
| 158 | { | ||
| 159 | if (left <= right) | ||
| 160 | return 0; | ||
| 161 | |||
| 162 | return left - right; | ||
| 163 | } | ||
| 164 | |||
| 165 | // 16-bit unsigned saturated subtraction | ||
| 166 | u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) | ||
| 167 | { | ||
| 168 | if (left <= right) | ||
| 169 | return 0; | ||
| 170 | |||
| 171 | return left - right; | ||
| 172 | } | ||
| 173 | |||
| 174 | // Signed saturation. | ||
| 175 | u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||
| 176 | { | ||
| 177 | const u32 max = (1 << shift) - 1; | ||
| 178 | const s32 top = (value >> shift); | ||
| 179 | |||
| 180 | if (top > 0) { | ||
| 181 | *saturation_occurred = true; | ||
| 182 | return max; | ||
| 183 | } | ||
| 184 | else if (top < -1) { | ||
| 185 | *saturation_occurred = true; | ||
| 186 | return ~max; | ||
| 187 | } | ||
| 188 | |||
| 189 | *saturation_occurred = false; | ||
| 190 | return (u32)value; | ||
| 191 | } | ||
| 192 | |||
| 193 | // Unsigned saturation | ||
| 194 | u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) | ||
| 195 | { | ||
| 196 | const u32 max = (1 << shift) - 1; | ||
| 197 | |||
| 198 | if (value < 0) { | ||
| 199 | *saturation_occurred = true; | ||
| 200 | return 0; | ||
| 201 | } else if ((u32)value > max) { | ||
| 202 | *saturation_occurred = true; | ||
| 203 | return max; | ||
| 204 | } | ||
| 205 | |||
| 206 | *saturation_occurred = false; | ||
| 207 | return (u32)value; | ||
| 208 | } | ||
diff --git a/src/core/arm/skyeye_common/armsupp.h b/src/core/arm/skyeye_common/armsupp.h new file mode 100644 index 000000000..391309fa8 --- /dev/null +++ b/src/core/arm/skyeye_common/armsupp.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | ||
| 10 | #define BIT(s, n) ((s >> (n)) & 1) | ||
| 11 | |||
| 12 | #define POS(i) ( (~(i)) >> 31 ) | ||
| 13 | #define NEG(i) ( (i) >> 31 ) | ||
| 14 | |||
| 15 | bool AddOverflow(u32, u32, u32); | ||
| 16 | bool SubOverflow(u32, u32, u32); | ||
| 17 | |||
| 18 | u32 AddWithCarry(u32, u32, u32, bool*, bool*); | ||
| 19 | bool ARMul_AddOverflowQ(u32, u32); | ||
| 20 | |||
| 21 | u8 ARMul_SignedSaturatedAdd8(u8, u8); | ||
| 22 | u8 ARMul_SignedSaturatedSub8(u8, u8); | ||
| 23 | u16 ARMul_SignedSaturatedAdd16(u16, u16); | ||
| 24 | u16 ARMul_SignedSaturatedSub16(u16, u16); | ||
| 25 | |||
| 26 | u8 ARMul_UnsignedSaturatedAdd8(u8, u8); | ||
| 27 | u16 ARMul_UnsignedSaturatedAdd16(u16, u16); | ||
| 28 | u8 ARMul_UnsignedSaturatedSub8(u8, u8); | ||
| 29 | u16 ARMul_UnsignedSaturatedSub16(u16, u16); | ||
| 30 | u8 ARMul_UnsignedAbsoluteDifference(u8, u8); | ||
| 31 | u32 ARMul_SignedSatQ(s32, u8, bool*); | ||
| 32 | u32 ARMul_UnsignedSatQ(s32, u8, bool*); | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index 571d6c2f2..26f303de4 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp | |||
| @@ -20,39 +20,30 @@ | |||
| 20 | 20 | ||
| 21 | /* Note: this file handles interface with arm core and vfp registers */ | 21 | /* Note: this file handles interface with arm core and vfp registers */ |
| 22 | 22 | ||
| 23 | #include "common/common_funcs.h" | ||
| 23 | #include "common/logging/log.h" | 24 | #include "common/logging/log.h" |
| 24 | 25 | ||
| 25 | #include "core/arm/skyeye_common/armdefs.h" | 26 | #include "core/arm/skyeye_common/armstate.h" |
| 26 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | 27 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" |
| 27 | #include "core/arm/skyeye_common/vfp/vfp.h" | 28 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 28 | 29 | ||
| 29 | unsigned VFPInit(ARMul_State* state) | 30 | void VFPInit(ARMul_State* state) |
| 30 | { | 31 | { |
| 31 | state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | | 32 | state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | |
| 32 | VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; | 33 | VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; |
| 33 | state->VFP[VFP_FPEXC] = 0; | 34 | state->VFP[VFP_FPEXC] = 0; |
| 34 | state->VFP[VFP_FPSCR] = 0; | 35 | state->VFP[VFP_FPSCR] = 0; |
| 35 | 36 | ||
| 37 | // ARM11 MPCore instruction register reset values. | ||
| 38 | state->VFP[VFP_FPINST] = 0xEE000A00; | ||
| 39 | state->VFP[VFP_FPINST2] = 0; | ||
| 40 | |||
| 36 | // ARM11 MPCore feature register values. | 41 | // ARM11 MPCore feature register values. |
| 37 | state->VFP[VFP_MVFR0] = 0x11111111; | 42 | state->VFP[VFP_MVFR0] = 0x11111111; |
| 38 | state->VFP[VFP_MVFR1] = 0; | 43 | state->VFP[VFP_MVFR1] = 0; |
| 39 | |||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | void VMSR(ARMul_State* state, ARMword reg, ARMword Rt) | ||
| 44 | { | ||
| 45 | if (reg == 1) | ||
| 46 | { | ||
| 47 | state->VFP[VFP_FPSCR] = state->Reg[Rt]; | ||
| 48 | } | ||
| 49 | else if (reg == 8) | ||
| 50 | { | ||
| 51 | state->VFP[VFP_FPEXC] = state->Reg[Rt]; | ||
| 52 | } | ||
| 53 | } | 44 | } |
| 54 | 45 | ||
| 55 | void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value) | 46 | void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value) |
| 56 | { | 47 | { |
| 57 | if (to_arm) | 48 | if (to_arm) |
| 58 | { | 49 | { |
| @@ -64,7 +55,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* | |||
| 64 | } | 55 | } |
| 65 | } | 56 | } |
| 66 | 57 | ||
| 67 | void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2) | 58 | void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) |
| 68 | { | 59 | { |
| 69 | if (to_arm) | 60 | if (to_arm) |
| 70 | { | 61 | { |
| @@ -77,7 +68,7 @@ void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword | |||
| 77 | state->ExtReg[n*2] = *value1; | 68 | state->ExtReg[n*2] = *value1; |
| 78 | } | 69 | } |
| 79 | } | 70 | } |
| 80 | void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2) | 71 | void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) |
| 81 | { | 72 | { |
| 82 | if (to_arm) | 73 | if (to_arm) |
| 83 | { | 74 | { |
| @@ -91,7 +82,7 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor | |||
| 91 | } | 82 | } |
| 92 | } | 83 | } |
| 93 | 84 | ||
| 94 | void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm) | 85 | void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm) |
| 95 | { | 86 | { |
| 96 | if (single) | 87 | if (single) |
| 97 | { | 88 | { |
| @@ -104,7 +95,7 @@ void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm) | |||
| 104 | state->ExtReg[d*2] = 0; | 95 | state->ExtReg[d*2] = 0; |
| 105 | } | 96 | } |
| 106 | } | 97 | } |
| 107 | void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword m) | 98 | void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) |
| 108 | { | 99 | { |
| 109 | if (single) | 100 | if (single) |
| 110 | { | 101 | { |
| @@ -153,9 +144,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc | |||
| 153 | LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); | 144 | LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); |
| 154 | 145 | ||
| 155 | if (exceptions == VFP_EXCEPTION_ERROR) { | 146 | if (exceptions == VFP_EXCEPTION_ERROR) { |
| 156 | LOG_TRACE(Core_ARM11, "unhandled bounce %x\n", inst); | 147 | LOG_CRITICAL(Core_ARM11, "unhandled bounce %x\n", inst); |
| 157 | exit(-1); | 148 | Crash(); |
| 158 | return; | ||
| 159 | } | 149 | } |
| 160 | 150 | ||
| 161 | /* | 151 | /* |
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index acefae9bb..88908da9f 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | #define CHECK_VFP_ENABLED | 26 | #define CHECK_VFP_ENABLED |
| 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); |
| 28 | 28 | ||
| 29 | unsigned VFPInit(ARMul_State* state); | 29 | void VFPInit(ARMul_State* state); |
| 30 | 30 | ||
| 31 | s32 vfp_get_float(ARMul_State* state, u32 reg); | 31 | s32 vfp_get_float(ARMul_State* state, u32 reg); |
| 32 | void vfp_put_float(ARMul_State* state, s32 val, u32 reg); | 32 | void vfp_put_float(ARMul_State* state, s32 val, u32 reg); |
| @@ -36,10 +36,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc | |||
| 36 | u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | 36 | u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); |
| 37 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | 37 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); |
| 38 | 38 | ||
| 39 | void VMSR(ARMul_State* state, ARMword reg, ARMword Rt); | 39 | void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value); |
| 40 | void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value); | 40 | void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); |
| 41 | void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); | 41 | void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); |
| 42 | void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); | 42 | void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm); |
| 43 | void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm); | 43 | void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm); |
| 44 | void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm); | ||
| 45 | |||
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 2007d6dc4..91a8d4d57 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | 34 | ||
| 35 | #include <cstdio> | 35 | #include <cstdio> |
| 36 | #include "common/common_types.h" | 36 | #include "common/common_types.h" |
| 37 | #include "core/arm/skyeye_common/armdefs.h" | 37 | #include "core/arm/skyeye_common/armstate.h" |
| 38 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | 38 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" |
| 39 | 39 | ||
| 40 | #define do_div(n, base) {n/=base;} | 40 | #define do_div(n, base) {n/=base;} |
| @@ -415,7 +415,7 @@ struct op { | |||
| 415 | u32 flags; | 415 | u32 flags; |
| 416 | }; | 416 | }; |
| 417 | 417 | ||
| 418 | static inline u32 fls(ARMword x) | 418 | static inline u32 fls(u32 x) |
| 419 | { | 419 | { |
| 420 | int r = 32; | 420 | int r = 32; |
| 421 | 421 | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index f91049585..1d844a66e 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp | |||
| @@ -70,9 +70,9 @@ static void vfp_double_dump(const char *str, struct vfp_double *d) | |||
| 70 | 70 | ||
| 71 | static void vfp_double_normalise_denormal(struct vfp_double *vd) | 71 | static void vfp_double_normalise_denormal(struct vfp_double *vd) |
| 72 | { | 72 | { |
| 73 | int bits = 31 - fls((ARMword)(vd->significand >> 32)); | 73 | int bits = 31 - fls((u32)(vd->significand >> 32)); |
| 74 | if (bits == 31) | 74 | if (bits == 31) |
| 75 | bits = 63 - fls((ARMword)vd->significand); | 75 | bits = 63 - fls((u32)vd->significand); |
| 76 | 76 | ||
| 77 | vfp_double_dump("normalise_denormal: in", vd); | 77 | vfp_double_dump("normalise_denormal: in", vd); |
| 78 | 78 | ||
| @@ -109,9 +109,9 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, | |||
| 109 | exponent = vd->exponent; | 109 | exponent = vd->exponent; |
| 110 | significand = vd->significand; | 110 | significand = vd->significand; |
| 111 | 111 | ||
| 112 | shift = 32 - fls((ARMword)(significand >> 32)); | 112 | shift = 32 - fls((u32)(significand >> 32)); |
| 113 | if (shift == 32) | 113 | if (shift == 32) |
| 114 | shift = 64 - fls((ARMword)significand); | 114 | shift = 64 - fls((u32)significand); |
| 115 | if (shift) { | 115 | if (shift) { |
| 116 | exponent -= shift; | 116 | exponent -= shift; |
| 117 | significand <<= shift; | 117 | significand <<= shift; |
| @@ -566,7 +566,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 566 | /* | 566 | /* |
| 567 | * 2^0 <= m < 2^32-2^8 | 567 | * 2^0 <= m < 2^32-2^8 |
| 568 | */ | 568 | */ |
| 569 | d = (ARMword)((vdm.significand << 1) >> shift); | 569 | d = (u32)((vdm.significand << 1) >> shift); |
| 570 | rem = vdm.significand << (65 - shift); | 570 | rem = vdm.significand << (65 - shift); |
| 571 | 571 | ||
| 572 | if (rmode == FPSCR_ROUND_NEAREST) { | 572 | if (rmode == FPSCR_ROUND_NEAREST) { |
| @@ -647,7 +647,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 647 | int shift = 1023 + 63 - vdm.exponent; /* 58 */ | 647 | int shift = 1023 + 63 - vdm.exponent; /* 58 */ |
| 648 | u64 rem, incr = 0; | 648 | u64 rem, incr = 0; |
| 649 | 649 | ||
| 650 | d = (ARMword)((vdm.significand << 1) >> shift); | 650 | d = (u32)((vdm.significand << 1) >> shift); |
| 651 | rem = vdm.significand << (65 - shift); | 651 | rem = vdm.significand << (65 - shift); |
| 652 | 652 | ||
| 653 | if (rmode == FPSCR_ROUND_NEAREST) { | 653 | if (rmode == FPSCR_ROUND_NEAREST) { |
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 67fe63aa4..9b99fc5bc 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp | |||
| @@ -51,7 +51,7 @@ VMLA_INST: | |||
| 51 | 51 | ||
| 52 | CHECK_VFP_CDP_RET; | 52 | CHECK_VFP_CDP_RET; |
| 53 | } | 53 | } |
| 54 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 54 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 55 | INC_PC(sizeof(vmla_inst)); | 55 | INC_PC(sizeof(vmla_inst)); |
| 56 | FETCH_INST; | 56 | FETCH_INST; |
| 57 | GOTO_NEXT_INST; | 57 | GOTO_NEXT_INST; |
| @@ -100,7 +100,7 @@ VMLS_INST: | |||
| 100 | 100 | ||
| 101 | CHECK_VFP_CDP_RET; | 101 | CHECK_VFP_CDP_RET; |
| 102 | } | 102 | } |
| 103 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 103 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 104 | INC_PC(sizeof(vmls_inst)); | 104 | INC_PC(sizeof(vmls_inst)); |
| 105 | FETCH_INST; | 105 | FETCH_INST; |
| 106 | GOTO_NEXT_INST; | 106 | GOTO_NEXT_INST; |
| @@ -149,7 +149,7 @@ VNMLA_INST: | |||
| 149 | 149 | ||
| 150 | CHECK_VFP_CDP_RET; | 150 | CHECK_VFP_CDP_RET; |
| 151 | } | 151 | } |
| 152 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 152 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 153 | INC_PC(sizeof(vnmla_inst)); | 153 | INC_PC(sizeof(vnmla_inst)); |
| 154 | FETCH_INST; | 154 | FETCH_INST; |
| 155 | GOTO_NEXT_INST; | 155 | GOTO_NEXT_INST; |
| @@ -199,7 +199,7 @@ VNMLS_INST: | |||
| 199 | 199 | ||
| 200 | CHECK_VFP_CDP_RET; | 200 | CHECK_VFP_CDP_RET; |
| 201 | } | 201 | } |
| 202 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 202 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 203 | INC_PC(sizeof(vnmls_inst)); | 203 | INC_PC(sizeof(vnmls_inst)); |
| 204 | FETCH_INST; | 204 | FETCH_INST; |
| 205 | GOTO_NEXT_INST; | 205 | GOTO_NEXT_INST; |
| @@ -248,7 +248,7 @@ VNMUL_INST: | |||
| 248 | 248 | ||
| 249 | CHECK_VFP_CDP_RET; | 249 | CHECK_VFP_CDP_RET; |
| 250 | } | 250 | } |
| 251 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 251 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 252 | INC_PC(sizeof(vnmul_inst)); | 252 | INC_PC(sizeof(vnmul_inst)); |
| 253 | FETCH_INST; | 253 | FETCH_INST; |
| 254 | GOTO_NEXT_INST; | 254 | GOTO_NEXT_INST; |
| @@ -297,7 +297,7 @@ VMUL_INST: | |||
| 297 | 297 | ||
| 298 | CHECK_VFP_CDP_RET; | 298 | CHECK_VFP_CDP_RET; |
| 299 | } | 299 | } |
| 300 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 300 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 301 | INC_PC(sizeof(vmul_inst)); | 301 | INC_PC(sizeof(vmul_inst)); |
| 302 | FETCH_INST; | 302 | FETCH_INST; |
| 303 | GOTO_NEXT_INST; | 303 | GOTO_NEXT_INST; |
| @@ -346,7 +346,7 @@ VADD_INST: | |||
| 346 | 346 | ||
| 347 | CHECK_VFP_CDP_RET; | 347 | CHECK_VFP_CDP_RET; |
| 348 | } | 348 | } |
| 349 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 349 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 350 | INC_PC(sizeof(vadd_inst)); | 350 | INC_PC(sizeof(vadd_inst)); |
| 351 | FETCH_INST; | 351 | FETCH_INST; |
| 352 | GOTO_NEXT_INST; | 352 | GOTO_NEXT_INST; |
| @@ -395,7 +395,7 @@ VSUB_INST: | |||
| 395 | 395 | ||
| 396 | CHECK_VFP_CDP_RET; | 396 | CHECK_VFP_CDP_RET; |
| 397 | } | 397 | } |
| 398 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 398 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 399 | INC_PC(sizeof(vsub_inst)); | 399 | INC_PC(sizeof(vsub_inst)); |
| 400 | FETCH_INST; | 400 | FETCH_INST; |
| 401 | GOTO_NEXT_INST; | 401 | GOTO_NEXT_INST; |
| @@ -444,7 +444,7 @@ VDIV_INST: | |||
| 444 | 444 | ||
| 445 | CHECK_VFP_CDP_RET; | 445 | CHECK_VFP_CDP_RET; |
| 446 | } | 446 | } |
| 447 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 447 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 448 | INC_PC(sizeof(vdiv_inst)); | 448 | INC_PC(sizeof(vdiv_inst)); |
| 449 | FETCH_INST; | 449 | FETCH_INST; |
| 450 | GOTO_NEXT_INST; | 450 | GOTO_NEXT_INST; |
| @@ -492,7 +492,7 @@ VMOVI_INST: | |||
| 492 | 492 | ||
| 493 | VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); | 493 | VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); |
| 494 | } | 494 | } |
| 495 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 495 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 496 | INC_PC(sizeof(vmovi_inst)); | 496 | INC_PC(sizeof(vmovi_inst)); |
| 497 | FETCH_INST; | 497 | FETCH_INST; |
| 498 | GOTO_NEXT_INST; | 498 | GOTO_NEXT_INST; |
| @@ -536,7 +536,7 @@ VMOVR_INST: | |||
| 536 | 536 | ||
| 537 | VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); | 537 | VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); |
| 538 | } | 538 | } |
| 539 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 539 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 540 | INC_PC(sizeof(vmovr_inst)); | 540 | INC_PC(sizeof(vmovr_inst)); |
| 541 | FETCH_INST; | 541 | FETCH_INST; |
| 542 | GOTO_NEXT_INST; | 542 | GOTO_NEXT_INST; |
| @@ -585,7 +585,7 @@ VABS_INST: | |||
| 585 | 585 | ||
| 586 | CHECK_VFP_CDP_RET; | 586 | CHECK_VFP_CDP_RET; |
| 587 | } | 587 | } |
| 588 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 588 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 589 | INC_PC(sizeof(vabs_inst)); | 589 | INC_PC(sizeof(vabs_inst)); |
| 590 | FETCH_INST; | 590 | FETCH_INST; |
| 591 | GOTO_NEXT_INST; | 591 | GOTO_NEXT_INST; |
| @@ -635,7 +635,7 @@ VNEG_INST: | |||
| 635 | 635 | ||
| 636 | CHECK_VFP_CDP_RET; | 636 | CHECK_VFP_CDP_RET; |
| 637 | } | 637 | } |
| 638 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 638 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 639 | INC_PC(sizeof(vneg_inst)); | 639 | INC_PC(sizeof(vneg_inst)); |
| 640 | FETCH_INST; | 640 | FETCH_INST; |
| 641 | GOTO_NEXT_INST; | 641 | GOTO_NEXT_INST; |
| @@ -684,7 +684,7 @@ VSQRT_INST: | |||
| 684 | 684 | ||
| 685 | CHECK_VFP_CDP_RET; | 685 | CHECK_VFP_CDP_RET; |
| 686 | } | 686 | } |
| 687 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 687 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 688 | INC_PC(sizeof(vsqrt_inst)); | 688 | INC_PC(sizeof(vsqrt_inst)); |
| 689 | FETCH_INST; | 689 | FETCH_INST; |
| 690 | GOTO_NEXT_INST; | 690 | GOTO_NEXT_INST; |
| @@ -733,7 +733,7 @@ VCMP_INST: | |||
| 733 | 733 | ||
| 734 | CHECK_VFP_CDP_RET; | 734 | CHECK_VFP_CDP_RET; |
| 735 | } | 735 | } |
| 736 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 736 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 737 | INC_PC(sizeof(vcmp_inst)); | 737 | INC_PC(sizeof(vcmp_inst)); |
| 738 | FETCH_INST; | 738 | FETCH_INST; |
| 739 | GOTO_NEXT_INST; | 739 | GOTO_NEXT_INST; |
| @@ -782,7 +782,7 @@ VCMP2_INST: | |||
| 782 | 782 | ||
| 783 | CHECK_VFP_CDP_RET; | 783 | CHECK_VFP_CDP_RET; |
| 784 | } | 784 | } |
| 785 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 785 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 786 | INC_PC(sizeof(vcmp2_inst)); | 786 | INC_PC(sizeof(vcmp2_inst)); |
| 787 | FETCH_INST; | 787 | FETCH_INST; |
| 788 | GOTO_NEXT_INST; | 788 | GOTO_NEXT_INST; |
| @@ -831,7 +831,7 @@ VCVTBDS_INST: | |||
| 831 | 831 | ||
| 832 | CHECK_VFP_CDP_RET; | 832 | CHECK_VFP_CDP_RET; |
| 833 | } | 833 | } |
| 834 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 834 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 835 | INC_PC(sizeof(vcvtbds_inst)); | 835 | INC_PC(sizeof(vcvtbds_inst)); |
| 836 | FETCH_INST; | 836 | FETCH_INST; |
| 837 | GOTO_NEXT_INST; | 837 | GOTO_NEXT_INST; |
| @@ -882,7 +882,7 @@ VCVTBFF_INST: | |||
| 882 | 882 | ||
| 883 | CHECK_VFP_CDP_RET; | 883 | CHECK_VFP_CDP_RET; |
| 884 | } | 884 | } |
| 885 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 885 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 886 | INC_PC(sizeof(vcvtbff_inst)); | 886 | INC_PC(sizeof(vcvtbff_inst)); |
| 887 | FETCH_INST; | 887 | FETCH_INST; |
| 888 | GOTO_NEXT_INST; | 888 | GOTO_NEXT_INST; |
| @@ -931,7 +931,7 @@ VCVTBFI_INST: | |||
| 931 | 931 | ||
| 932 | CHECK_VFP_CDP_RET; | 932 | CHECK_VFP_CDP_RET; |
| 933 | } | 933 | } |
| 934 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 934 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 935 | INC_PC(sizeof(vcvtbfi_inst)); | 935 | INC_PC(sizeof(vcvtbfi_inst)); |
| 936 | FETCH_INST; | 936 | FETCH_INST; |
| 937 | GOTO_NEXT_INST; | 937 | GOTO_NEXT_INST; |
| @@ -981,7 +981,7 @@ VMOVBRS_INST: | |||
| 981 | 981 | ||
| 982 | VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); | 982 | VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); |
| 983 | } | 983 | } |
| 984 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 984 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 985 | INC_PC(sizeof(vmovbrs_inst)); | 985 | INC_PC(sizeof(vmovbrs_inst)); |
| 986 | FETCH_INST; | 986 | FETCH_INST; |
| 987 | GOTO_NEXT_INST; | 987 | GOTO_NEXT_INST; |
| @@ -995,7 +995,7 @@ VMOVBRS_INST: | |||
| 995 | #ifdef VFP_INTERPRETER_STRUCT | 995 | #ifdef VFP_INTERPRETER_STRUCT |
| 996 | struct vmsr_inst { | 996 | struct vmsr_inst { |
| 997 | unsigned int reg; | 997 | unsigned int reg; |
| 998 | unsigned int Rd; | 998 | unsigned int Rt; |
| 999 | }; | 999 | }; |
| 1000 | #endif | 1000 | #endif |
| 1001 | #ifdef VFP_INTERPRETER_TRANS | 1001 | #ifdef VFP_INTERPRETER_TRANS |
| @@ -1009,7 +1009,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) | |||
| 1009 | inst_base->br = NON_BRANCH; | 1009 | inst_base->br = NON_BRANCH; |
| 1010 | 1010 | ||
| 1011 | inst_cream->reg = BITS(inst, 16, 19); | 1011 | inst_cream->reg = BITS(inst, 16, 19); |
| 1012 | inst_cream->Rd = BITS(inst, 12, 15); | 1012 | inst_cream->Rt = BITS(inst, 12, 15); |
| 1013 | 1013 | ||
| 1014 | return inst_base; | 1014 | return inst_base; |
| 1015 | } | 1015 | } |
| @@ -1017,17 +1017,32 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) | |||
| 1017 | #ifdef VFP_INTERPRETER_IMPL | 1017 | #ifdef VFP_INTERPRETER_IMPL |
| 1018 | VMSR_INST: | 1018 | VMSR_INST: |
| 1019 | { | 1019 | { |
| 1020 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | 1020 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { |
| 1021 | /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , | 1021 | /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , |
| 1022 | and in privileged mode */ | 1022 | and in privileged mode */ |
| 1023 | /* Exceptions must be checked, according to v7 ref manual */ | 1023 | /* Exceptions must be checked, according to v7 ref manual */ |
| 1024 | CHECK_VFP_ENABLED; | 1024 | CHECK_VFP_ENABLED; |
| 1025 | 1025 | ||
| 1026 | vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component; | 1026 | vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component; |
| 1027 | |||
| 1028 | unsigned int reg = inst_cream->reg; | ||
| 1029 | unsigned int rt = inst_cream->Rt; | ||
| 1027 | 1030 | ||
| 1028 | VMSR(cpu, inst_cream->reg, inst_cream->Rd); | 1031 | if (reg == 1) |
| 1032 | { | ||
| 1033 | cpu->VFP[VFP_FPSCR] = cpu->Reg[rt]; | ||
| 1034 | } | ||
| 1035 | else if (cpu->InAPrivilegedMode()) | ||
| 1036 | { | ||
| 1037 | if (reg == 8) | ||
| 1038 | cpu->VFP[VFP_FPEXC] = cpu->Reg[rt]; | ||
| 1039 | else if (reg == 9) | ||
| 1040 | cpu->VFP[VFP_FPINST] = cpu->Reg[rt]; | ||
| 1041 | else if (reg == 10) | ||
| 1042 | cpu->VFP[VFP_FPINST2] = cpu->Reg[rt]; | ||
| 1043 | } | ||
| 1029 | } | 1044 | } |
| 1030 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1045 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1031 | INC_PC(sizeof(vmsr_inst)); | 1046 | INC_PC(sizeof(vmsr_inst)); |
| 1032 | FETCH_INST; | 1047 | FETCH_INST; |
| 1033 | GOTO_NEXT_INST; | 1048 | GOTO_NEXT_INST; |
| @@ -1075,7 +1090,7 @@ VMOVBRC_INST: | |||
| 1075 | 1090 | ||
| 1076 | cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; | 1091 | cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; |
| 1077 | } | 1092 | } |
| 1078 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1093 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1079 | INC_PC(sizeof(vmovbrc_inst)); | 1094 | INC_PC(sizeof(vmovbrc_inst)); |
| 1080 | FETCH_INST; | 1095 | FETCH_INST; |
| 1081 | GOTO_NEXT_INST; | 1096 | GOTO_NEXT_INST; |
| @@ -1111,19 +1126,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index) | |||
| 1111 | #ifdef VFP_INTERPRETER_IMPL | 1126 | #ifdef VFP_INTERPRETER_IMPL |
| 1112 | VMRS_INST: | 1127 | VMRS_INST: |
| 1113 | { | 1128 | { |
| 1114 | if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { | 1129 | if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { |
| 1115 | /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, | 1130 | /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, |
| 1116 | and in privileged mode */ | 1131 | and in privileged mode */ |
| 1117 | /* Exceptions must be checked, according to v7 ref manual */ | 1132 | /* Exceptions must be checked, according to v7 ref manual */ |
| 1118 | CHECK_VFP_ENABLED; | 1133 | CHECK_VFP_ENABLED; |
| 1119 | 1134 | ||
| 1120 | vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component; | 1135 | vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component; |
| 1121 | 1136 | ||
| 1122 | if (inst_cream->reg == 1) /* FPSCR */ | 1137 | unsigned int reg = inst_cream->reg; |
| 1138 | unsigned int rt = inst_cream->Rt; | ||
| 1139 | |||
| 1140 | if (reg == 1) // FPSCR | ||
| 1123 | { | 1141 | { |
| 1124 | if (inst_cream->Rt != 15) | 1142 | if (rt != 15) |
| 1125 | { | 1143 | { |
| 1126 | cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSCR]; | 1144 | cpu->Reg[rt] = cpu->VFP[VFP_FPSCR]; |
| 1127 | } | 1145 | } |
| 1128 | else | 1146 | else |
| 1129 | { | 1147 | { |
| @@ -1133,28 +1151,29 @@ VMRS_INST: | |||
| 1133 | cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; | 1151 | cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; |
| 1134 | } | 1152 | } |
| 1135 | } | 1153 | } |
| 1136 | else | 1154 | else if (reg == 0) |
| 1137 | { | 1155 | { |
| 1138 | switch (inst_cream->reg) | 1156 | cpu->Reg[rt] = cpu->VFP[VFP_FPSID]; |
| 1139 | { | 1157 | } |
| 1140 | case 0: | 1158 | else if (reg == 6) |
| 1141 | cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; | 1159 | { |
| 1142 | break; | 1160 | cpu->Reg[rt] = cpu->VFP[VFP_MVFR1]; |
| 1143 | case 6: | 1161 | } |
| 1144 | cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1]; | 1162 | else if (reg == 7) |
| 1145 | break; | 1163 | { |
| 1146 | case 7: | 1164 | cpu->Reg[rt] = cpu->VFP[VFP_MVFR0]; |
| 1147 | cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0]; | 1165 | } |
| 1148 | break; | 1166 | else if (cpu->InAPrivilegedMode()) |
| 1149 | case 8: | 1167 | { |
| 1150 | cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; | 1168 | if (reg == 8) |
| 1151 | break; | 1169 | cpu->Reg[rt] = cpu->VFP[VFP_FPEXC]; |
| 1152 | default: | 1170 | else if (reg == 9) |
| 1153 | break; | 1171 | cpu->Reg[rt] = cpu->VFP[VFP_FPINST]; |
| 1154 | } | 1172 | else if (reg == 10) |
| 1173 | cpu->Reg[rt] = cpu->VFP[VFP_FPINST2]; | ||
| 1155 | } | 1174 | } |
| 1156 | } | 1175 | } |
| 1157 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1176 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1158 | INC_PC(sizeof(vmrs_inst)); | 1177 | INC_PC(sizeof(vmrs_inst)); |
| 1159 | FETCH_INST; | 1178 | FETCH_INST; |
| 1160 | GOTO_NEXT_INST; | 1179 | GOTO_NEXT_INST; |
| @@ -1202,7 +1221,7 @@ VMOVBCR_INST: | |||
| 1202 | 1221 | ||
| 1203 | cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; | 1222 | cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; |
| 1204 | } | 1223 | } |
| 1205 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1224 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1206 | INC_PC(sizeof(vmovbcr_inst)); | 1225 | INC_PC(sizeof(vmovbcr_inst)); |
| 1207 | FETCH_INST; | 1226 | FETCH_INST; |
| 1208 | GOTO_NEXT_INST; | 1227 | GOTO_NEXT_INST; |
| @@ -1255,7 +1274,7 @@ VMOVBRRSS_INST: | |||
| 1255 | VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, | 1274 | VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, |
| 1256 | &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); | 1275 | &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); |
| 1257 | } | 1276 | } |
| 1258 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1277 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1259 | INC_PC(sizeof(vmovbrrss_inst)); | 1278 | INC_PC(sizeof(vmovbrrss_inst)); |
| 1260 | FETCH_INST; | 1279 | FETCH_INST; |
| 1261 | GOTO_NEXT_INST; | 1280 | GOTO_NEXT_INST; |
| @@ -1303,7 +1322,7 @@ VMOVBRRD_INST: | |||
| 1303 | VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, | 1322 | VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, |
| 1304 | &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); | 1323 | &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); |
| 1305 | } | 1324 | } |
| 1306 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1325 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1307 | INC_PC(sizeof(vmovbrrd_inst)); | 1326 | INC_PC(sizeof(vmovbrrd_inst)); |
| 1308 | FETCH_INST; | 1327 | FETCH_INST; |
| 1309 | GOTO_NEXT_INST; | 1328 | GOTO_NEXT_INST; |
| @@ -1359,23 +1378,23 @@ VSTR_INST: | |||
| 1359 | 1378 | ||
| 1360 | if (inst_cream->single) | 1379 | if (inst_cream->single) |
| 1361 | { | 1380 | { |
| 1362 | WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d]); | 1381 | cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]); |
| 1363 | } | 1382 | } |
| 1364 | else | 1383 | else |
| 1365 | { | 1384 | { |
| 1366 | const u32 word1 = cpu->ExtReg[inst_cream->d*2+0]; | 1385 | const u32 word1 = cpu->ExtReg[inst_cream->d*2+0]; |
| 1367 | const u32 word2 = cpu->ExtReg[inst_cream->d*2+1]; | 1386 | const u32 word2 = cpu->ExtReg[inst_cream->d*2+1]; |
| 1368 | 1387 | ||
| 1369 | if (InBigEndianMode(cpu)) { | 1388 | if (cpu->InBigEndianMode()) { |
| 1370 | WriteMemory32(cpu, addr + 0, word2); | 1389 | cpu->WriteMemory32(addr + 0, word2); |
| 1371 | WriteMemory32(cpu, addr + 4, word1); | 1390 | cpu->WriteMemory32(addr + 4, word1); |
| 1372 | } else { | 1391 | } else { |
| 1373 | WriteMemory32(cpu, addr + 0, word1); | 1392 | cpu->WriteMemory32(addr + 0, word1); |
| 1374 | WriteMemory32(cpu, addr + 4, word2); | 1393 | cpu->WriteMemory32(addr + 4, word2); |
| 1375 | } | 1394 | } |
| 1376 | } | 1395 | } |
| 1377 | } | 1396 | } |
| 1378 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1397 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1379 | INC_PC(sizeof(vstr_inst)); | 1398 | INC_PC(sizeof(vstr_inst)); |
| 1380 | FETCH_INST; | 1399 | FETCH_INST; |
| 1381 | GOTO_NEXT_INST; | 1400 | GOTO_NEXT_INST; |
| @@ -1425,7 +1444,7 @@ VPUSH_INST: | |||
| 1425 | { | 1444 | { |
| 1426 | if (inst_cream->single) | 1445 | if (inst_cream->single) |
| 1427 | { | 1446 | { |
| 1428 | WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); | 1447 | cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]); |
| 1429 | addr += 4; | 1448 | addr += 4; |
| 1430 | } | 1449 | } |
| 1431 | else | 1450 | else |
| @@ -1433,12 +1452,12 @@ VPUSH_INST: | |||
| 1433 | const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; | 1452 | const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; |
| 1434 | const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; | 1453 | const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; |
| 1435 | 1454 | ||
| 1436 | if (InBigEndianMode(cpu)) { | 1455 | if (cpu->InBigEndianMode()) { |
| 1437 | WriteMemory32(cpu, addr + 0, word2); | 1456 | cpu->WriteMemory32(addr + 0, word2); |
| 1438 | WriteMemory32(cpu, addr + 4, word1); | 1457 | cpu->WriteMemory32(addr + 4, word1); |
| 1439 | } else { | 1458 | } else { |
| 1440 | WriteMemory32(cpu, addr + 0, word1); | 1459 | cpu->WriteMemory32(addr + 0, word1); |
| 1441 | WriteMemory32(cpu, addr + 4, word2); | 1460 | cpu->WriteMemory32(addr + 4, word2); |
| 1442 | } | 1461 | } |
| 1443 | 1462 | ||
| 1444 | addr += 8; | 1463 | addr += 8; |
| @@ -1447,7 +1466,7 @@ VPUSH_INST: | |||
| 1447 | 1466 | ||
| 1448 | cpu->Reg[R13] -= inst_cream->imm32; | 1467 | cpu->Reg[R13] -= inst_cream->imm32; |
| 1449 | } | 1468 | } |
| 1450 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1469 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1451 | INC_PC(sizeof(vpush_inst)); | 1470 | INC_PC(sizeof(vpush_inst)); |
| 1452 | FETCH_INST; | 1471 | FETCH_INST; |
| 1453 | GOTO_NEXT_INST; | 1472 | GOTO_NEXT_INST; |
| @@ -1503,7 +1522,7 @@ VSTM_INST: /* encoding 1 */ | |||
| 1503 | { | 1522 | { |
| 1504 | if (inst_cream->single) | 1523 | if (inst_cream->single) |
| 1505 | { | 1524 | { |
| 1506 | WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); | 1525 | cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]); |
| 1507 | addr += 4; | 1526 | addr += 4; |
| 1508 | } | 1527 | } |
| 1509 | else | 1528 | else |
| @@ -1511,12 +1530,12 @@ VSTM_INST: /* encoding 1 */ | |||
| 1511 | const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; | 1530 | const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; |
| 1512 | const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; | 1531 | const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; |
| 1513 | 1532 | ||
| 1514 | if (InBigEndianMode(cpu)) { | 1533 | if (cpu->InBigEndianMode()) { |
| 1515 | WriteMemory32(cpu, addr + 0, word2); | 1534 | cpu->WriteMemory32(addr + 0, word2); |
| 1516 | WriteMemory32(cpu, addr + 4, word1); | 1535 | cpu->WriteMemory32(addr + 4, word1); |
| 1517 | } else { | 1536 | } else { |
| 1518 | WriteMemory32(cpu, addr + 0, word1); | 1537 | cpu->WriteMemory32(addr + 0, word1); |
| 1519 | WriteMemory32(cpu, addr + 4, word2); | 1538 | cpu->WriteMemory32(addr + 4, word2); |
| 1520 | } | 1539 | } |
| 1521 | 1540 | ||
| 1522 | addr += 8; | 1541 | addr += 8; |
| @@ -1578,15 +1597,15 @@ VPOP_INST: | |||
| 1578 | { | 1597 | { |
| 1579 | if (inst_cream->single) | 1598 | if (inst_cream->single) |
| 1580 | { | 1599 | { |
| 1581 | cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); | 1600 | cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr); |
| 1582 | addr += 4; | 1601 | addr += 4; |
| 1583 | } | 1602 | } |
| 1584 | else | 1603 | else |
| 1585 | { | 1604 | { |
| 1586 | const u32 word1 = ReadMemory32(cpu, addr + 0); | 1605 | const u32 word1 = cpu->ReadMemory32(addr + 0); |
| 1587 | const u32 word2 = ReadMemory32(cpu, addr + 4); | 1606 | const u32 word2 = cpu->ReadMemory32(addr + 4); |
| 1588 | 1607 | ||
| 1589 | if (InBigEndianMode(cpu)) { | 1608 | if (cpu->InBigEndianMode()) { |
| 1590 | cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; | 1609 | cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; |
| 1591 | cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; | 1610 | cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; |
| 1592 | } else { | 1611 | } else { |
| @@ -1599,7 +1618,7 @@ VPOP_INST: | |||
| 1599 | } | 1618 | } |
| 1600 | cpu->Reg[R13] += inst_cream->imm32; | 1619 | cpu->Reg[R13] += inst_cream->imm32; |
| 1601 | } | 1620 | } |
| 1602 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1621 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1603 | INC_PC(sizeof(vpop_inst)); | 1622 | INC_PC(sizeof(vpop_inst)); |
| 1604 | FETCH_INST; | 1623 | FETCH_INST; |
| 1605 | GOTO_NEXT_INST; | 1624 | GOTO_NEXT_INST; |
| @@ -1651,14 +1670,14 @@ VLDR_INST: | |||
| 1651 | 1670 | ||
| 1652 | if (inst_cream->single) | 1671 | if (inst_cream->single) |
| 1653 | { | 1672 | { |
| 1654 | cpu->ExtReg[inst_cream->d] = ReadMemory32(cpu, addr); | 1673 | cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr); |
| 1655 | } | 1674 | } |
| 1656 | else | 1675 | else |
| 1657 | { | 1676 | { |
| 1658 | const u32 word1 = ReadMemory32(cpu, addr + 0); | 1677 | const u32 word1 = cpu->ReadMemory32(addr + 0); |
| 1659 | const u32 word2 = ReadMemory32(cpu, addr + 4); | 1678 | const u32 word2 = cpu->ReadMemory32(addr + 4); |
| 1660 | 1679 | ||
| 1661 | if (InBigEndianMode(cpu)) { | 1680 | if (cpu->InBigEndianMode()) { |
| 1662 | cpu->ExtReg[inst_cream->d*2+0] = word2; | 1681 | cpu->ExtReg[inst_cream->d*2+0] = word2; |
| 1663 | cpu->ExtReg[inst_cream->d*2+1] = word1; | 1682 | cpu->ExtReg[inst_cream->d*2+1] = word1; |
| 1664 | } else { | 1683 | } else { |
| @@ -1667,7 +1686,7 @@ VLDR_INST: | |||
| 1667 | } | 1686 | } |
| 1668 | } | 1687 | } |
| 1669 | } | 1688 | } |
| 1670 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1689 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1671 | INC_PC(sizeof(vldr_inst)); | 1690 | INC_PC(sizeof(vldr_inst)); |
| 1672 | FETCH_INST; | 1691 | FETCH_INST; |
| 1673 | GOTO_NEXT_INST; | 1692 | GOTO_NEXT_INST; |
| @@ -1723,15 +1742,15 @@ VLDM_INST: | |||
| 1723 | { | 1742 | { |
| 1724 | if (inst_cream->single) | 1743 | if (inst_cream->single) |
| 1725 | { | 1744 | { |
| 1726 | cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); | 1745 | cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr); |
| 1727 | addr += 4; | 1746 | addr += 4; |
| 1728 | } | 1747 | } |
| 1729 | else | 1748 | else |
| 1730 | { | 1749 | { |
| 1731 | const u32 word1 = ReadMemory32(cpu, addr + 0); | 1750 | const u32 word1 = cpu->ReadMemory32(addr + 0); |
| 1732 | const u32 word2 = ReadMemory32(cpu, addr + 4); | 1751 | const u32 word2 = cpu->ReadMemory32(addr + 4); |
| 1733 | 1752 | ||
| 1734 | if (InBigEndianMode(cpu)) { | 1753 | if (cpu->InBigEndianMode()) { |
| 1735 | cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; | 1754 | cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; |
| 1736 | cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; | 1755 | cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; |
| 1737 | } else { | 1756 | } else { |
| @@ -1747,7 +1766,7 @@ VLDM_INST: | |||
| 1747 | cpu->Reg[inst_cream->n] - inst_cream->imm32); | 1766 | cpu->Reg[inst_cream->n] - inst_cream->imm32); |
| 1748 | } | 1767 | } |
| 1749 | } | 1768 | } |
| 1750 | cpu->Reg[15] += GET_INST_SIZE(cpu); | 1769 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 1751 | INC_PC(sizeof(vldm_inst)); | 1770 | INC_PC(sizeof(vldm_inst)); |
| 1752 | FETCH_INST; | 1771 | FETCH_INST; |
| 1753 | GOTO_NEXT_INST; | 1772 | GOTO_NEXT_INST; |
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index 5a655a6f2..e5d339252 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp | |||
| @@ -53,6 +53,8 @@ | |||
| 53 | 53 | ||
| 54 | #include <cinttypes> | 54 | #include <cinttypes> |
| 55 | 55 | ||
| 56 | #include "common/common_funcs.h" | ||
| 57 | #include "common/common_types.h" | ||
| 56 | #include "common/logging/log.h" | 58 | #include "common/logging/log.h" |
| 57 | 59 | ||
| 58 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" | 60 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" |
| @@ -1246,7 +1248,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1246 | 1248 | ||
| 1247 | if (!fop->fn) { | 1249 | if (!fop->fn) { |
| 1248 | LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]); | 1250 | LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]); |
| 1249 | exit(-1); | 1251 | Crash(); |
| 1250 | goto invalid; | 1252 | goto invalid; |
| 1251 | } | 1253 | } |
| 1252 | 1254 | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index 79038cd52..dddc16708 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -2,15 +2,12 @@ | |||
| 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/common_types.h" | ||
| 6 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 7 | 6 | ||
| 8 | #include "core/core.h" | 7 | #include "core/core.h" |
| 9 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 10 | 9 | ||
| 11 | #include "core/settings.h" | ||
| 12 | #include "core/arm/arm_interface.h" | 10 | #include "core/arm/arm_interface.h" |
| 13 | #include "core/arm/disassembler/arm_disasm.h" | ||
| 14 | #include "core/arm/dyncom/arm_dyncom.h" | 11 | #include "core/arm/dyncom/arm_dyncom.h" |
| 15 | #include "core/hle/hle.h" | 12 | #include "core/hle/hle.h" |
| 16 | #include "core/hle/kernel/thread.h" | 13 | #include "core/hle/kernel/thread.h" |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index e53c2e606..20f2da0fe 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -3,12 +3,12 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <atomic> | 5 | #include <atomic> |
| 6 | #include <cstdio> | ||
| 7 | #include <mutex> | 6 | #include <mutex> |
| 8 | #include <vector> | 7 | #include <vector> |
| 9 | 8 | ||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/chunk_file.h" | 9 | #include "common/chunk_file.h" |
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "common/string_util.h" | ||
| 12 | 12 | ||
| 13 | #include "core/arm/arm_interface.h" | 13 | #include "core/arm/arm_interface.h" |
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| @@ -502,7 +502,7 @@ void Advance() { | |||
| 502 | Core::g_app_core->down_count += diff; | 502 | Core::g_app_core->down_count += diff; |
| 503 | } | 503 | } |
| 504 | if (advance_callback) | 504 | if (advance_callback) |
| 505 | advance_callback(cycles_executed); | 505 | advance_callback(static_cast<int>(cycles_executed)); |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | void LogPendingEvents() { | 508 | void LogPendingEvents() { |
diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp index 45a559ce8..3f81447df 100644 --- a/src/core/file_sys/archive_backend.cpp +++ b/src/core/file_sys/archive_backend.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 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 <cstddef> | ||
| 6 | #include <iomanip> | ||
| 5 | #include <sstream> | 7 | #include <sstream> |
| 6 | 8 | ||
| 7 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index e50c58a52..92dad8e6f 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp | |||
| @@ -2,17 +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 <sys/stat.h> | 5 | #include <algorithm> |
| 6 | #include <vector> | ||
| 6 | 7 | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 10 | #include "common/make_unique.h" | 11 | #include "common/make_unique.h" |
| 12 | #include "common/string_util.h" | ||
| 11 | 13 | ||
| 12 | #include "core/file_sys/archive_extsavedata.h" | 14 | #include "core/file_sys/archive_extsavedata.h" |
| 13 | #include "core/file_sys/disk_archive.h" | 15 | #include "core/file_sys/disk_archive.h" |
| 14 | #include "core/hle/service/fs/archive.h" | 16 | #include "core/hle/service/fs/archive.h" |
| 15 | #include "core/settings.h" | ||
| 16 | 17 | ||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 18 | // FileSys namespace | 19 | // FileSys namespace |
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index ef0b27bde..ec8d770fc 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h | |||
| @@ -4,10 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 9 | #include "core/file_sys/disk_archive.h" | 12 | #include "core/file_sys/archive_backend.h" |
| 10 | #include "core/loader/loader.h" | 13 | #include "core/hle/result.h" |
| 11 | 14 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 13 | // FileSys namespace | 16 | // FileSys namespace |
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index d4a12ed10..696b51a94 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp | |||
| @@ -2,30 +2,30 @@ | |||
| 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 <algorithm> | ||
| 5 | #include <memory> | 6 | #include <memory> |
| 6 | 7 | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | ||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/make_unique.h" | 10 | #include "common/make_unique.h" |
| 11 | 11 | ||
| 12 | #include "core/file_sys/archive_romfs.h" | 12 | #include "core/file_sys/archive_romfs.h" |
| 13 | #include "core/file_sys/ivfc_archive.h" | ||
| 13 | 14 | ||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 15 | // FileSys namespace | 16 | // FileSys namespace |
| 16 | 17 | ||
| 17 | namespace FileSys { | 18 | namespace FileSys { |
| 18 | 19 | ||
| 19 | ArchiveFactory_RomFS::ArchiveFactory_RomFS(const Loader::AppLoader& app_loader) | 20 | ArchiveFactory_RomFS::ArchiveFactory_RomFS(Loader::AppLoader& app_loader) { |
| 20 | : romfs_data(std::make_shared<std::vector<u8>>()) { | ||
| 21 | // Load the RomFS from the app | 21 | // Load the RomFS from the app |
| 22 | if (Loader::ResultStatus::Success != app_loader.ReadRomFS(*romfs_data)) { | 22 | if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) { |
| 23 | LOG_ERROR(Service_FS, "Unable to read RomFS!"); | 23 | LOG_ERROR(Service_FS, "Unable to read RomFS!"); |
| 24 | } | 24 | } |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) { | 27 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) { |
| 28 | auto archive = Common::make_unique<IVFCArchive>(romfs_data); | 28 | auto archive = Common::make_unique<IVFCArchive>(romfs_file, data_offset, data_size); |
| 29 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | 29 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |
| 30 | } | 30 | } |
| 31 | 31 | ||
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 409bc670a..2bedfa9c6 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h | |||
| @@ -5,11 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | ||
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| 12 | #include "core/file_sys/ivfc_archive.h" | 13 | #include "core/file_sys/archive_backend.h" |
| 14 | #include "core/hle/result.h" | ||
| 13 | #include "core/loader/loader.h" | 15 | #include "core/loader/loader.h" |
| 14 | 16 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -20,14 +22,16 @@ namespace FileSys { | |||
| 20 | /// File system interface to the RomFS archive | 22 | /// File system interface to the RomFS archive |
| 21 | class ArchiveFactory_RomFS final : public ArchiveFactory { | 23 | class ArchiveFactory_RomFS final : public ArchiveFactory { |
| 22 | public: | 24 | public: |
| 23 | ArchiveFactory_RomFS(const Loader::AppLoader& app_loader); | 25 | ArchiveFactory_RomFS(Loader::AppLoader& app_loader); |
| 24 | 26 | ||
| 25 | std::string GetName() const override { return "RomFS"; } | 27 | std::string GetName() const override { return "RomFS"; } |
| 26 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | 28 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |
| 27 | ResultCode Format(const Path& path) override; | 29 | ResultCode Format(const Path& path) override; |
| 28 | 30 | ||
| 29 | private: | 31 | private: |
| 30 | std::shared_ptr<std::vector<u8>> romfs_data; | 32 | std::shared_ptr<FileUtil::IOFile> romfs_file; |
| 33 | u64 data_offset; | ||
| 34 | u64 data_size; | ||
| 31 | }; | 35 | }; |
| 32 | 36 | ||
| 33 | } // namespace FileSys | 37 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index a92309377..12876899f 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp | |||
| @@ -2,18 +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 <sys/stat.h> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/make_unique.h" | 10 | #include "common/make_unique.h" |
| 11 | #include "common/string_util.h" | ||
| 11 | 12 | ||
| 12 | #include "core/file_sys/archive_savedata.h" | 13 | #include "core/file_sys/archive_savedata.h" |
| 13 | #include "core/file_sys/disk_archive.h" | 14 | #include "core/file_sys/disk_archive.h" |
| 14 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/service/fs/archive.h" | 16 | #include "core/hle/service/fs/archive.h" |
| 16 | #include "core/settings.h" | ||
| 17 | 17 | ||
| 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 19 | // FileSys namespace | 19 | // FileSys namespace |
| @@ -37,7 +37,7 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directo | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { | 39 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { |
| 40 | std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id); | 40 | std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id); |
| 41 | if (!FileUtil::Exists(concrete_mount_point)) { | 41 | if (!FileUtil::Exists(concrete_mount_point)) { |
| 42 | // When a SaveData archive is created for the first time, it is not yet formatted | 42 | // When a SaveData archive is created for the first time, it is not yet formatted |
| 43 | // and the save file/directory structure expected by the game has not yet been initialized. | 43 | // and the save file/directory structure expected by the game has not yet been initialized. |
| @@ -52,7 +52,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P | |||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | ResultCode ArchiveFactory_SaveData::Format(const Path& path) { | 54 | ResultCode ArchiveFactory_SaveData::Format(const Path& path) { |
| 55 | std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id); | 55 | std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id); |
| 56 | FileUtil::DeleteDirRecursively(concrete_mount_point); | 56 | FileUtil::DeleteDirRecursively(concrete_mount_point); |
| 57 | FileUtil::CreateFullPath(concrete_mount_point); | 57 | FileUtil::CreateFullPath(concrete_mount_point); |
| 58 | return RESULT_SUCCESS; | 58 | return RESULT_SUCCESS; |
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h index db17afc92..1f65297dd 100644 --- a/src/core/file_sys/archive_savedata.h +++ b/src/core/file_sys/archive_savedata.h | |||
| @@ -4,10 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include <memory> |
| 8 | #include <string> | ||
| 8 | 9 | ||
| 9 | #include "core/file_sys/disk_archive.h" | 10 | #include "core/file_sys/archive_backend.h" |
| 10 | #include "core/loader/loader.h" | 11 | #include "core/hle/result.h" |
| 11 | 12 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 13 | // FileSys namespace | 14 | // FileSys namespace |
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp index e7e4fbf1d..ea1dfe2c7 100644 --- a/src/core/file_sys/archive_savedatacheck.cpp +++ b/src/core/file_sys/archive_savedatacheck.cpp | |||
| @@ -2,11 +2,17 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 5 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 6 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 7 | #include "common/make_unique.h" | 11 | #include "common/make_unique.h" |
| 12 | #include "common/string_util.h" | ||
| 8 | 13 | ||
| 9 | #include "core/file_sys/archive_savedatacheck.h" | 14 | #include "core/file_sys/archive_savedatacheck.h" |
| 15 | #include "core/file_sys/ivfc_archive.h" | ||
| 10 | #include "core/hle/service/fs/archive.h" | 16 | #include "core/hle/service/fs/archive.h" |
| 11 | 17 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -31,17 +37,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co | |||
| 31 | auto vec = path.AsBinary(); | 37 | auto vec = path.AsBinary(); |
| 32 | const u32* data = reinterpret_cast<u32*>(vec.data()); | 38 | const u32* data = reinterpret_cast<u32*>(vec.data()); |
| 33 | std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); | 39 | std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); |
| 34 | FileUtil::IOFile file(file_path, "rb"); | 40 | auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb"); |
| 35 | 41 | ||
| 36 | if (!file.IsOpen()) { | 42 | if (!file->IsOpen()) { |
| 37 | return ResultCode(-1); // TODO(Subv): Find the right error code | 43 | return ResultCode(-1); // TODO(Subv): Find the right error code |
| 38 | } | 44 | } |
| 39 | auto size = file.GetSize(); | 45 | auto size = file->GetSize(); |
| 40 | auto raw_data = std::make_shared<std::vector<u8>>(size); | ||
| 41 | file.ReadBytes(raw_data->data(), size); | ||
| 42 | file.Close(); | ||
| 43 | 46 | ||
| 44 | auto archive = Common::make_unique<IVFCArchive>(std::move(raw_data)); | 47 | auto archive = Common::make_unique<IVFCArchive>(file, 0, size); |
| 45 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | 48 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |
| 46 | } | 49 | } |
| 47 | 50 | ||
diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h index f78a6f02e..b14aefe8b 100644 --- a/src/core/file_sys/archive_savedatacheck.h +++ b/src/core/file_sys/archive_savedatacheck.h | |||
| @@ -4,12 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | 7 | #include <memory> |
| 8 | #include <string> | ||
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "core/file_sys/archive_backend.h" |
| 10 | 11 | #include "core/hle/result.h" | |
| 11 | #include "core/file_sys/ivfc_archive.h" | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | 12 | ||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 15 | // FileSys namespace | 14 | // FileSys namespace |
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index c1234a186..5c825f429 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -2,9 +2,8 @@ | |||
| 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 <sys/stat.h> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | 7 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 10 | #include "common/make_unique.h" | 9 | #include "common/make_unique.h" |
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 1becf6c0f..10b273bdb 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h | |||
| @@ -4,10 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include <memory> |
| 8 | #include <string> | ||
| 8 | 9 | ||
| 9 | #include "core/file_sys/disk_archive.h" | 10 | #include "core/file_sys/archive_backend.h" |
| 10 | #include "core/loader/loader.h" | 11 | #include "core/hle/result.h" |
| 11 | 12 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 13 | // FileSys namespace | 14 | // FileSys namespace |
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 4fe785c97..896f89529 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp | |||
| @@ -2,15 +2,17 @@ | |||
| 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 <sys/stat.h> | 5 | #include <algorithm> |
| 6 | #include <vector> | ||
| 6 | 7 | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 9 | #include "common/make_unique.h" | 10 | #include "common/make_unique.h" |
| 11 | #include "common/string_util.h" | ||
| 10 | 12 | ||
| 11 | #include "core/file_sys/archive_systemsavedata.h" | 13 | #include "core/file_sys/archive_systemsavedata.h" |
| 14 | #include "core/file_sys/disk_archive.h" | ||
| 12 | #include "core/hle/service/fs/archive.h" | 15 | #include "core/hle/service/fs/archive.h" |
| 13 | #include "core/settings.h" | ||
| 14 | 16 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 16 | // FileSys namespace | 18 | // FileSys namespace |
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h index 3431fed88..afc689848 100644 --- a/src/core/file_sys/archive_systemsavedata.h +++ b/src/core/file_sys/archive_systemsavedata.h | |||
| @@ -4,10 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 9 | #include "core/file_sys/disk_archive.h" | 12 | #include "core/file_sys/archive_backend.h" |
| 10 | #include "core/loader/loader.h" | 13 | #include "core/hle/result.h" |
| 11 | 14 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 13 | // FileSys namespace | 16 | // FileSys namespace |
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index 9980cced1..1096fd34d 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -2,7 +2,8 @@ | |||
| 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 <sys/stat.h> | 5 | #include <algorithm> |
| 6 | #include <cstdio> | ||
| 6 | 7 | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| @@ -10,7 +11,6 @@ | |||
| 10 | #include "common/make_unique.h" | 11 | #include "common/make_unique.h" |
| 11 | 12 | ||
| 12 | #include "core/file_sys/disk_archive.h" | 13 | #include "core/file_sys/disk_archive.h" |
| 13 | #include "core/settings.h" | ||
| 14 | 14 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 16 | // FileSys namespace | 16 | // FileSys namespace |
| @@ -105,12 +105,12 @@ bool DiskFile::Open() { | |||
| 105 | return true; | 105 | return true; |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const { | 108 | size_t DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { |
| 109 | file->Seek(offset, SEEK_SET); | 109 | file->Seek(offset, SEEK_SET); |
| 110 | return file->ReadBytes(buffer, length); | 110 | return file->ReadBytes(buffer, length); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | 113 | size_t DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const { |
| 114 | file->Seek(offset, SEEK_SET); | 114 | file->Seek(offset, SEEK_SET); |
| 115 | size_t written = file->WriteBytes(buffer, length); | 115 | size_t written = file->WriteBytes(buffer, length); |
| 116 | if (flush) | 116 | if (flush) |
| @@ -118,8 +118,8 @@ size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, cons | |||
| 118 | return written; | 118 | return written; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | size_t DiskFile::GetSize() const { | 121 | u64 DiskFile::GetSize() const { |
| 122 | return static_cast<size_t>(file->GetSize()); | 122 | return file->GetSize(); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | bool DiskFile::SetSize(const u64 size) const { | 125 | bool DiskFile::SetSize(const u64 size) const { |
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index a22d3837a..c5da07508 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -4,13 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | #include <memory> | ||
| 9 | #include <string> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 7 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | 13 | #include "common/file_util.h" |
| 9 | 14 | ||
| 10 | #include "core/file_sys/archive_backend.h" | 15 | #include "core/file_sys/archive_backend.h" |
| 11 | #include "core/file_sys/directory_backend.h" | 16 | #include "core/file_sys/directory_backend.h" |
| 12 | #include "core/file_sys/file_backend.h" | 17 | #include "core/file_sys/file_backend.h" |
| 13 | #include "core/loader/loader.h" | 18 | #include "core/hle/result.h" |
| 14 | 19 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 20 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 16 | // FileSys namespace | 21 | // FileSys namespace |
| @@ -50,10 +55,10 @@ public: | |||
| 50 | DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); | 55 | DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); |
| 51 | 56 | ||
| 52 | bool Open() override; | 57 | bool Open() override; |
| 53 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | 58 | size_t Read(u64 offset, size_t length, u8* buffer) const override; |
| 54 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | 59 | size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; |
| 55 | size_t GetSize() const override; | 60 | u64 GetSize() const override; |
| 56 | bool SetSize(const u64 size) const override; | 61 | bool SetSize(u64 size) const override; |
| 57 | bool Close() const override; | 62 | bool Close() const override; |
| 58 | 63 | ||
| 59 | void Flush() const override { | 64 | void Flush() const override { |
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h index 0fcff1845..df7165df3 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/file_backend.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -29,7 +31,7 @@ public: | |||
| 29 | * @param buffer Buffer to read data into | 31 | * @param buffer Buffer to read data into |
| 30 | * @return Number of bytes read | 32 | * @return Number of bytes read |
| 31 | */ | 33 | */ |
| 32 | virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; | 34 | virtual size_t Read(u64 offset, size_t length, u8* buffer) const = 0; |
| 33 | 35 | ||
| 34 | /** | 36 | /** |
| 35 | * Write data to the file | 37 | * Write data to the file |
| @@ -39,20 +41,20 @@ public: | |||
| 39 | * @param buffer Buffer to read data from | 41 | * @param buffer Buffer to read data from |
| 40 | * @return Number of bytes written | 42 | * @return Number of bytes written |
| 41 | */ | 43 | */ |
| 42 | virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; | 44 | virtual size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0; |
| 43 | 45 | ||
| 44 | /** | 46 | /** |
| 45 | * Get the size of the file in bytes | 47 | * Get the size of the file in bytes |
| 46 | * @return Size of the file in bytes | 48 | * @return Size of the file in bytes |
| 47 | */ | 49 | */ |
| 48 | virtual size_t GetSize() const = 0; | 50 | virtual u64 GetSize() const = 0; |
| 49 | 51 | ||
| 50 | /** | 52 | /** |
| 51 | * Set the size of the file in bytes | 53 | * Set the size of the file in bytes |
| 52 | * @param size New size of the file | 54 | * @param size New size of the file |
| 53 | * @return true if successful | 55 | * @return true if successful |
| 54 | */ | 56 | */ |
| 55 | virtual bool SetSize(const u64 size) const = 0; | 57 | virtual bool SetSize(u64 size) const = 0; |
| 56 | 58 | ||
| 57 | /** | 59 | /** |
| 58 | * Close the file | 60 | * Close the file |
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp index 2d2509d16..e16aa1491 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp | |||
| @@ -2,10 +2,10 @@ | |||
| 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 <cstring> | ||
| 5 | #include <memory> | 6 | #include <memory> |
| 6 | 7 | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | ||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/make_unique.h" | 10 | #include "common/make_unique.h" |
| 11 | 11 | ||
| @@ -16,15 +16,12 @@ | |||
| 16 | 16 | ||
| 17 | namespace FileSys { | 17 | namespace FileSys { |
| 18 | 18 | ||
| 19 | IVFCArchive::IVFCArchive(std::shared_ptr<const std::vector<u8>> data) : data(data) { | ||
| 20 | } | ||
| 21 | |||
| 22 | std::string IVFCArchive::GetName() const { | 19 | std::string IVFCArchive::GetName() const { |
| 23 | return "IVFC"; | 20 | return "IVFC"; |
| 24 | } | 21 | } |
| 25 | 22 | ||
| 26 | std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { | 23 | std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { |
| 27 | return Common::make_unique<IVFCFile>(data); | 24 | return Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size); |
| 28 | } | 25 | } |
| 29 | 26 | ||
| 30 | bool IVFCArchive::DeleteFile(const Path& path) const { | 27 | bool IVFCArchive::DeleteFile(const Path& path) const { |
| @@ -64,19 +61,21 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c | |||
| 64 | 61 | ||
| 65 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 62 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 66 | 63 | ||
| 67 | size_t IVFCFile::Read(const u64 offset, const u32 length, u8* buffer) const { | 64 | size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { |
| 68 | LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); | 65 | LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); |
| 69 | memcpy(buffer, data->data() + offset, length); | 66 | romfs_file->Seek(data_offset + offset, SEEK_SET); |
| 70 | return length; | 67 | size_t read_length = (size_t)std::min((u64)length, data_size - offset); |
| 68 | |||
| 69 | return romfs_file->ReadBytes(buffer, read_length); | ||
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | size_t IVFCFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | 72 | size_t IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const { |
| 74 | LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); | 73 | LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); |
| 75 | return 0; | 74 | return 0; |
| 76 | } | 75 | } |
| 77 | 76 | ||
| 78 | size_t IVFCFile::GetSize() const { | 77 | u64 IVFCFile::GetSize() const { |
| 79 | return sizeof(u8) * data->size(); | 78 | return data_size; |
| 80 | } | 79 | } |
| 81 | 80 | ||
| 82 | bool IVFCFile::SetSize(const u64 size) const { | 81 | bool IVFCFile::SetSize(const u64 size) const { |
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index 10415798d..c15a6c4ae 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h | |||
| @@ -4,15 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string> | ||
| 8 | #include <vector> | 10 | #include <vector> |
| 9 | 11 | ||
| 10 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/file_util.h" | ||
| 11 | 14 | ||
| 12 | #include "core/file_sys/archive_backend.h" | 15 | #include "core/file_sys/archive_backend.h" |
| 13 | #include "core/file_sys/directory_backend.h" | 16 | #include "core/file_sys/directory_backend.h" |
| 14 | #include "core/file_sys/file_backend.h" | 17 | #include "core/file_sys/file_backend.h" |
| 15 | #include "core/loader/loader.h" | 18 | #include "core/hle/result.h" |
| 16 | 19 | ||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 20 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 18 | // FileSys namespace | 21 | // FileSys namespace |
| @@ -26,7 +29,8 @@ namespace FileSys { | |||
| 26 | */ | 29 | */ |
| 27 | class IVFCArchive : public ArchiveBackend { | 30 | class IVFCArchive : public ArchiveBackend { |
| 28 | public: | 31 | public: |
| 29 | IVFCArchive(std::shared_ptr<const std::vector<u8>> data); | 32 | IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size) |
| 33 | : romfs_file(file), data_offset(offset), data_size(size) {} | ||
| 30 | 34 | ||
| 31 | std::string GetName() const override; | 35 | std::string GetName() const override; |
| 32 | 36 | ||
| @@ -40,23 +44,28 @@ public: | |||
| 40 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 44 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 41 | 45 | ||
| 42 | protected: | 46 | protected: |
| 43 | std::shared_ptr<const std::vector<u8>> data; | 47 | std::shared_ptr<FileUtil::IOFile> romfs_file; |
| 48 | u64 data_offset; | ||
| 49 | u64 data_size; | ||
| 44 | }; | 50 | }; |
| 45 | 51 | ||
| 46 | class IVFCFile : public FileBackend { | 52 | class IVFCFile : public FileBackend { |
| 47 | public: | 53 | public: |
| 48 | IVFCFile(std::shared_ptr<const std::vector<u8>> data) : data(data) {} | 54 | IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size) |
| 55 | : romfs_file(file), data_offset(offset), data_size(size) {} | ||
| 49 | 56 | ||
| 50 | bool Open() override { return true; } | 57 | bool Open() override { return true; } |
| 51 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | 58 | size_t Read(u64 offset, size_t length, u8* buffer) const override; |
| 52 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | 59 | size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; |
| 53 | size_t GetSize() const override; | 60 | u64 GetSize() const override; |
| 54 | bool SetSize(const u64 size) const override; | 61 | bool SetSize(u64 size) const override; |
| 55 | bool Close() const override { return false; } | 62 | bool Close() const override { return false; } |
| 56 | void Flush() const override { } | 63 | void Flush() const override { } |
| 57 | 64 | ||
| 58 | private: | 65 | private: |
| 59 | std::shared_ptr<const std::vector<u8>> data; | 66 | std::shared_ptr<FileUtil::IOFile> romfs_file; |
| 67 | u64 data_offset; | ||
| 68 | u64 data_size; | ||
| 60 | }; | 69 | }; |
| 61 | 70 | ||
| 62 | class IVFCDirectory : public DirectoryBackend { | 71 | class IVFCDirectory : public DirectoryBackend { |
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp new file mode 100644 index 000000000..826f6cbb6 --- /dev/null +++ b/src/core/hle/applets/applet.cpp | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | #include <memory> | ||
| 7 | #include <type_traits> | ||
| 8 | #include <unordered_map> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | #include "core/core_timing.h" | ||
| 14 | #include "core/hle/applets/applet.h" | ||
| 15 | #include "core/hle/applets/swkbd.h" | ||
| 16 | #include "core/hle/result.h" | ||
| 17 | #include "core/hle/service/apt/apt.h" | ||
| 18 | |||
| 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 20 | |||
| 21 | // Specializes std::hash for AppletId, so that we can use it in std::unordered_map. | ||
| 22 | // Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 | ||
| 23 | namespace std { | ||
| 24 | template <> | ||
| 25 | struct hash<Service::APT::AppletId> { | ||
| 26 | typedef Service::APT::AppletId argument_type; | ||
| 27 | typedef std::size_t result_type; | ||
| 28 | |||
| 29 | result_type operator()(const argument_type& id_code) const { | ||
| 30 | typedef std::underlying_type<argument_type>::type Type; | ||
| 31 | return std::hash<Type>()(static_cast<Type>(id_code)); | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | } | ||
| 35 | |||
| 36 | namespace HLE { | ||
| 37 | namespace Applets { | ||
| 38 | |||
| 39 | static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets; | ||
| 40 | static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback. | ||
| 41 | /// The interval at which the Applet update callback will be called, 16.6ms | ||
| 42 | static const u64 applet_update_interval_us = 16666; | ||
| 43 | |||
| 44 | ResultCode Applet::Create(Service::APT::AppletId id) { | ||
| 45 | switch (id) { | ||
| 46 | case Service::APT::AppletId::SoftwareKeyboard1: | ||
| 47 | case Service::APT::AppletId::SoftwareKeyboard2: | ||
| 48 | applets[id] = std::make_shared<SoftwareKeyboard>(id); | ||
| 49 | break; | ||
| 50 | default: | ||
| 51 | // TODO(Subv): Find the right error code | ||
| 52 | return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||
| 53 | } | ||
| 54 | |||
| 55 | return RESULT_SUCCESS; | ||
| 56 | } | ||
| 57 | |||
| 58 | std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) { | ||
| 59 | auto itr = applets.find(id); | ||
| 60 | if (itr != applets.end()) | ||
| 61 | return itr->second; | ||
| 62 | return nullptr; | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Handles updating the current Applet every time it's called. | ||
| 66 | static void AppletUpdateEvent(u64 applet_id, int cycles_late) { | ||
| 67 | Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id); | ||
| 68 | std::shared_ptr<Applet> applet = Applet::Get(id); | ||
| 69 | ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); | ||
| 70 | |||
| 71 | applet->Update(); | ||
| 72 | |||
| 73 | // If the applet is still running after the last update, reschedule the event | ||
| 74 | if (applet->IsRunning()) { | ||
| 75 | CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, | ||
| 76 | applet_update_event, applet_id); | ||
| 77 | } else { | ||
| 78 | // Otherwise the applet has terminated, in which case we should clean it up | ||
| 79 | applets[id] = nullptr; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { | ||
| 84 | ResultCode result = StartImpl(parameter); | ||
| 85 | if (result.IsError()) | ||
| 86 | return result; | ||
| 87 | // Schedule the update event | ||
| 88 | CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id)); | ||
| 89 | return result; | ||
| 90 | } | ||
| 91 | |||
| 92 | void Init() { | ||
| 93 | // Register the applet update callback | ||
| 94 | applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); | ||
| 95 | } | ||
| 96 | |||
| 97 | void Shutdown() { | ||
| 98 | } | ||
| 99 | |||
| 100 | } | ||
| 101 | } // namespace | ||
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h new file mode 100644 index 000000000..b235d0b8a --- /dev/null +++ b/src/core/hle/applets/applet.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/apt/apt.h" | ||
| 11 | |||
| 12 | namespace HLE { | ||
| 13 | namespace Applets { | ||
| 14 | |||
| 15 | class Applet { | ||
| 16 | public: | ||
| 17 | virtual ~Applet() { } | ||
| 18 | Applet(Service::APT::AppletId id) : id(id) { } | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Creates an instance of the Applet subclass identified by the parameter. | ||
| 22 | * and stores it in a global map. | ||
| 23 | * @param id Id of the applet to create. | ||
| 24 | * @returns ResultCode Whether the operation was successful or not. | ||
| 25 | */ | ||
| 26 | static ResultCode Create(Service::APT::AppletId id); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Retrieves the Applet instance identified by the specified id. | ||
| 30 | * @param id Id of the Applet to retrieve. | ||
| 31 | * @returns Requested Applet or nullptr if not found. | ||
| 32 | */ | ||
| 33 | static std::shared_ptr<Applet> Get(Service::APT::AppletId id); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Handles a parameter from the application. | ||
| 37 | * @param parameter Parameter data to handle. | ||
| 38 | * @returns ResultCode Whether the operation was successful or not. | ||
| 39 | */ | ||
| 40 | virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Handles the Applet start event, triggered from the application. | ||
| 44 | * @param parameter Parameter data to handle. | ||
| 45 | * @returns ResultCode Whether the operation was successful or not. | ||
| 46 | */ | ||
| 47 | ResultCode Start(const Service::APT::AppletStartupParameter& parameter); | ||
| 48 | |||
| 49 | /** | ||
| 50 | * Whether the applet is currently executing instead of the host application or not. | ||
| 51 | */ | ||
| 52 | virtual bool IsRunning() const = 0; | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Handles an update tick for the Applet, lets it update the screen, send commands, etc. | ||
| 56 | */ | ||
| 57 | virtual void Update() = 0; | ||
| 58 | |||
| 59 | protected: | ||
| 60 | /** | ||
| 61 | * Handles the Applet start event, triggered from the application. | ||
| 62 | * @param parameter Parameter data to handle. | ||
| 63 | * @returns ResultCode Whether the operation was successful or not. | ||
| 64 | */ | ||
| 65 | virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; | ||
| 66 | |||
| 67 | Service::APT::AppletId id; ///< Id of this Applet | ||
| 68 | }; | ||
| 69 | |||
| 70 | /// Initializes the HLE applets | ||
| 71 | void Init(); | ||
| 72 | |||
| 73 | /// Shuts down the HLE applets | ||
| 74 | void Shutdown(); | ||
| 75 | |||
| 76 | } | ||
| 77 | } // namespace | ||
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp new file mode 100644 index 000000000..1db6b5a17 --- /dev/null +++ b/src/core/hle/applets/swkbd.cpp | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <string> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/logging/log.h" | ||
| 10 | #include "common/string_util.h" | ||
| 11 | |||
| 12 | #include "core/hle/applets/swkbd.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | ||
| 14 | #include "core/hle/kernel/shared_memory.h" | ||
| 15 | #include "core/hle/service/hid/hid.h" | ||
| 16 | #include "core/hle/service/gsp_gpu.h" | ||
| 17 | #include "core/hle/result.h" | ||
| 18 | #include "core/memory.h" | ||
| 19 | |||
| 20 | #include "video_core/video_core.h" | ||
| 21 | |||
| 22 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 23 | |||
| 24 | namespace HLE { | ||
| 25 | namespace Applets { | ||
| 26 | |||
| 27 | SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) { | ||
| 28 | // Create the SharedMemory that will hold the framebuffer data | ||
| 29 | // TODO(Subv): What size should we use here? | ||
| 30 | using Kernel::MemoryPermission; | ||
| 31 | framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); | ||
| 32 | } | ||
| 33 | |||
| 34 | ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { | ||
| 35 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) { | ||
| 36 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | ||
| 37 | UNIMPLEMENTED(); | ||
| 38 | // TODO(Subv): Find the right error code | ||
| 39 | return ResultCode(-1); | ||
| 40 | } | ||
| 41 | |||
| 42 | Service::APT::MessageParameter result; | ||
| 43 | // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo | ||
| 44 | result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished); | ||
| 45 | result.data = nullptr; | ||
| 46 | result.buffer_size = 0; | ||
| 47 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 48 | result.sender_id = static_cast<u32>(id); | ||
| 49 | result.object = framebuffer_memory; | ||
| 50 | |||
| 51 | Service::APT::SendParameter(result); | ||
| 52 | return RESULT_SUCCESS; | ||
| 53 | } | ||
| 54 | |||
| 55 | ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { | ||
| 56 | ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); | ||
| 57 | |||
| 58 | memcpy(&config, parameter.data, parameter.buffer_size); | ||
| 59 | text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object); | ||
| 60 | |||
| 61 | // TODO(Subv): Verify if this is the correct behavior | ||
| 62 | memset(text_memory->GetPointer(), 0, text_memory->size); | ||
| 63 | |||
| 64 | DrawScreenKeyboard(); | ||
| 65 | |||
| 66 | started = true; | ||
| 67 | return RESULT_SUCCESS; | ||
| 68 | } | ||
| 69 | |||
| 70 | void SoftwareKeyboard::Update() { | ||
| 71 | // TODO(Subv): Handle input using the touch events from the HID module | ||
| 72 | |||
| 73 | // TODO(Subv): Remove this hardcoded text | ||
| 74 | std::u16string text = Common::UTF8ToUTF16("Citra"); | ||
| 75 | memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t)); | ||
| 76 | |||
| 77 | // TODO(Subv): Ask for input and write it to the shared memory | ||
| 78 | // TODO(Subv): Find out what are the possible values for the return code, | ||
| 79 | // some games seem to check for a hardcoded 2 | ||
| 80 | config.return_code = 2; | ||
| 81 | config.text_length = 6; | ||
| 82 | config.text_offset = 0; | ||
| 83 | |||
| 84 | // TODO(Subv): We're finalizing the applet immediately after it's started, | ||
| 85 | // but we should defer this call until after all the input has been collected. | ||
| 86 | Finalize(); | ||
| 87 | } | ||
| 88 | |||
| 89 | void SoftwareKeyboard::DrawScreenKeyboard() { | ||
| 90 | auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1); | ||
| 91 | auto info = bottom_screen->framebuffer_info[bottom_screen->index]; | ||
| 92 | |||
| 93 | // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer | ||
| 94 | memset(Memory::GetPointer(info.address_left), 0, info.stride * 320); | ||
| 95 | |||
| 96 | GSP_GPU::SetBufferSwap(1, info); | ||
| 97 | } | ||
| 98 | |||
| 99 | void SoftwareKeyboard::Finalize() { | ||
| 100 | // Let the application know that we're closing | ||
| 101 | Service::APT::MessageParameter message; | ||
| 102 | message.buffer_size = sizeof(SoftwareKeyboardConfig); | ||
| 103 | message.data = reinterpret_cast<u8*>(&config); | ||
| 104 | message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed); | ||
| 105 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 106 | message.sender_id = static_cast<u32>(id); | ||
| 107 | Service::APT::SendParameter(message); | ||
| 108 | |||
| 109 | started = false; | ||
| 110 | } | ||
| 111 | |||
| 112 | } | ||
| 113 | } // namespace | ||
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h new file mode 100644 index 000000000..cb95b8d90 --- /dev/null +++ b/src/core/hle/applets/swkbd.h | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | |||
| 10 | #include "core/hle/applets/applet.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/shared_memory.h" | ||
| 13 | #include "core/hle/result.h" | ||
| 14 | #include "core/hle/service/apt/apt.h" | ||
| 15 | |||
| 16 | namespace HLE { | ||
| 17 | namespace Applets { | ||
| 18 | |||
| 19 | struct SoftwareKeyboardConfig { | ||
| 20 | INSERT_PADDING_WORDS(0x8); | ||
| 21 | |||
| 22 | u16 max_text_length; ///< Maximum length of the input text | ||
| 23 | |||
| 24 | INSERT_PADDING_BYTES(0x6E); | ||
| 25 | |||
| 26 | char16_t display_text[65]; ///< Text to display when asking the user for input | ||
| 27 | |||
| 28 | INSERT_PADDING_BYTES(0xE); | ||
| 29 | |||
| 30 | u32 default_text_offset; ///< Offset of the default text in the output SharedMemory | ||
| 31 | |||
| 32 | INSERT_PADDING_WORDS(0x3); | ||
| 33 | |||
| 34 | u32 shared_memory_size; ///< Size of the SharedMemory | ||
| 35 | |||
| 36 | INSERT_PADDING_WORDS(0x1); | ||
| 37 | |||
| 38 | u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown | ||
| 39 | |||
| 40 | INSERT_PADDING_WORDS(0x2); | ||
| 41 | |||
| 42 | u32 text_offset; ///< Offset in the SharedMemory where the output text starts | ||
| 43 | u16 text_length; ///< Length in characters of the output text | ||
| 44 | |||
| 45 | INSERT_PADDING_BYTES(0x2B6); | ||
| 46 | }; | ||
| 47 | |||
| 48 | /** | ||
| 49 | * The size of this structure (0x400) has been verified via reverse engineering of multiple games | ||
| 50 | * that use the software keyboard. | ||
| 51 | */ | ||
| 52 | static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); | ||
| 53 | |||
| 54 | class SoftwareKeyboard final : public Applet { | ||
| 55 | public: | ||
| 56 | SoftwareKeyboard(Service::APT::AppletId id); | ||
| 57 | ~SoftwareKeyboard() {} | ||
| 58 | |||
| 59 | ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||
| 60 | ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||
| 61 | void Update() override; | ||
| 62 | bool IsRunning() const override { return started; } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Draws a keyboard to the current bottom screen framebuffer. | ||
| 66 | */ | ||
| 67 | void DrawScreenKeyboard(); | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Sends the LibAppletClosing signal to the application, | ||
| 71 | * along with the relevant data buffers. | ||
| 72 | */ | ||
| 73 | void Finalize(); | ||
| 74 | |||
| 75 | /// TODO(Subv): Find out what this is actually used for. | ||
| 76 | /// It is believed that the application stores the current screen image here. | ||
| 77 | Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||
| 78 | |||
| 79 | /// SharedMemory where the output text will be stored | ||
| 80 | Kernel::SharedPtr<Kernel::SharedMemory> text_memory; | ||
| 81 | |||
| 82 | /// Configuration of this instance of the SoftwareKeyboard, as received from the application | ||
| 83 | SoftwareKeyboardConfig config; | ||
| 84 | |||
| 85 | /// Whether this applet is currently running instead of the host application or not. | ||
| 86 | bool started; | ||
| 87 | }; | ||
| 88 | |||
| 89 | } | ||
| 90 | } // namespace | ||
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 5949cb470..1a0518926 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -87,8 +87,28 @@ template<ResultCode func(u32, s64)> void Wrap() { | |||
| 87 | } | 87 | } |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | template<ResultCode func(void*, void*, u32)> void Wrap(){ | 90 | template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() { |
| 91 | FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw); | 91 | MemoryInfo memory_info = {}; |
| 92 | PageInfo page_info = {}; | ||
| 93 | u32 retval = func(&memory_info, &page_info, PARAM(2)).raw; | ||
| 94 | Core::g_app_core->SetReg(1, memory_info.base_address); | ||
| 95 | Core::g_app_core->SetReg(2, memory_info.size); | ||
| 96 | Core::g_app_core->SetReg(3, memory_info.permission); | ||
| 97 | Core::g_app_core->SetReg(4, memory_info.state); | ||
| 98 | Core::g_app_core->SetReg(5, page_info.flags); | ||
| 99 | FuncReturn(retval); | ||
| 100 | } | ||
| 101 | |||
| 102 | template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() { | ||
| 103 | MemoryInfo memory_info = {}; | ||
| 104 | PageInfo page_info = {}; | ||
| 105 | u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw; | ||
| 106 | Core::g_app_core->SetReg(1, memory_info.base_address); | ||
| 107 | Core::g_app_core->SetReg(2, memory_info.size); | ||
| 108 | Core::g_app_core->SetReg(3, memory_info.permission); | ||
| 109 | Core::g_app_core->SetReg(4, memory_info.state); | ||
| 110 | Core::g_app_core->SetReg(5, page_info.flags); | ||
| 111 | FuncReturn(retval); | ||
| 92 | } | 112 | } |
| 93 | 113 | ||
| 94 | template<ResultCode func(s32*, u32)> void Wrap(){ | 114 | template<ResultCode func(s32*, u32)> void Wrap(){ |
| @@ -113,7 +133,7 @@ template<ResultCode func(u32)> void Wrap() { | |||
| 113 | FuncReturn(func(PARAM(0)).raw); | 133 | FuncReturn(func(PARAM(0)).raw); |
| 114 | } | 134 | } |
| 115 | 135 | ||
| 116 | template<ResultCode func(s64*, u32, u32*, s32)> void Wrap(){ | 136 | template<ResultCode func(s64*, u32, u32*, u32)> void Wrap(){ |
| 117 | FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)), | 137 | FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)), |
| 118 | (s32)PARAM(3)).raw); | 138 | (s32)PARAM(3)).raw); |
| 119 | } | 139 | } |
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index fdeb9a028..cd0a400dc 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "core/hle/hle.h" | 10 | #include "core/hle/hle.h" |
| 11 | #include "core/hle/config_mem.h" | 11 | #include "core/hle/config_mem.h" |
| 12 | #include "core/hle/shared_page.h" | 12 | #include "core/hle/shared_page.h" |
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 15 | 14 | ||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index f338f3266..53feebbc0 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -21,7 +21,7 @@ SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { | |||
| 21 | SharedPtr<Event> evt(new Event); | 21 | SharedPtr<Event> evt(new Event); |
| 22 | 22 | ||
| 23 | evt->signaled = false; | 23 | evt->signaled = false; |
| 24 | evt->reset_type = evt->intitial_reset_type = reset_type; | 24 | evt->reset_type = reset_type; |
| 25 | evt->name = std::move(name); | 25 | evt->name = std::move(name); |
| 26 | 26 | ||
| 27 | return evt; | 27 | return evt; |
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index fba960d2a..89d405236 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h | |||
| @@ -26,7 +26,6 @@ public: | |||
| 26 | static const HandleType HANDLE_TYPE = HandleType::Event; | 26 | static const HandleType HANDLE_TYPE = HandleType::Event; |
| 27 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 27 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 28 | 28 | ||
| 29 | ResetType intitial_reset_type; ///< ResetType specified at Event initialization | ||
| 30 | ResetType reset_type; ///< Current ResetType | 29 | ResetType reset_type; ///< Current ResetType |
| 31 | 30 | ||
| 32 | bool signaled; ///< Whether the event has already been signaled | 31 | bool signaled; ///< Whether the event has already been signaled |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 20e11da16..5711c0405 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -7,8 +7,6 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | 9 | ||
| 10 | #include "core/arm/arm_interface.h" | ||
| 11 | #include "core/core.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/resource_limit.h" | 11 | #include "core/hle/kernel/resource_limit.h" |
| 14 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 64595f758..4d4276f7a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -4,10 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <boost/intrusive_ptr.hpp> | 7 | #include <boost/smart_ptr/intrusive_ptr.hpp> |
| 8 | 8 | ||
| 9 | #include <algorithm> | ||
| 9 | #include <array> | 10 | #include <array> |
| 10 | #include <memory> | 11 | #include <cstddef> |
| 11 | #include <string> | 12 | #include <string> |
| 12 | #include <vector> | 13 | #include <vector> |
| 13 | 14 | ||
| @@ -16,8 +17,6 @@ | |||
| 16 | #include "core/hle/hle.h" | 17 | #include "core/hle/hle.h" |
| 17 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| 18 | 19 | ||
| 19 | struct ApplicationInfo; | ||
| 20 | |||
| 21 | namespace Kernel { | 20 | namespace Kernel { |
| 22 | 21 | ||
| 23 | class Thread; | 22 | class Thread; |
| @@ -48,6 +47,7 @@ enum class HandleType : u32 { | |||
| 48 | Semaphore = 10, | 47 | Semaphore = 10, |
| 49 | Timer = 11, | 48 | Timer = 11, |
| 50 | ResourceLimit = 12, | 49 | ResourceLimit = 12, |
| 50 | CodeSet = 13, | ||
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | enum { | 53 | enum { |
| @@ -86,6 +86,7 @@ public: | |||
| 86 | case HandleType::Process: | 86 | case HandleType::Process: |
| 87 | case HandleType::AddressArbiter: | 87 | case HandleType::AddressArbiter: |
| 88 | case HandleType::ResourceLimit: | 88 | case HandleType::ResourceLimit: |
| 89 | case HandleType::CodeSet: | ||
| 89 | return false; | 90 | return false; |
| 90 | } | 91 | } |
| 91 | } | 92 | } |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b0e75ba59..a7892c652 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -5,24 +5,39 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/common_funcs.h" | 6 | #include "common/common_funcs.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "common/make_unique.h" | ||
| 8 | 9 | ||
| 9 | #include "core/hle/kernel/process.h" | 10 | #include "core/hle/kernel/process.h" |
| 10 | #include "core/hle/kernel/resource_limit.h" | 11 | #include "core/hle/kernel/resource_limit.h" |
| 11 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 13 | #include "core/hle/kernel/vm_manager.h" | ||
| 14 | #include "core/mem_map.h" | ||
| 12 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 13 | 16 | ||
| 14 | namespace Kernel { | 17 | namespace Kernel { |
| 15 | 18 | ||
| 19 | SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) { | ||
| 20 | SharedPtr<CodeSet> codeset(new CodeSet); | ||
| 21 | |||
| 22 | codeset->name = std::move(name); | ||
| 23 | codeset->program_id = program_id; | ||
| 24 | |||
| 25 | return codeset; | ||
| 26 | } | ||
| 27 | |||
| 28 | CodeSet::CodeSet() {} | ||
| 29 | CodeSet::~CodeSet() {} | ||
| 30 | |||
| 16 | u32 Process::next_process_id; | 31 | u32 Process::next_process_id; |
| 17 | 32 | ||
| 18 | SharedPtr<Process> Process::Create(std::string name, u64 program_id) { | 33 | SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) { |
| 19 | SharedPtr<Process> process(new Process); | 34 | SharedPtr<Process> process(new Process); |
| 20 | 35 | ||
| 21 | process->name = std::move(name); | 36 | process->codeset = std::move(code_set); |
| 22 | process->program_id = program_id; | ||
| 23 | |||
| 24 | process->flags.raw = 0; | 37 | process->flags.raw = 0; |
| 25 | process->flags.memory_region = MemoryRegion::APPLICATION; | 38 | process->flags.memory_region = MemoryRegion::APPLICATION; |
| 39 | process->address_space = Common::make_unique<VMManager>(); | ||
| 40 | Memory::InitLegacyAddressSpace(*process->address_space); | ||
| 26 | 41 | ||
| 27 | return process; | 42 | return process; |
| 28 | } | 43 | } |
| @@ -87,8 +102,19 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 87 | } | 102 | } |
| 88 | } | 103 | } |
| 89 | 104 | ||
| 90 | void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | 105 | void Process::Run(s32 main_thread_priority, u32 stack_size) { |
| 91 | Kernel::SetupMainThread(entry_point, main_thread_priority); | 106 | auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { |
| 107 | auto vma = address_space->MapMemoryBlock(segment.addr, codeset->memory, | ||
| 108 | segment.offset, segment.size, memory_state).Unwrap(); | ||
| 109 | address_space->Reprotect(vma, permissions); | ||
| 110 | }; | ||
| 111 | |||
| 112 | MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code); | ||
| 113 | MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code); | ||
| 114 | MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private); | ||
| 115 | |||
| 116 | address_space->LogLayout(); | ||
| 117 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); | ||
| 92 | } | 118 | } |
| 93 | 119 | ||
| 94 | Kernel::Process::Process() {} | 120 | Kernel::Process::Process() {} |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 7b8a68610..83d3aceae 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -5,6 +5,9 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <bitset> | 7 | #include <bitset> |
| 8 | #include <cstddef> | ||
| 9 | #include <memory> | ||
| 10 | #include <string> | ||
| 8 | 11 | ||
| 9 | #include <boost/container/static_vector.hpp> | 12 | #include <boost/container/static_vector.hpp> |
| 10 | 13 | ||
| @@ -12,7 +15,6 @@ | |||
| 12 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 13 | 16 | ||
| 14 | #include "core/hle/kernel/kernel.h" | 17 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/result.h" | ||
| 16 | 18 | ||
| 17 | namespace Kernel { | 19 | namespace Kernel { |
| 18 | 20 | ||
| @@ -46,23 +48,51 @@ union ProcessFlags { | |||
| 46 | }; | 48 | }; |
| 47 | 49 | ||
| 48 | class ResourceLimit; | 50 | class ResourceLimit; |
| 51 | class VMManager; | ||
| 52 | |||
| 53 | struct CodeSet final : public Object { | ||
| 54 | static SharedPtr<CodeSet> Create(std::string name, u64 program_id); | ||
| 55 | |||
| 56 | std::string GetTypeName() const override { return "CodeSet"; } | ||
| 57 | std::string GetName() const override { return name; } | ||
| 58 | |||
| 59 | static const HandleType HANDLE_TYPE = HandleType::CodeSet; | ||
| 60 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 61 | |||
| 62 | /// Name of the process | ||
| 63 | std::string name; | ||
| 64 | /// Title ID corresponding to the process | ||
| 65 | u64 program_id; | ||
| 66 | |||
| 67 | std::shared_ptr<std::vector<u8>> memory; | ||
| 68 | |||
| 69 | struct Segment { | ||
| 70 | size_t offset = 0; | ||
| 71 | VAddr addr = 0; | ||
| 72 | u32 size = 0; | ||
| 73 | }; | ||
| 74 | |||
| 75 | Segment code, rodata, data; | ||
| 76 | VAddr entrypoint; | ||
| 77 | |||
| 78 | private: | ||
| 79 | CodeSet(); | ||
| 80 | ~CodeSet() override; | ||
| 81 | }; | ||
| 49 | 82 | ||
| 50 | class Process final : public Object { | 83 | class Process final : public Object { |
| 51 | public: | 84 | public: |
| 52 | static SharedPtr<Process> Create(std::string name, u64 program_id); | 85 | static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set); |
| 53 | 86 | ||
| 54 | std::string GetTypeName() const override { return "Process"; } | 87 | std::string GetTypeName() const override { return "Process"; } |
| 55 | std::string GetName() const override { return name; } | 88 | std::string GetName() const override { return codeset->name; } |
| 56 | 89 | ||
| 57 | static const HandleType HANDLE_TYPE = HandleType::Process; | 90 | static const HandleType HANDLE_TYPE = HandleType::Process; |
| 58 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 91 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 59 | 92 | ||
| 60 | static u32 next_process_id; | 93 | static u32 next_process_id; |
| 61 | 94 | ||
| 62 | /// Name of the process | 95 | SharedPtr<CodeSet> codeset; |
| 63 | std::string name; | ||
| 64 | /// Title ID corresponding to the process | ||
| 65 | u64 program_id; | ||
| 66 | /// Resource limit descriptor for this process | 96 | /// Resource limit descriptor for this process |
| 67 | SharedPtr<ResourceLimit> resource_limit; | 97 | SharedPtr<ResourceLimit> resource_limit; |
| 68 | 98 | ||
| @@ -80,6 +110,7 @@ public: | |||
| 80 | 110 | ||
| 81 | /// Bitmask of the used TLS slots | 111 | /// Bitmask of the used TLS slots |
| 82 | std::bitset<300> used_tls_slots; | 112 | std::bitset<300> used_tls_slots; |
| 113 | std::unique_ptr<VMManager> address_space; | ||
| 83 | 114 | ||
| 84 | /** | 115 | /** |
| 85 | * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them | 116 | * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them |
| @@ -90,7 +121,7 @@ public: | |||
| 90 | /** | 121 | /** |
| 91 | * Applies address space changes and launches the process main thread. | 122 | * Applies address space changes and launches the process main thread. |
| 92 | */ | 123 | */ |
| 93 | void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size); | 124 | void Run(s32 main_thread_priority, u32 stack_size); |
| 94 | 125 | ||
| 95 | private: | 126 | private: |
| 96 | Process(); | 127 | Process(); |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 257da9105..adaffcafe 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -4,8 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 7 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/thread.h" | 13 | #include "core/hle/kernel/thread.h" |
| 14 | #include "core/hle/result.h" | ||
| 9 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 10 | 16 | ||
| 11 | namespace IPC { | 17 | namespace IPC { |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 204266896..7a2922776 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -4,9 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/result.h" | ||
| 10 | 13 | ||
| 11 | namespace Kernel { | 14 | namespace Kernel { |
| 12 | 15 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 4729a7fe0..29ea6d531 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #include "common/thread_queue_list.h" | 13 | #include "common/thread_queue_list.h" |
| 14 | 14 | ||
| 15 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/arm/skyeye_common/armdefs.h" | 16 | #include "core/arm/skyeye_common/armstate.h" |
| 17 | #include "core/core.h" | 17 | #include "core/core.h" |
| 18 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 19 | #include "core/hle/hle.h" | 19 | #include "core/hle/hle.h" |
| @@ -37,6 +37,10 @@ void Thread::Acquire() { | |||
| 37 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | 37 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing | ||
| 41 | // us to simply use a pool index or similar. | ||
| 42 | static Kernel::HandleTable wakeup_callback_handle_table; | ||
| 43 | |||
| 40 | // Lists all thread ids that aren't deleted/etc. | 44 | // Lists all thread ids that aren't deleted/etc. |
| 41 | static std::vector<SharedPtr<Thread>> thread_list; | 45 | static std::vector<SharedPtr<Thread>> thread_list; |
| 42 | 46 | ||
| @@ -93,6 +97,8 @@ void Thread::Stop() { | |||
| 93 | 97 | ||
| 94 | // Cancel any outstanding wakeup events for this thread | 98 | // Cancel any outstanding wakeup events for this thread |
| 95 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | 99 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); |
| 100 | wakeup_callback_handle_table.Close(callback_handle); | ||
| 101 | callback_handle = 0; | ||
| 96 | 102 | ||
| 97 | // Clean up thread from ready queue | 103 | // Clean up thread from ready queue |
| 98 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) | 104 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) |
| @@ -108,6 +114,7 @@ void Thread::Stop() { | |||
| 108 | for (auto& wait_object : wait_objects) { | 114 | for (auto& wait_object : wait_objects) { |
| 109 | wait_object->RemoveWaitingThread(this); | 115 | wait_object->RemoveWaitingThread(this); |
| 110 | } | 116 | } |
| 117 | wait_objects.clear(); | ||
| 111 | 118 | ||
| 112 | Kernel::g_current_process->used_tls_slots[tls_index] = false; | 119 | Kernel::g_current_process->used_tls_slots[tls_index] = false; |
| 113 | 120 | ||
| @@ -210,6 +217,14 @@ static void SwitchContext(Thread* new_thread) { | |||
| 210 | new_thread->context.pc -= thumb_mode ? 2 : 4; | 217 | new_thread->context.pc -= thumb_mode ? 2 : 4; |
| 211 | } | 218 | } |
| 212 | 219 | ||
| 220 | // Clean up the thread's wait_objects, they'll be restored if needed during | ||
| 221 | // the svcWaitSynchronization call | ||
| 222 | for (int i = 0; i < new_thread->wait_objects.size(); ++i) { | ||
| 223 | SharedPtr<WaitObject> object = new_thread->wait_objects[i]; | ||
| 224 | object->RemoveWaitingThread(new_thread); | ||
| 225 | } | ||
| 226 | new_thread->wait_objects.clear(); | ||
| 227 | |||
| 213 | ready_queue.remove(new_thread->current_priority, new_thread); | 228 | ready_queue.remove(new_thread->current_priority, new_thread); |
| 214 | new_thread->status = THREADSTATUS_RUNNING; | 229 | new_thread->status = THREADSTATUS_RUNNING; |
| 215 | 230 | ||
| @@ -268,10 +283,6 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { | |||
| 268 | thread->status = THREADSTATUS_WAIT_ARB; | 283 | thread->status = THREADSTATUS_WAIT_ARB; |
| 269 | } | 284 | } |
| 270 | 285 | ||
| 271 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing | ||
| 272 | // us to simply use a pool index or similar. | ||
| 273 | static Kernel::HandleTable wakeup_callback_handle_table; | ||
| 274 | |||
| 275 | /** | 286 | /** |
| 276 | * Callback that will wake up the thread it was scheduled for | 287 | * Callback that will wake up the thread it was scheduled for |
| 277 | * @param thread_handle The handle of the thread that's been awoken | 288 | * @param thread_handle The handle of the thread that's been awoken |
| @@ -503,12 +514,16 @@ void ThreadingInit() { | |||
| 503 | 514 | ||
| 504 | current_thread = nullptr; | 515 | current_thread = nullptr; |
| 505 | next_thread_id = 1; | 516 | next_thread_id = 1; |
| 506 | |||
| 507 | thread_list.clear(); | ||
| 508 | ready_queue.clear(); | ||
| 509 | } | 517 | } |
| 510 | 518 | ||
| 511 | void ThreadingShutdown() { | 519 | void ThreadingShutdown() { |
| 520 | current_thread = nullptr; | ||
| 521 | |||
| 522 | for (auto& t : thread_list) { | ||
| 523 | t->Stop(); | ||
| 524 | } | ||
| 525 | thread_list.clear(); | ||
| 526 | ready_queue.clear(); | ||
| 512 | } | 527 | } |
| 513 | 528 | ||
| 514 | } // namespace | 529 | } // namespace |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index b8160bb2c..1ff1d9b97 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | 15 | ||
| 16 | #include "core/hle/hle.h" | ||
| 16 | #include "core/hle/kernel/kernel.h" | 17 | #include "core/hle/kernel/kernel.h" |
| 17 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| 18 | 19 | ||
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index b2dd21542..205cc7b53 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 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 <iterator> | ||
| 6 | |||
| 5 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 6 | 8 | ||
| 7 | #include "core/hle/kernel/vm_manager.h" | 9 | #include "core/hle/kernel/vm_manager.h" |
| @@ -33,6 +35,10 @@ VMManager::VMManager() { | |||
| 33 | Reset(); | 35 | Reset(); |
| 34 | } | 36 | } |
| 35 | 37 | ||
| 38 | VMManager::~VMManager() { | ||
| 39 | Reset(); | ||
| 40 | } | ||
| 41 | |||
| 36 | void VMManager::Reset() { | 42 | void VMManager::Reset() { |
| 37 | vma_map.clear(); | 43 | vma_map.clear(); |
| 38 | 44 | ||
| @@ -128,6 +134,16 @@ void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) { | |||
| 128 | MergeAdjacent(iter); | 134 | MergeAdjacent(iter); |
| 129 | } | 135 | } |
| 130 | 136 | ||
| 137 | void VMManager::LogLayout() const { | ||
| 138 | for (const auto& p : vma_map) { | ||
| 139 | const VirtualMemoryArea& vma = p.second; | ||
| 140 | LOG_DEBUG(Kernel, "%08X - %08X size: %8X %c%c%c", vma.base, vma.base + vma.size, vma.size, | ||
| 141 | (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', | ||
| 142 | (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', | ||
| 143 | (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-'); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 131 | VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { | 147 | VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { |
| 132 | // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given | 148 | // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given |
| 133 | // non-const access to its container. | 149 | // non-const access to its container. |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 22b724603..b3795a94a 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <map> | 7 | #include <map> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string> | ||
| 10 | #include <vector> | 9 | #include <vector> |
| 11 | 10 | ||
| 12 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| @@ -102,7 +101,7 @@ struct VirtualMemoryArea { | |||
| 102 | * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ | 101 | * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ |
| 103 | * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ | 102 | * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ |
| 104 | */ | 103 | */ |
| 105 | class VMManager { | 104 | class VMManager final { |
| 106 | // TODO(yuriks): Make page tables switchable to support multiple VMManagers | 105 | // TODO(yuriks): Make page tables switchable to support multiple VMManagers |
| 107 | public: | 106 | public: |
| 108 | /** | 107 | /** |
| @@ -122,6 +121,7 @@ public: | |||
| 122 | using VMAHandle = decltype(vma_map)::const_iterator; | 121 | using VMAHandle = decltype(vma_map)::const_iterator; |
| 123 | 122 | ||
| 124 | VMManager(); | 123 | VMManager(); |
| 124 | ~VMManager(); | ||
| 125 | 125 | ||
| 126 | /// Clears the address space map, re-initializing with a single free area. | 126 | /// Clears the address space map, re-initializing with a single free area. |
| 127 | void Reset(); | 127 | void Reset(); |
| @@ -169,6 +169,9 @@ public: | |||
| 169 | /// Changes the permissions of the given VMA. | 169 | /// Changes the permissions of the given VMA. |
| 170 | void Reprotect(VMAHandle vma, VMAPermission new_perms); | 170 | void Reprotect(VMAHandle vma, VMAPermission new_perms); |
| 171 | 171 | ||
| 172 | /// Dumps the address space layout to the log, for debugging | ||
| 173 | void LogLayout() const; | ||
| 174 | |||
| 172 | private: | 175 | private: |
| 173 | using VMAIter = decltype(vma_map)::iterator; | 176 | using VMAIter = decltype(vma_map)::iterator; |
| 174 | 177 | ||
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index ce633d841..cb2d681e0 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <new> |
| 8 | #include <type_traits> | 8 | #include <type_traits> |
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | 10 | ||
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 57dc1ece7..7332478fb 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -38,6 +38,15 @@ void GetTitleIDList(Service::Interface* self) { | |||
| 38 | LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); | 38 | LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void GetNumContentInfos(Service::Interface* self) { | ||
| 42 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 43 | |||
| 44 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 45 | cmd_buff[2] = 1; // Number of content infos plus one | ||
| 46 | |||
| 47 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 48 | } | ||
| 49 | |||
| 41 | void Init() { | 50 | void Init() { |
| 42 | using namespace Kernel; | 51 | using namespace Kernel; |
| 43 | 52 | ||
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 063b8bd09..0b78f5393 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -37,6 +37,19 @@ void TitleIDListGetTotal(Service::Interface* self); | |||
| 37 | */ | 37 | */ |
| 38 | void GetTitleIDList(Service::Interface* self); | 38 | void GetTitleIDList(Service::Interface* self); |
| 39 | 39 | ||
| 40 | /** | ||
| 41 | * AM::GetNumContentInfos service function | ||
| 42 | * Inputs: | ||
| 43 | * 0 : Command header (0x100100C0) | ||
| 44 | * 1 : Unknown | ||
| 45 | * 2 : Unknown | ||
| 46 | * 3 : Unknown | ||
| 47 | * Outputs: | ||
| 48 | * 1 : Result, 0 on success, otherwise error code | ||
| 49 | * 2 : Number of content infos plus one | ||
| 50 | */ | ||
| 51 | void GetNumContentInfos(Service::Interface* self); | ||
| 52 | |||
| 40 | /// Initialize AM service | 53 | /// Initialize AM service |
| 41 | void Init(); | 54 | void Init(); |
| 42 | 55 | ||
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp index c6fc81bc3..f40a87cb4 100644 --- a/src/core/hle/service/am/am_app.cpp +++ b/src/core/hle/service/am/am_app.cpp | |||
| @@ -9,11 +9,19 @@ | |||
| 9 | namespace Service { | 9 | namespace Service { |
| 10 | namespace AM { | 10 | namespace AM { |
| 11 | 11 | ||
| 12 | // Empty arrays are illegal -- commented out until an entry is added. | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | //const Interface::FunctionInfo FunctionTable[] = { }; | 13 | {0x100100C0, GetNumContentInfos, "GetNumContentInfos"}, |
| 14 | {0x10020104, nullptr, "FindContentInfos"}, | ||
| 15 | {0x10030142, nullptr, "ListContentInfos"}, | ||
| 16 | {0x10040102, nullptr, "DeleteContents"}, | ||
| 17 | {0x10050084, nullptr, "GetDataTitleInfos"}, | ||
| 18 | {0x10070102, nullptr, "ListDataTitleTicketInfos"}, | ||
| 19 | {0x100900C0, nullptr, "IsDataTitleInUse"}, | ||
| 20 | {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, | ||
| 21 | }; | ||
| 14 | 22 | ||
| 15 | AM_APP_Interface::AM_APP_Interface() { | 23 | AM_APP_Interface::AM_APP_Interface() { |
| 16 | //Register(FunctionTable); | 24 | Register(FunctionTable); |
| 17 | } | 25 | } |
| 18 | 26 | ||
| 19 | } // namespace AM | 27 | } // namespace AM |
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index b454a2709..7b6ab4ce0 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/file_util.h" | 6 | #include "common/file_util.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | 8 | ||
| 9 | #include "core/hle/applets/applet.h" | ||
| 9 | #include "core/hle/service/service.h" | 10 | #include "core/hle/service/service.h" |
| 10 | #include "core/hle/service/apt/apt.h" | 11 | #include "core/hle/service/apt/apt.h" |
| 11 | #include "core/hle/service/apt/apt_a.h" | 12 | #include "core/hle/service/apt/apt_a.h" |
| @@ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | |||
| 34 | 35 | ||
| 35 | static Kernel::SharedPtr<Kernel::Mutex> lock; | 36 | static Kernel::SharedPtr<Kernel::Mutex> lock; |
| 36 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event | 37 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event |
| 37 | static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event | 38 | static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event |
| 38 | 39 | ||
| 39 | static std::vector<u8> shared_font; | 40 | static std::vector<u8> shared_font; |
| 40 | 41 | ||
| 41 | static u32 cpu_percent; ///< CPU time available to the running application | 42 | static u32 cpu_percent; ///< CPU time available to the running application |
| 42 | 43 | ||
| 44 | /// Parameter data to be returned in the next call to Glance/ReceiveParameter | ||
| 45 | static MessageParameter next_parameter; | ||
| 46 | |||
| 47 | void SendParameter(const MessageParameter& parameter) { | ||
| 48 | next_parameter = parameter; | ||
| 49 | // Signal the event to let the application know that a new parameter is ready to be read | ||
| 50 | parameter_event->Signal(); | ||
| 51 | } | ||
| 52 | |||
| 43 | void Initialize(Service::Interface* self) { | 53 | void Initialize(Service::Interface* self) { |
| 44 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 54 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 45 | u32 app_id = cmd_buff[1]; | 55 | u32 app_id = cmd_buff[1]; |
| @@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) { | |||
| 47 | 57 | ||
| 48 | cmd_buff[2] = IPC::MoveHandleDesc(2); | 58 | cmd_buff[2] = IPC::MoveHandleDesc(2); |
| 49 | cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); | 59 | cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); |
| 50 | cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom(); | 60 | cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom(); |
| 51 | 61 | ||
| 52 | // TODO(bunnei): Check if these events are cleared every time Initialize is called. | 62 | // TODO(bunnei): Check if these events are cleared every time Initialize is called. |
| 53 | notification_event->Clear(); | 63 | notification_event->Clear(); |
| 54 | start_event->Clear(); | 64 | parameter_event->Clear(); |
| 55 | 65 | ||
| 56 | ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); | 66 | ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); |
| 57 | lock->Release(); | 67 | lock->Release(); |
| 58 | 68 | ||
| 59 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 69 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 60 | 70 | ||
| 61 | LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); | 71 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); |
| 62 | } | 72 | } |
| 63 | 73 | ||
| 64 | void GetSharedFont(Service::Interface* self) { | 74 | void GetSharedFont(Service::Interface* self) { |
| @@ -85,9 +95,6 @@ void GetSharedFont(Service::Interface* self) { | |||
| 85 | void NotifyToWait(Service::Interface* self) { | 95 | void NotifyToWait(Service::Interface* self) { |
| 86 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 96 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 87 | u32 app_id = cmd_buff[1]; | 97 | u32 app_id = cmd_buff[1]; |
| 88 | // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. | ||
| 89 | start_event->Signal(); | ||
| 90 | |||
| 91 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 98 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 92 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | 99 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |
| 93 | } | 100 | } |
| @@ -100,7 +107,7 @@ void GetLockHandle(Service::Interface* self) { | |||
| 100 | 107 | ||
| 101 | // Not sure what these parameters are used for, but retail apps check that they are 0 after | 108 | // Not sure what these parameters are used for, but retail apps check that they are 0 after |
| 102 | // GetLockHandle has been called. | 109 | // GetLockHandle has been called. |
| 103 | cmd_buff[2] = 0; | 110 | cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable. |
| 104 | cmd_buff[3] = 0; | 111 | cmd_buff[3] = 0; |
| 105 | cmd_buff[4] = 0; | 112 | cmd_buff[4] = 0; |
| 106 | 113 | ||
| @@ -110,9 +117,10 @@ void GetLockHandle(Service::Interface* self) { | |||
| 110 | 117 | ||
| 111 | void Enable(Service::Interface* self) { | 118 | void Enable(Service::Interface* self) { |
| 112 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 119 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 113 | u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? | 120 | u32 attributes = cmd_buff[1]; |
| 114 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 121 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 115 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | 122 | parameter_event->Signal(); // Let the application know that it has been started |
| 123 | LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); | ||
| 116 | } | 124 | } |
| 117 | 125 | ||
| 118 | void GetAppletManInfo(Service::Interface* self) { | 126 | void GetAppletManInfo(Service::Interface* self) { |
| @@ -121,8 +129,8 @@ void GetAppletManInfo(Service::Interface* self) { | |||
| 121 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 129 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 122 | cmd_buff[2] = 0; | 130 | cmd_buff[2] = 0; |
| 123 | cmd_buff[3] = 0; | 131 | cmd_buff[3] = 0; |
| 124 | cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID | 132 | cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID |
| 125 | cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly | 133 | cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly |
| 126 | 134 | ||
| 127 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | 135 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); |
| 128 | } | 136 | } |
| @@ -131,7 +139,13 @@ void IsRegistered(Service::Interface* self) { | |||
| 131 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 139 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 132 | u32 app_id = cmd_buff[1]; | 140 | u32 app_id = cmd_buff[1]; |
| 133 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 141 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 134 | cmd_buff[2] = 1; // Set to registered | 142 | /// TODO(Subv): It is currently unknown what this value (0x400) means, |
| 143 | /// but i believe it is used as a global "LibraryApplet" id, to verify if there's | ||
| 144 | /// any LibApplet currently running. This is not verified. | ||
| 145 | if (app_id != 0x400) | ||
| 146 | cmd_buff[2] = 1; // Set to registered | ||
| 147 | else | ||
| 148 | cmd_buff[2] = 0; // Set to not registered | ||
| 135 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | 149 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |
| 136 | } | 150 | } |
| 137 | 151 | ||
| @@ -145,50 +159,82 @@ void InquireNotification(Service::Interface* self) { | |||
| 145 | 159 | ||
| 146 | void SendParameter(Service::Interface* self) { | 160 | void SendParameter(Service::Interface* self) { |
| 147 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 161 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 148 | u32 src_app_id = cmd_buff[1]; | 162 | u32 src_app_id = cmd_buff[1]; |
| 149 | u32 dst_app_id = cmd_buff[2]; | 163 | u32 dst_app_id = cmd_buff[2]; |
| 150 | u32 signal_type = cmd_buff[3]; | 164 | u32 signal_type = cmd_buff[3]; |
| 151 | u32 buffer_size = cmd_buff[4]; | 165 | u32 buffer_size = cmd_buff[4]; |
| 152 | u32 value = cmd_buff[5]; | 166 | u32 value = cmd_buff[5]; |
| 153 | u32 handle = cmd_buff[6]; | 167 | u32 handle = cmd_buff[6]; |
| 154 | u32 size = cmd_buff[7]; | 168 | u32 size = cmd_buff[7]; |
| 155 | u32 in_param_buffer_ptr = cmd_buff[8]; | 169 | u32 buffer = cmd_buff[8]; |
| 170 | |||
| 171 | std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); | ||
| 172 | |||
| 173 | if (dest_applet == nullptr) { | ||
| 174 | LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); | ||
| 175 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | ||
| 176 | return; | ||
| 177 | } | ||
| 156 | 178 | ||
| 157 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 179 | MessageParameter param; |
| 180 | param.buffer_size = buffer_size; | ||
| 181 | param.destination_id = dst_app_id; | ||
| 182 | param.sender_id = src_app_id; | ||
| 183 | param.object = Kernel::g_handle_table.GetGeneric(handle); | ||
| 184 | param.signal = signal_type; | ||
| 185 | param.data = Memory::GetPointer(buffer); | ||
| 186 | |||
| 187 | cmd_buff[1] = dest_applet->ReceiveParameter(param).raw; | ||
| 158 | 188 | ||
| 159 | LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | 189 | LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," |
| 160 | "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", | 190 | "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", |
| 161 | src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); | 191 | src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer); |
| 162 | } | 192 | } |
| 163 | 193 | ||
| 164 | void ReceiveParameter(Service::Interface* self) { | 194 | void ReceiveParameter(Service::Interface* self) { |
| 165 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 195 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 166 | u32 app_id = cmd_buff[1]; | 196 | u32 app_id = cmd_buff[1]; |
| 167 | u32 buffer_size = cmd_buff[2]; | 197 | u32 buffer_size = cmd_buff[2]; |
| 198 | VAddr buffer = cmd_buff[0x104 >> 2]; | ||
| 199 | |||
| 168 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 200 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 169 | cmd_buff[2] = 0; | 201 | cmd_buff[2] = next_parameter.sender_id; |
| 170 | cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type | 202 | cmd_buff[3] = next_parameter.signal; // Signal type |
| 171 | cmd_buff[4] = 0x10; // Parameter buffer size (16) | 203 | cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size |
| 172 | cmd_buff[5] = 0; | 204 | cmd_buff[5] = 0x10; |
| 173 | cmd_buff[6] = 0; | 205 | cmd_buff[6] = 0; |
| 174 | cmd_buff[7] = 0; | 206 | if (next_parameter.object != nullptr) |
| 175 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 207 | cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); |
| 208 | cmd_buff[7] = (next_parameter.buffer_size << 14) | 2; | ||
| 209 | cmd_buff[8] = buffer; | ||
| 210 | |||
| 211 | if (next_parameter.data) | ||
| 212 | memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size)); | ||
| 213 | |||
| 214 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | ||
| 176 | } | 215 | } |
| 177 | 216 | ||
| 178 | void GlanceParameter(Service::Interface* self) { | 217 | void GlanceParameter(Service::Interface* self) { |
| 179 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 218 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 180 | u32 app_id = cmd_buff[1]; | 219 | u32 app_id = cmd_buff[1]; |
| 181 | u32 buffer_size = cmd_buff[2]; | 220 | u32 buffer_size = cmd_buff[2]; |
| 221 | VAddr buffer = cmd_buff[0x104 >> 2]; | ||
| 182 | 222 | ||
| 183 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 223 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 184 | cmd_buff[2] = 0; | 224 | cmd_buff[2] = next_parameter.sender_id; |
| 185 | cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type | 225 | cmd_buff[3] = next_parameter.signal; // Signal type |
| 186 | cmd_buff[4] = 0x10; // Parameter buffer size (16) | 226 | cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size |
| 187 | cmd_buff[5] = 0; | 227 | cmd_buff[5] = 0x10; |
| 188 | cmd_buff[6] = 0; | 228 | cmd_buff[6] = 0; |
| 189 | cmd_buff[7] = 0; | 229 | if (next_parameter.object != nullptr) |
| 230 | cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | ||
| 231 | cmd_buff[7] = (next_parameter.buffer_size << 14) | 2; | ||
| 232 | cmd_buff[8] = buffer; | ||
| 190 | 233 | ||
| 191 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | 234 | if (next_parameter.data) |
| 235 | memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size)); | ||
| 236 | |||
| 237 | LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | ||
| 192 | } | 238 | } |
| 193 | 239 | ||
| 194 | void CancelParameter(Service::Interface* self) { | 240 | void CancelParameter(Service::Interface* self) { |
| @@ -240,7 +286,7 @@ void AppletUtility(Service::Interface* self) { | |||
| 240 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 286 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 241 | 287 | ||
| 242 | // These are from 3dbrew - I'm not really sure what they're used for. | 288 | // These are from 3dbrew - I'm not really sure what they're used for. |
| 243 | u32 unk = cmd_buff[1]; | 289 | u32 command = cmd_buff[1]; |
| 244 | u32 buffer1_size = cmd_buff[2]; | 290 | u32 buffer1_size = cmd_buff[2]; |
| 245 | u32 buffer2_size = cmd_buff[3]; | 291 | u32 buffer2_size = cmd_buff[3]; |
| 246 | u32 buffer1_addr = cmd_buff[5]; | 292 | u32 buffer1_addr = cmd_buff[5]; |
| @@ -248,8 +294,8 @@ void AppletUtility(Service::Interface* self) { | |||
| 248 | 294 | ||
| 249 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 295 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 250 | 296 | ||
| 251 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " | 297 | LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " |
| 252 | "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size, | 298 | "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size, |
| 253 | buffer1_addr, buffer2_addr); | 299 | buffer1_addr, buffer2_addr); |
| 254 | } | 300 | } |
| 255 | 301 | ||
| @@ -281,11 +327,41 @@ void GetAppCpuTimeLimit(Service::Interface* self) { | |||
| 281 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); | 327 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); |
| 282 | } | 328 | } |
| 283 | 329 | ||
| 330 | void PrepareToStartLibraryApplet(Service::Interface* self) { | ||
| 331 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 332 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | ||
| 333 | cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; | ||
| 334 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||
| 335 | } | ||
| 336 | |||
| 337 | void StartLibraryApplet(Service::Interface* self) { | ||
| 338 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 339 | AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | ||
| 340 | std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); | ||
| 341 | |||
| 342 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||
| 343 | |||
| 344 | if (applet == nullptr) { | ||
| 345 | LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); | ||
| 346 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | ||
| 347 | return; | ||
| 348 | } | ||
| 349 | |||
| 350 | AppletStartupParameter parameter; | ||
| 351 | parameter.buffer_size = cmd_buff[2]; | ||
| 352 | parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]); | ||
| 353 | parameter.data = Memory::GetPointer(cmd_buff[6]); | ||
| 354 | |||
| 355 | cmd_buff[1] = applet->Start(parameter).raw; | ||
| 356 | } | ||
| 357 | |||
| 284 | void Init() { | 358 | void Init() { |
| 285 | AddService(new APT_A_Interface); | 359 | AddService(new APT_A_Interface); |
| 286 | AddService(new APT_S_Interface); | 360 | AddService(new APT_S_Interface); |
| 287 | AddService(new APT_U_Interface); | 361 | AddService(new APT_U_Interface); |
| 288 | 362 | ||
| 363 | HLE::Applets::Init(); | ||
| 364 | |||
| 289 | // Load the shared system font (if available). | 365 | // Load the shared system font (if available). |
| 290 | // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header | 366 | // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header |
| 291 | // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided | 367 | // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided |
| @@ -318,7 +394,10 @@ void Init() { | |||
| 318 | 394 | ||
| 319 | // TODO(bunnei): Check if these are created in Initialize or on APT process startup. | 395 | // TODO(bunnei): Check if these are created in Initialize or on APT process startup. |
| 320 | notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); | 396 | notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); |
| 321 | start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); | 397 | parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); |
| 398 | |||
| 399 | next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted); | ||
| 400 | next_parameter.destination_id = 0x300; | ||
| 322 | } | 401 | } |
| 323 | 402 | ||
| 324 | void Shutdown() { | 403 | void Shutdown() { |
| @@ -326,7 +405,11 @@ void Shutdown() { | |||
| 326 | shared_font_mem = nullptr; | 405 | shared_font_mem = nullptr; |
| 327 | lock = nullptr; | 406 | lock = nullptr; |
| 328 | notification_event = nullptr; | 407 | notification_event = nullptr; |
| 329 | start_event = nullptr; | 408 | parameter_event = nullptr; |
| 409 | |||
| 410 | next_parameter.object = nullptr; | ||
| 411 | |||
| 412 | HLE::Applets::Shutdown(); | ||
| 330 | } | 413 | } |
| 331 | 414 | ||
| 332 | } // namespace APT | 415 | } // namespace APT |
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index a03e1712a..72972d05b 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h | |||
| @@ -4,13 +4,33 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include "common/common_types.h" |
| 8 | #include "core/hle/result.h" | 8 | |
| 9 | #include "core/hle/service/service.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | 10 | ||
| 11 | namespace Service { | 11 | namespace Service { |
| 12 | |||
| 13 | class Interface; | ||
| 14 | |||
| 12 | namespace APT { | 15 | namespace APT { |
| 13 | 16 | ||
| 17 | /// Holds information about the parameters used in Send/Glance/ReceiveParameter | ||
| 18 | struct MessageParameter { | ||
| 19 | u32 sender_id = 0; | ||
| 20 | u32 destination_id = 0; | ||
| 21 | u32 signal = 0; | ||
| 22 | u32 buffer_size = 0; | ||
| 23 | Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||
| 24 | u8* data = nullptr; | ||
| 25 | }; | ||
| 26 | |||
| 27 | /// Holds information about the parameters used in StartLibraryApplet | ||
| 28 | struct AppletStartupParameter { | ||
| 29 | u32 buffer_size = 0; | ||
| 30 | Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||
| 31 | u8* data = nullptr; | ||
| 32 | }; | ||
| 33 | |||
| 14 | /// Signals used by APT functions | 34 | /// Signals used by APT functions |
| 15 | enum class SignalType : u32 { | 35 | enum class SignalType : u32 { |
| 16 | None = 0x0, | 36 | None = 0x0, |
| @@ -23,7 +43,7 @@ enum class SignalType : u32 { | |||
| 23 | }; | 43 | }; |
| 24 | 44 | ||
| 25 | /// App Id's used by APT functions | 45 | /// App Id's used by APT functions |
| 26 | enum class AppID : u32 { | 46 | enum class AppletId : u32 { |
| 27 | HomeMenu = 0x101, | 47 | HomeMenu = 0x101, |
| 28 | AlternateMenu = 0x103, | 48 | AlternateMenu = 0x103, |
| 29 | Camera = 0x110, | 49 | Camera = 0x110, |
| @@ -45,6 +65,9 @@ enum class AppID : u32 { | |||
| 45 | SoftwareKeyboard2 = 0x401, | 65 | SoftwareKeyboard2 = 0x401, |
| 46 | }; | 66 | }; |
| 47 | 67 | ||
| 68 | /// Send a parameter to the currently-running application, which will read it via ReceiveParameter | ||
| 69 | void SendParameter(const MessageParameter& parameter); | ||
| 70 | |||
| 48 | /** | 71 | /** |
| 49 | * APT::Initialize service function | 72 | * APT::Initialize service function |
| 50 | * Service function that initializes the APT process for the running application | 73 | * Service function that initializes the APT process for the running application |
| @@ -249,6 +272,33 @@ void SetAppCpuTimeLimit(Service::Interface* self); | |||
| 249 | */ | 272 | */ |
| 250 | void GetAppCpuTimeLimit(Service::Interface* self); | 273 | void GetAppCpuTimeLimit(Service::Interface* self); |
| 251 | 274 | ||
| 275 | /** | ||
| 276 | * APT::PrepareToStartLibraryApplet service function | ||
| 277 | * Inputs: | ||
| 278 | * 0 : Command header [0x00180040] | ||
| 279 | * 1 : Id of the applet to start | ||
| 280 | * Outputs: | ||
| 281 | * 0 : Return header | ||
| 282 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 283 | */ | ||
| 284 | void PrepareToStartLibraryApplet(Service::Interface* self); | ||
| 285 | |||
| 286 | /** | ||
| 287 | * APT::StartLibraryApplet service function | ||
| 288 | * Inputs: | ||
| 289 | * 0 : Command header [0x001E0084] | ||
| 290 | * 1 : Id of the applet to start | ||
| 291 | * 2 : Buffer size | ||
| 292 | * 3 : Always 0? | ||
| 293 | * 4 : Handle passed to the applet | ||
| 294 | * 5 : (Size << 14) | 2 | ||
| 295 | * 6 : Input buffer virtual address | ||
| 296 | * Outputs: | ||
| 297 | * 0 : Return header | ||
| 298 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 299 | */ | ||
| 300 | void StartLibraryApplet(Service::Interface* self); | ||
| 301 | |||
| 252 | /// Initialize the APT service | 302 | /// Initialize the APT service |
| 253 | void Init(); | 303 | void Init(); |
| 254 | 304 | ||
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 864934245..88de339f9 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp | |||
| @@ -10,19 +10,24 @@ namespace Service { | |||
| 10 | namespace APT { | 10 | namespace APT { |
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010040, GetLockHandle, "GetLockHandle?"}, | 13 | {0x00010040, GetLockHandle, "GetLockHandle?"}, |
| 14 | {0x00020080, Initialize, "Initialize?"}, | 14 | {0x00020080, Initialize, "Initialize?"}, |
| 15 | {0x00030040, Enable, "Enable?"}, | 15 | {0x00030040, Enable, "Enable?"}, |
| 16 | {0x00040040, nullptr, "Finalize?"}, | 16 | {0x00040040, nullptr, "Finalize?"}, |
| 17 | {0x00050040, nullptr, "GetAppletManInfo?"}, | 17 | {0x00050040, nullptr, "GetAppletManInfo?"}, |
| 18 | {0x00060040, nullptr, "GetAppletInfo?"}, | 18 | {0x00060040, nullptr, "GetAppletInfo?"}, |
| 19 | {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, | 19 | {0x00090040, IsRegistered, "IsRegistered"}, |
| 20 | {0x000E0080, GlanceParameter, "GlanceParameter?"}, | 20 | {0x000C0104, SendParameter, "SendParameter"}, |
| 21 | {0x003B0040, nullptr, "CancelLibraryApplet?"}, | 21 | {0x000D0080, ReceiveParameter, "ReceiveParameter"}, |
| 22 | {0x00430040, NotifyToWait, "NotifyToWait?"}, | 22 | {0x000E0080, GlanceParameter, "GlanceParameter"}, |
| 23 | {0x00440000, GetSharedFont, "GetSharedFont?"}, | 23 | {0x000F0100, CancelParameter, "CancelParameter"}, |
| 24 | {0x004B00C2, AppletUtility, "AppletUtility?"}, | 24 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, |
| 25 | {0x00550040, nullptr, "WriteInputToNsState?"}, | 25 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, |
| 26 | {0x003B0040, nullptr, "CancelLibraryApplet?"}, | ||
| 27 | {0x00430040, NotifyToWait, "NotifyToWait?"}, | ||
| 28 | {0x00440000, GetSharedFont, "GetSharedFont?"}, | ||
| 29 | {0x004B00C2, AppletUtility, "AppletUtility?"}, | ||
| 30 | {0x00550040, nullptr, "WriteInputToNsState?"}, | ||
| 26 | }; | 31 | }; |
| 27 | 32 | ||
| 28 | APT_A_Interface::APT_A_Interface() { | 33 | APT_A_Interface::APT_A_Interface() { |
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index d006b5930..b724cd72b 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp | |||
| @@ -35,13 +35,13 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 35 | {0x00150140, nullptr, "PrepareToStartApplication"}, | 35 | {0x00150140, nullptr, "PrepareToStartApplication"}, |
| 36 | {0x00160040, nullptr, "PreloadLibraryApplet"}, | 36 | {0x00160040, nullptr, "PreloadLibraryApplet"}, |
| 37 | {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, | 37 | {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, |
| 38 | {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, | 38 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, |
| 39 | {0x00190040, nullptr, "PrepareToStartSystemApplet"}, | 39 | {0x00190040, nullptr, "PrepareToStartSystemApplet"}, |
| 40 | {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, | 40 | {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, |
| 41 | {0x001B00C4, nullptr, "StartApplication"}, | 41 | {0x001B00C4, nullptr, "StartApplication"}, |
| 42 | {0x001C0000, nullptr, "WakeupApplication"}, | 42 | {0x001C0000, nullptr, "WakeupApplication"}, |
| 43 | {0x001D0000, nullptr, "CancelApplication"}, | 43 | {0x001D0000, nullptr, "CancelApplication"}, |
| 44 | {0x001E0084, nullptr, "StartLibraryApplet"}, | 44 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, |
| 45 | {0x001F0084, nullptr, "StartSystemApplet"}, | 45 | {0x001F0084, nullptr, "StartSystemApplet"}, |
| 46 | {0x00200044, nullptr, "StartNewestHomeMenu"}, | 46 | {0x00200044, nullptr, "StartNewestHomeMenu"}, |
| 47 | {0x00210000, nullptr, "OrderToCloseApplication"}, | 47 | {0x00210000, nullptr, "OrderToCloseApplication"}, |
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index af4adba84..a329514a6 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp | |||
| @@ -11,7 +11,9 @@ namespace CFG { | |||
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, | 13 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, |
| 14 | {0x00020000, nullptr, "SecureInfoGetRegion"}, | 14 | {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, |
| 15 | {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"}, | ||
| 16 | {0x00050000, GetSystemModel, "GetSystemModel"}, | ||
| 15 | {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, | 17 | {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, |
| 16 | {0x04020082, nullptr, "SetConfigInfoBlk4"}, | 18 | {0x04020082, nullptr, "SetConfigInfoBlk4"}, |
| 17 | {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, | 19 | {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, |
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index fafb43a2f..a8cb15d60 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp | |||
| @@ -310,4 +310,9 @@ Interface::Interface() { | |||
| 310 | Register(FunctionTable); | 310 | Register(FunctionTable); |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | Interface::~Interface() { | ||
| 314 | semaphore_event = nullptr; | ||
| 315 | interrupt_event = nullptr; | ||
| 316 | } | ||
| 317 | |||
| 313 | } // namespace | 318 | } // namespace |
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h index fa13bfb7c..b6f611db5 100644 --- a/src/core/hle/service/dsp_dsp.h +++ b/src/core/hle/service/dsp_dsp.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 8 | 10 | ||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -14,6 +16,7 @@ namespace DSP_DSP { | |||
| 14 | class Interface : public Service::Interface { | 16 | class Interface : public Service::Interface { |
| 15 | public: | 17 | public: |
| 16 | Interface(); | 18 | Interface(); |
| 19 | ~Interface() override; | ||
| 17 | 20 | ||
| 18 | std::string GetPortName() const override { | 21 | std::string GetPortName() const override { |
| 19 | return "dsp::DSP"; | 22 | return "dsp::DSP"; |
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 439c7282e..3a5897d06 100644 --- a/src/core/hle/service/frd/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp | |||
| @@ -10,15 +10,26 @@ namespace Service { | |||
| 10 | namespace FRD { | 10 | namespace FRD { |
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010000, nullptr, "HasLoggedIn"}, | ||
| 14 | {0x00030000, nullptr, "Login"}, | ||
| 15 | {0x00040000, nullptr, "Logout"}, | ||
| 13 | {0x00050000, nullptr, "GetFriendKey"}, | 16 | {0x00050000, nullptr, "GetFriendKey"}, |
| 14 | {0x00080000, nullptr, "GetMyPresence"}, | 17 | {0x00080000, nullptr, "GetMyPresence"}, |
| 18 | {0x00090000, nullptr, "GetMyScreenName"}, | ||
| 15 | {0x00100040, nullptr, "GetPassword"}, | 19 | {0x00100040, nullptr, "GetPassword"}, |
| 20 | {0x00110080, nullptr, "GetFriendKeyList"}, | ||
| 16 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, | 21 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, |
| 17 | {0x001A00C4, nullptr, "GetFriendInfo"}, | 22 | {0x001A00C4, nullptr, "GetFriendInfo"}, |
| 18 | {0x001B0080, nullptr, "IsOnFriendList"}, | 23 | {0x001B0080, nullptr, "IsOnFriendList"}, |
| 19 | {0x001C0042, nullptr, "DecodeLocalFriendCode"}, | 24 | {0x001C0042, nullptr, "DecodeLocalFriendCode"}, |
| 20 | {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, | 25 | {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, |
| 21 | {0x00320042, nullptr, "SetClientSdkVersion"} | 26 | {0x00230000, nullptr, "GetLastResponseResult"}, |
| 27 | {0x00270040, nullptr, "ResultToErrorCode"}, | ||
| 28 | {0x00280244, nullptr, "RequestGameAuthentication"}, | ||
| 29 | {0x00290000, nullptr, "GetGameAuthenticationData"}, | ||
| 30 | {0x002A0204, nullptr, "RequestServiceLocator"}, | ||
| 31 | {0x002B0000, nullptr, "GetServiceLocatorData"}, | ||
| 32 | {0x00320042, nullptr, "SetClientSdkVersion"}, | ||
| 22 | }; | 33 | }; |
| 23 | 34 | ||
| 24 | FRD_U_Interface::FRD_U_Interface() { | 35 | FRD_U_Interface::FRD_U_Interface() { |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 4e275cb13..6c0df67c3 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -2,29 +2,35 @@ | |||
| 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 <cstddef> | ||
| 6 | #include <system_error> | ||
| 7 | #include <type_traits> | ||
| 5 | #include <memory> | 8 | #include <memory> |
| 6 | #include <unordered_map> | 9 | #include <unordered_map> |
| 10 | #include <utility> | ||
| 7 | 11 | ||
| 8 | #include <boost/container/flat_map.hpp> | 12 | #include <boost/container/flat_map.hpp> |
| 9 | 13 | ||
| 14 | #include "common/assert.h" | ||
| 10 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 11 | #include "common/file_util.h" | 16 | #include "common/file_util.h" |
| 12 | #include "common/logging/log.h" | 17 | #include "common/logging/log.h" |
| 13 | #include "common/make_unique.h" | 18 | #include "common/make_unique.h" |
| 14 | #include "common/math_util.h" | ||
| 15 | 19 | ||
| 16 | #include "core/file_sys/archive_backend.h" | 20 | #include "core/file_sys/archive_backend.h" |
| 17 | #include "core/file_sys/archive_extsavedata.h" | 21 | #include "core/file_sys/archive_extsavedata.h" |
| 18 | #include "core/file_sys/archive_romfs.h" | ||
| 19 | #include "core/file_sys/archive_savedata.h" | 22 | #include "core/file_sys/archive_savedata.h" |
| 20 | #include "core/file_sys/archive_savedatacheck.h" | 23 | #include "core/file_sys/archive_savedatacheck.h" |
| 21 | #include "core/file_sys/archive_sdmc.h" | 24 | #include "core/file_sys/archive_sdmc.h" |
| 22 | #include "core/file_sys/archive_systemsavedata.h" | 25 | #include "core/file_sys/archive_systemsavedata.h" |
| 23 | #include "core/file_sys/directory_backend.h" | 26 | #include "core/file_sys/directory_backend.h" |
| 27 | #include "core/file_sys/file_backend.h" | ||
| 28 | #include "core/hle/hle.h" | ||
| 24 | #include "core/hle/service/service.h" | 29 | #include "core/hle/service/service.h" |
| 25 | #include "core/hle/service/fs/archive.h" | 30 | #include "core/hle/service/fs/archive.h" |
| 26 | #include "core/hle/service/fs/fs_user.h" | 31 | #include "core/hle/service/fs/fs_user.h" |
| 27 | #include "core/hle/result.h" | 32 | #include "core/hle/result.h" |
| 33 | #include "core/memory.h" | ||
| 28 | 34 | ||
| 29 | // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. | 35 | // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. |
| 30 | // Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 | 36 | // Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 |
| @@ -110,7 +116,7 @@ ResultVal<bool> File::SyncRequest() { | |||
| 110 | u32 address = cmd_buff[6]; | 116 | u32 address = cmd_buff[6]; |
| 111 | LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", | 117 | LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", |
| 112 | GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); | 118 | GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); |
| 113 | cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush, Memory::GetPointer(address))); | 119 | cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush != 0, Memory::GetPointer(address))); |
| 114 | break; | 120 | break; |
| 115 | } | 121 | } |
| 116 | 122 | ||
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 357b6b096..f61125953 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -4,22 +4,25 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 9 | #include "core/file_sys/archive_backend.h" | 12 | #include "core/file_sys/archive_backend.h" |
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/session.h" | 13 | #include "core/hle/kernel/session.h" |
| 12 | #include "core/hle/result.h" | 14 | #include "core/hle/result.h" |
| 13 | 15 | ||
| 16 | namespace FileSys { | ||
| 17 | class DirectoryBackend; | ||
| 18 | class FileBackend; | ||
| 19 | } | ||
| 20 | |||
| 14 | /// The unique system identifier hash, also known as ID0 | 21 | /// The unique system identifier hash, also known as ID0 |
| 15 | extern const std::string SYSTEM_ID; | 22 | extern const std::string SYSTEM_ID; |
| 16 | /// The scrambled SD card CID, also known as ID1 | 23 | /// The scrambled SD card CID, also known as ID1 |
| 17 | extern const std::string SDCARD_ID; | 24 | extern const std::string SDCARD_ID; |
| 18 | 25 | ||
| 19 | namespace Kernel { | ||
| 20 | class Session; | ||
| 21 | } | ||
| 22 | |||
| 23 | namespace Service { | 26 | namespace Service { |
| 24 | namespace FS { | 27 | namespace FS { |
| 25 | 28 | ||
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 0ad44e55e..ae52083f9 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -115,7 +115,8 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 115 | 115 | ||
| 116 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); | 116 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); |
| 117 | if (archive_handle.Failed()) { | 117 | if (archive_handle.Failed()) { |
| 118 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 118 | LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s", |
| 119 | archive_id, archive_path.DebugStr().c_str()); | ||
| 119 | cmd_buff[1] = archive_handle.Code().raw; | 120 | cmd_buff[1] = archive_handle.Code().raw; |
| 120 | cmd_buff[3] = 0; | 121 | cmd_buff[3] = 0; |
| 121 | return; | 122 | return; |
| @@ -128,7 +129,8 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 128 | cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); | 129 | cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); |
| 129 | } else { | 130 | } else { |
| 130 | cmd_buff[3] = 0; | 131 | cmd_buff[3] = 0; |
| 131 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | 132 | LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%d", |
| 133 | file_path.DebugStr().c_str(), mode.hex, attributes); | ||
| 132 | } | 134 | } |
| 133 | } | 135 | } |
| 134 | 136 | ||
| @@ -347,7 +349,8 @@ static void OpenDirectory(Service::Interface* self) { | |||
| 347 | if (dir_res.Succeeded()) { | 349 | if (dir_res.Succeeded()) { |
| 348 | cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); | 350 | cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); |
| 349 | } else { | 351 | } else { |
| 350 | LOG_ERROR(Service_FS, "failed to get a handle for directory"); | 352 | LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", |
| 353 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); | ||
| 351 | } | 354 | } |
| 352 | } | 355 | } |
| 353 | 356 | ||
| @@ -382,7 +385,8 @@ static void OpenArchive(Service::Interface* self) { | |||
| 382 | cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; | 385 | cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; |
| 383 | } else { | 386 | } else { |
| 384 | cmd_buff[2] = cmd_buff[3] = 0; | 387 | cmd_buff[2] = cmd_buff[3] = 0; |
| 385 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 388 | LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s", |
| 389 | archive_id, archive_path.DebugStr().c_str()); | ||
| 386 | } | 390 | } |
| 387 | } | 391 | } |
| 388 | 392 | ||
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 4b0b4229d..e93c1b436 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -9,14 +9,17 @@ | |||
| 9 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/kernel/shared_memory.h" | 10 | #include "core/hle/kernel/shared_memory.h" |
| 11 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| 12 | #include "gsp_gpu.h" | ||
| 13 | #include "core/hw/hw.h" | 12 | #include "core/hw/hw.h" |
| 14 | #include "core/hw/gpu.h" | 13 | #include "core/hw/gpu.h" |
| 15 | #include "core/hw/lcd.h" | 14 | #include "core/hw/lcd.h" |
| 16 | 15 | ||
| 17 | #include "video_core/gpu_debugger.h" | 16 | #include "video_core/gpu_debugger.h" |
| 17 | #include "video_core/debug_utils/debug_utils.h" | ||
| 18 | #include "video_core/renderer_base.h" | ||
| 18 | #include "video_core/video_core.h" | 19 | #include "video_core/video_core.h" |
| 19 | 20 | ||
| 21 | #include "gsp_gpu.h" | ||
| 22 | |||
| 20 | // Main graphics debugger object - TODO: Here is probably not the best place for this | 23 | // Main graphics debugger object - TODO: Here is probably not the best place for this |
| 21 | GraphicsDebugger g_debugger; | 24 | GraphicsDebugger g_debugger; |
| 22 | 25 | ||
| @@ -40,7 +43,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) { | |||
| 40 | return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); | 43 | return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); |
| 41 | } | 44 | } |
| 42 | 45 | ||
| 43 | static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { | 46 | FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { |
| 44 | DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); | 47 | DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); |
| 45 | 48 | ||
| 46 | // For each thread there are two FrameBufferUpdate fields | 49 | // For each thread there are two FrameBufferUpdate fields |
| @@ -203,7 +206,7 @@ static void ReadHWRegs(Service::Interface* self) { | |||
| 203 | } | 206 | } |
| 204 | } | 207 | } |
| 205 | 208 | ||
| 206 | static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | 209 | void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { |
| 207 | u32 base_address = 0x400000; | 210 | u32 base_address = 0x400000; |
| 208 | PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); | 211 | PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); |
| 209 | PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); | 212 | PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); |
| @@ -224,6 +227,9 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | |||
| 224 | &info.format); | 227 | &info.format); |
| 225 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, | 228 | WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, |
| 226 | &info.shown_fb); | 229 | &info.shown_fb); |
| 230 | |||
| 231 | if (Pica::g_debug_context) | ||
| 232 | Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); | ||
| 227 | } | 233 | } |
| 228 | 234 | ||
| 229 | /** | 235 | /** |
| @@ -347,7 +353,7 @@ void SignalInterrupt(InterruptId interrupt_id) { | |||
| 347 | /// Executes the next GSP command | 353 | /// Executes the next GSP command |
| 348 | static void ExecuteCommand(const Command& command, u32 thread_id) { | 354 | static void ExecuteCommand(const Command& command, u32 thread_id) { |
| 349 | // Utility function to convert register ID to address | 355 | // Utility function to convert register ID to address |
| 350 | auto WriteGPURegister = [](u32 id, u32 data) { | 356 | static auto WriteGPURegister = [](u32 id, u32 data) { |
| 351 | GPU::Write<u32>(0x1EF00000 + 4 * id, data); | 357 | GPU::Write<u32>(0x1EF00000 + 4 * id, data); |
| 352 | }; | 358 | }; |
| 353 | 359 | ||
| @@ -389,19 +395,24 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 389 | case CommandId::SET_MEMORY_FILL: | 395 | case CommandId::SET_MEMORY_FILL: |
| 390 | { | 396 | { |
| 391 | auto& params = command.memory_fill; | 397 | auto& params = command.memory_fill; |
| 392 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), | 398 | |
| 393 | Memory::VirtualToPhysicalAddress(params.start1) >> 3); | 399 | if (params.start1 != 0) { |
| 394 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), | 400 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), |
| 395 | Memory::VirtualToPhysicalAddress(params.end1) >> 3); | 401 | Memory::VirtualToPhysicalAddress(params.start1) >> 3); |
| 396 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1); | 402 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), |
| 397 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1); | 403 | Memory::VirtualToPhysicalAddress(params.end1) >> 3); |
| 398 | 404 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1); | |
| 399 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), | 405 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1); |
| 400 | Memory::VirtualToPhysicalAddress(params.start2) >> 3); | 406 | } |
| 401 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), | 407 | |
| 402 | Memory::VirtualToPhysicalAddress(params.end2) >> 3); | 408 | if (params.start2 != 0) { |
| 403 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2); | 409 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), |
| 404 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2); | 410 | Memory::VirtualToPhysicalAddress(params.start2) >> 3); |
| 411 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), | ||
| 412 | Memory::VirtualToPhysicalAddress(params.end2) >> 3); | ||
| 413 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2); | ||
| 414 | WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2); | ||
| 415 | } | ||
| 405 | break; | 416 | break; |
| 406 | } | 417 | } |
| 407 | 418 | ||
| @@ -446,6 +457,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 446 | default: | 457 | default: |
| 447 | LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value()); | 458 | LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value()); |
| 448 | } | 459 | } |
| 460 | |||
| 461 | if (Pica::g_debug_context) | ||
| 462 | Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, (void*)&command); | ||
| 449 | } | 463 | } |
| 450 | 464 | ||
| 451 | /** | 465 | /** |
| @@ -582,7 +596,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 582 | Interface::Interface() { | 596 | Interface::Interface() { |
| 583 | Register(FunctionTable); | 597 | Register(FunctionTable); |
| 584 | 598 | ||
| 585 | g_interrupt_event = 0; | 599 | g_interrupt_event = nullptr; |
| 586 | 600 | ||
| 587 | using Kernel::MemoryPermission; | 601 | using Kernel::MemoryPermission; |
| 588 | g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, | 602 | g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, |
| @@ -591,4 +605,9 @@ Interface::Interface() { | |||
| 591 | g_thread_id = 0; | 605 | g_thread_id = 0; |
| 592 | } | 606 | } |
| 593 | 607 | ||
| 608 | Interface::~Interface() { | ||
| 609 | g_interrupt_event = nullptr; | ||
| 610 | g_shared_memory = nullptr; | ||
| 611 | } | ||
| 612 | |||
| 594 | } // namespace | 613 | } // namespace |
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h index a435d418a..c89d0a467 100644 --- a/src/core/hle/service/gsp_gpu.h +++ b/src/core/hle/service/gsp_gpu.h | |||
| @@ -5,8 +5,11 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <string> | ||
| 8 | 9 | ||
| 9 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 10 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 11 | 14 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -158,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec | |||
| 158 | class Interface : public Service::Interface { | 161 | class Interface : public Service::Interface { |
| 159 | public: | 162 | public: |
| 160 | Interface(); | 163 | Interface(); |
| 164 | ~Interface() override; | ||
| 161 | 165 | ||
| 162 | std::string GetPortName() const override { | 166 | std::string GetPortName() const override { |
| 163 | return "gsp::Gpu"; | 167 | return "gsp::Gpu"; |
| @@ -170,4 +174,14 @@ public: | |||
| 170 | */ | 174 | */ |
| 171 | void SignalInterrupt(InterruptId interrupt_id); | 175 | void SignalInterrupt(InterruptId interrupt_id); |
| 172 | 176 | ||
| 177 | void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info); | ||
| 178 | |||
| 179 | /** | ||
| 180 | * Retrieves the framebuffer info stored in the GSP shared memory for the | ||
| 181 | * specified screen index and thread id. | ||
| 182 | * @param thread_id GSP thread id of the process that accesses the structure that we are requesting. | ||
| 183 | * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1). | ||
| 184 | * @returns FramebufferUpdate Information about the specified framebuffer. | ||
| 185 | */ | ||
| 186 | FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index); | ||
| 173 | } // namespace | 187 | } // namespace |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index c7c1bb5ab..c35b13b25 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/emu_window.h" | ||
| 6 | 7 | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | #include "core/hle/service/hid/hid.h" | 9 | #include "core/hle/service/hid/hid.h" |
| @@ -34,6 +35,16 @@ static Kernel::SharedPtr<Kernel::Event> event_debug_pad; | |||
| 34 | static u32 next_pad_index; | 35 | static u32 next_pad_index; |
| 35 | static u32 next_touch_index; | 36 | static u32 next_touch_index; |
| 36 | 37 | ||
| 38 | const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = { | ||
| 39 | Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, | ||
| 40 | Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, | ||
| 41 | Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, | ||
| 42 | Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, | ||
| 43 | Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT, | ||
| 44 | Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT | ||
| 45 | }; | ||
| 46 | |||
| 47 | |||
| 37 | // TODO(peachum): | 48 | // TODO(peachum): |
| 38 | // Add a method for setting analog input from joystick device for the circle Pad. | 49 | // Add a method for setting analog input from joystick device for the circle Pad. |
| 39 | // | 50 | // |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 68e2bcee0..517f4f2ae 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -6,16 +6,18 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | 8 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 9 | #ifndef _MSC_VER |
| 10 | #include "core/hle/service/service.h" | 10 | #include <cstddef> |
| 11 | #endif | ||
| 12 | #include "core/settings.h" | ||
| 11 | #include "common/bit_field.h" | 13 | #include "common/bit_field.h" |
| 12 | 14 | #include "common/common_funcs.h" | |
| 13 | namespace Kernel { | 15 | #include "common/common_types.h" |
| 14 | class SharedMemory; | ||
| 15 | class Event; | ||
| 16 | } | ||
| 17 | 16 | ||
| 18 | namespace Service { | 17 | namespace Service { |
| 18 | |||
| 19 | class Interface; | ||
| 20 | |||
| 19 | namespace HID { | 21 | namespace HID { |
| 20 | 22 | ||
| 21 | /** | 23 | /** |
| @@ -155,6 +157,9 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; | |||
| 155 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; | 157 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; |
| 156 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | 158 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; |
| 157 | 159 | ||
| 160 | |||
| 161 | extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping; | ||
| 162 | |||
| 158 | /** | 163 | /** |
| 159 | * HID::GetIPCHandles service function | 164 | * HID::GetIPCHandles service function |
| 160 | * Inputs: | 165 | * Inputs: |
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp index 25b01860e..18b22956f 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm_uds.cpp | |||
| @@ -125,4 +125,8 @@ Interface::Interface() { | |||
| 125 | Register(FunctionTable); | 125 | Register(FunctionTable); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | Interface::~Interface() { | ||
| 129 | handle_event = nullptr; | ||
| 130 | } | ||
| 131 | |||
| 128 | } // namespace | 132 | } // namespace |
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h index 82abdff28..0ced2359c 100644 --- a/src/core/hle/service/nwm_uds.h +++ b/src/core/hle/service/nwm_uds.h | |||
| @@ -16,6 +16,7 @@ namespace NWM_UDS { | |||
| 16 | class Interface : public Service::Interface { | 16 | class Interface : public Service::Interface { |
| 17 | public: | 17 | public: |
| 18 | Interface(); | 18 | Interface(); |
| 19 | ~Interface() override; | ||
| 19 | 20 | ||
| 20 | std::string GetPortName() const override { | 21 | std::string GetPortName() const override { |
| 21 | return "nwm::UDS"; | 22 | return "nwm::UDS"; |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index d681cc3dc..0de0b13a3 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -54,7 +54,7 @@ static std::string MakeFunctionString(const char* name, const char* port_name, c | |||
| 54 | 54 | ||
| 55 | std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); | 55 | std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); |
| 56 | for (int i = 1; i <= num_params; ++i) { | 56 | for (int i = 1; i <= num_params; ++i) { |
| 57 | function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); | 57 | function_string += Common::StringFromFormat(", cmd_buff[%i]=0x%X", i, cmd_buff[i]); |
| 58 | } | 58 | } |
| 59 | return function_string; | 59 | return function_string; |
| 60 | } | 60 | } |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 77bfb9ff1..f31135212 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | #include <unordered_map> | 9 | #include <unordered_map> |
| 9 | 10 | ||
| @@ -11,8 +12,8 @@ | |||
| 11 | 12 | ||
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | 14 | ||
| 14 | #include "core/hle/kernel/kernel.h" | ||
| 15 | #include "core/hle/kernel/session.h" | 15 | #include "core/hle/kernel/session.h" |
| 16 | #include "core/hle/result.h" | ||
| 16 | 17 | ||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 18 | // Namespace Service | 19 | // Namespace Service |
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 3f0c5e388..d768a3fc7 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -2,40 +2,47 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <cstring> | ||
| 7 | #include <unordered_map> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 5 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 6 | #include "common/platform.h" | 13 | #include "common/scope_exit.h" |
| 7 | |||
| 8 | #if EMU_PLATFORM == PLATFORM_WINDOWS | ||
| 9 | #include <winsock2.h> | ||
| 10 | #include <ws2tcpip.h> | ||
| 11 | |||
| 12 | // MinGW does not define several errno constants | ||
| 13 | #ifndef _MSC_VER | ||
| 14 | #define EBADMSG 104 | ||
| 15 | #define ENODATA 120 | ||
| 16 | #define ENOMSG 122 | ||
| 17 | #define ENOSR 124 | ||
| 18 | #define ENOSTR 125 | ||
| 19 | #define ETIME 137 | ||
| 20 | #define EIDRM 2001 | ||
| 21 | #define ENOLINK 2002 | ||
| 22 | #endif // _MSC_VER | ||
| 23 | 14 | ||
| 15 | #include "core/hle/kernel/session.h" | ||
| 16 | #include "core/hle/result.h" | ||
| 17 | #include "core/hle/service/soc_u.h" | ||
| 18 | #include "core/memory.h" | ||
| 19 | |||
| 20 | #ifdef _WIN32 | ||
| 21 | #include <winsock2.h> | ||
| 22 | #include <ws2tcpip.h> | ||
| 23 | |||
| 24 | // MinGW does not define several errno constants | ||
| 25 | #ifndef _MSC_VER | ||
| 26 | #define EBADMSG 104 | ||
| 27 | #define ENODATA 120 | ||
| 28 | #define ENOMSG 122 | ||
| 29 | #define ENOSR 124 | ||
| 30 | #define ENOSTR 125 | ||
| 31 | #define ETIME 137 | ||
| 32 | #define EIDRM 2001 | ||
| 33 | #define ENOLINK 2002 | ||
| 34 | #endif // _MSC_VER | ||
| 24 | #else | 35 | #else |
| 25 | #include <sys/socket.h> | 36 | #include <cerrno> |
| 26 | #include <netinet/in.h> | 37 | #include <fcntl.h> |
| 27 | #include <netdb.h> | 38 | #include <netinet/in.h> |
| 28 | #include <arpa/inet.h> | 39 | #include <netdb.h> |
| 29 | #include <fcntl.h> | 40 | #include <poll.h> |
| 30 | #include <poll.h> | 41 | #include <sys/socket.h> |
| 42 | #include <unistd.h> | ||
| 31 | #endif | 43 | #endif |
| 32 | 44 | ||
| 33 | #include "common/scope_exit.h" | 45 | #ifdef _WIN32 |
| 34 | #include "core/hle/hle.h" | ||
| 35 | #include "core/hle/service/soc_u.h" | ||
| 36 | #include <unordered_map> | ||
| 37 | |||
| 38 | #if EMU_PLATFORM == PLATFORM_WINDOWS | ||
| 39 | # define WSAEAGAIN WSAEWOULDBLOCK | 46 | # define WSAEAGAIN WSAEWOULDBLOCK |
| 40 | # define WSAEMULTIHOP -1 // Invalid dummy value | 47 | # define WSAEMULTIHOP -1 // Invalid dummy value |
| 41 | # define ERRNO(x) WSA##x | 48 | # define ERRNO(x) WSA##x |
| @@ -328,6 +335,7 @@ static void Socket(Service::Interface* self) { | |||
| 328 | if ((s32)socket_handle == SOCKET_ERROR_VALUE) | 335 | if ((s32)socket_handle == SOCKET_ERROR_VALUE) |
| 329 | result = TranslateError(GET_ERRNO); | 336 | result = TranslateError(GET_ERRNO); |
| 330 | 337 | ||
| 338 | cmd_buffer[0] = IPC::MakeHeader(2, 2, 0); | ||
| 331 | cmd_buffer[1] = result; | 339 | cmd_buffer[1] = result; |
| 332 | cmd_buffer[2] = socket_handle; | 340 | cmd_buffer[2] = socket_handle; |
| 333 | } | 341 | } |
| @@ -351,8 +359,9 @@ static void Bind(Service::Interface* self) { | |||
| 351 | if (res != 0) | 359 | if (res != 0) |
| 352 | result = TranslateError(GET_ERRNO); | 360 | result = TranslateError(GET_ERRNO); |
| 353 | 361 | ||
| 354 | cmd_buffer[2] = res; | 362 | cmd_buffer[0] = IPC::MakeHeader(5, 2, 0); |
| 355 | cmd_buffer[1] = result; | 363 | cmd_buffer[1] = result; |
| 364 | cmd_buffer[2] = res; | ||
| 356 | } | 365 | } |
| 357 | 366 | ||
| 358 | static void Fcntl(Service::Interface* self) { | 367 | static void Fcntl(Service::Interface* self) { |
| @@ -369,7 +378,7 @@ static void Fcntl(Service::Interface* self) { | |||
| 369 | }); | 378 | }); |
| 370 | 379 | ||
| 371 | if (ctr_cmd == 3) { // F_GETFL | 380 | if (ctr_cmd == 3) { // F_GETFL |
| 372 | #if EMU_PLATFORM == PLATFORM_WINDOWS | 381 | #ifdef _WIN32 |
| 373 | posix_ret = 0; | 382 | posix_ret = 0; |
| 374 | auto iter = open_sockets.find(socket_handle); | 383 | auto iter = open_sockets.find(socket_handle); |
| 375 | if (iter != open_sockets.end() && iter->second.blocking == false) | 384 | if (iter != open_sockets.end() && iter->second.blocking == false) |
| @@ -386,7 +395,7 @@ static void Fcntl(Service::Interface* self) { | |||
| 386 | posix_ret |= 4; // O_NONBLOCK | 395 | posix_ret |= 4; // O_NONBLOCK |
| 387 | #endif | 396 | #endif |
| 388 | } else if (ctr_cmd == 4) { // F_SETFL | 397 | } else if (ctr_cmd == 4) { // F_SETFL |
| 389 | #if EMU_PLATFORM == PLATFORM_WINDOWS | 398 | #ifdef _WIN32 |
| 390 | unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; | 399 | unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; |
| 391 | int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); | 400 | int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); |
| 392 | if (ret == SOCKET_ERROR_VALUE) { | 401 | if (ret == SOCKET_ERROR_VALUE) { |
| @@ -434,8 +443,9 @@ static void Listen(Service::Interface* self) { | |||
| 434 | if (ret != 0) | 443 | if (ret != 0) |
| 435 | result = TranslateError(GET_ERRNO); | 444 | result = TranslateError(GET_ERRNO); |
| 436 | 445 | ||
| 437 | cmd_buffer[2] = ret; | 446 | cmd_buffer[0] = IPC::MakeHeader(3, 2, 0); |
| 438 | cmd_buffer[1] = result; | 447 | cmd_buffer[1] = result; |
| 448 | cmd_buffer[2] = ret; | ||
| 439 | } | 449 | } |
| 440 | 450 | ||
| 441 | static void Accept(Service::Interface* self) { | 451 | static void Accept(Service::Interface* self) { |
| @@ -460,8 +470,10 @@ static void Accept(Service::Interface* self) { | |||
| 460 | Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len); | 470 | Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len); |
| 461 | } | 471 | } |
| 462 | 472 | ||
| 463 | cmd_buffer[2] = ret; | 473 | cmd_buffer[0] = IPC::MakeHeader(4, 2, 2); |
| 464 | cmd_buffer[1] = result; | 474 | cmd_buffer[1] = result; |
| 475 | cmd_buffer[2] = ret; | ||
| 476 | cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0); | ||
| 465 | } | 477 | } |
| 466 | 478 | ||
| 467 | static void GetHostId(Service::Interface* self) { | 479 | static void GetHostId(Service::Interface* self) { |
| @@ -675,26 +687,29 @@ static void Connect(Service::Interface* self) { | |||
| 675 | int result = 0; | 687 | int result = 0; |
| 676 | if (ret != 0) | 688 | if (ret != 0) |
| 677 | result = TranslateError(GET_ERRNO); | 689 | result = TranslateError(GET_ERRNO); |
| 678 | cmd_buffer[2] = ret; | 690 | |
| 691 | cmd_buffer[0] = IPC::MakeHeader(6, 2, 0); | ||
| 679 | cmd_buffer[1] = result; | 692 | cmd_buffer[1] = result; |
| 693 | cmd_buffer[2] = ret; | ||
| 680 | } | 694 | } |
| 681 | 695 | ||
| 682 | static void InitializeSockets(Service::Interface* self) { | 696 | static void InitializeSockets(Service::Interface* self) { |
| 683 | // TODO(Subv): Implement | 697 | // TODO(Subv): Implement |
| 684 | #if EMU_PLATFORM == PLATFORM_WINDOWS | 698 | #ifdef _WIN32 |
| 685 | WSADATA data; | 699 | WSADATA data; |
| 686 | WSAStartup(MAKEWORD(2, 2), &data); | 700 | WSAStartup(MAKEWORD(2, 2), &data); |
| 687 | #endif | 701 | #endif |
| 688 | 702 | ||
| 689 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | 703 | u32* cmd_buffer = Kernel::GetCommandBuffer(); |
| 690 | cmd_buffer[1] = 0; | 704 | cmd_buffer[0] = IPC::MakeHeader(1, 1, 0); |
| 705 | cmd_buffer[1] = RESULT_SUCCESS.raw; | ||
| 691 | } | 706 | } |
| 692 | 707 | ||
| 693 | static void ShutdownSockets(Service::Interface* self) { | 708 | static void ShutdownSockets(Service::Interface* self) { |
| 694 | // TODO(Subv): Implement | 709 | // TODO(Subv): Implement |
| 695 | CleanupSockets(); | 710 | CleanupSockets(); |
| 696 | 711 | ||
| 697 | #if EMU_PLATFORM == PLATFORM_WINDOWS | 712 | #ifdef _WIN32 |
| 698 | WSACleanup(); | 713 | WSACleanup(); |
| 699 | #endif | 714 | #endif |
| 700 | 715 | ||
| @@ -745,7 +760,7 @@ Interface::Interface() { | |||
| 745 | 760 | ||
| 746 | Interface::~Interface() { | 761 | Interface::~Interface() { |
| 747 | CleanupSockets(); | 762 | CleanupSockets(); |
| 748 | #if EMU_PLATFORM == PLATFORM_WINDOWS | 763 | #ifdef _WIN32 |
| 749 | WSACleanup(); | 764 | WSACleanup(); |
| 750 | #endif | 765 | #endif |
| 751 | } | 766 | } |
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h index 483b3111b..a091f597c 100644 --- a/src/core/hle/service/soc_u.h +++ b/src/core/hle/service/soc_u.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 8 | 10 | ||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 6c49fa6cf..3b8c7c0e4 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp | |||
| @@ -68,4 +68,8 @@ Interface::Interface() { | |||
| 68 | Register(FunctionTable); | 68 | Register(FunctionTable); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | Interface::~Interface() { | ||
| 72 | event_handle = nullptr; | ||
| 73 | } | ||
| 74 | |||
| 71 | } // namespace | 75 | } // namespace |
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 653aba5cb..96c89b025 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h | |||
| @@ -13,6 +13,7 @@ namespace SRV { | |||
| 13 | class Interface : public Service::Interface { | 13 | class Interface : public Service::Interface { |
| 14 | public: | 14 | public: |
| 15 | Interface(); | 15 | Interface(); |
| 16 | ~Interface() override; | ||
| 16 | 17 | ||
| 17 | std::string GetPortName() const override { | 18 | std::string GetPortName() const override { |
| 18 | return "srv:"; | 19 | return "srv:"; |
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index ac1967da8..6e7dafaad 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "core/hw/y2r.h" | 12 | #include "core/hw/y2r.h" |
| 13 | #include "core/mem_map.h" | 13 | #include "core/mem_map.h" |
| 14 | 14 | ||
| 15 | #include "video_core/renderer_base.h" | ||
| 15 | #include "video_core/utils.h" | 16 | #include "video_core/utils.h" |
| 16 | #include "video_core/video_core.h" | 17 | #include "video_core/video_core.h" |
| 17 | 18 | ||
| @@ -409,4 +410,8 @@ Interface::Interface() { | |||
| 409 | Register(FunctionTable); | 410 | Register(FunctionTable); |
| 410 | } | 411 | } |
| 411 | 412 | ||
| 413 | Interface::~Interface() { | ||
| 414 | completion_event = nullptr; | ||
| 415 | } | ||
| 416 | |||
| 412 | } // namespace | 417 | } // namespace |
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h index 7df47fcb9..3965a5545 100644 --- a/src/core/hle/service/y2r_u.h +++ b/src/core/hle/service/y2r_u.h | |||
| @@ -5,9 +5,11 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <string> | ||
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | 11 | ||
| 12 | #include "core/hle/result.h" | ||
| 11 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 12 | 14 | ||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -110,6 +112,7 @@ struct ConversionConfiguration { | |||
| 110 | class Interface : public Service::Interface { | 112 | class Interface : public Service::Interface { |
| 111 | public: | 113 | public: |
| 112 | Interface(); | 114 | Interface(); |
| 115 | ~Interface() override; | ||
| 113 | 116 | ||
| 114 | std::string GetPortName() const override { | 117 | std::string GetPortName() const override { |
| 115 | return "y2r:u"; | 118 | return "y2r:u"; |
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 4014eee98..26d87c7e2 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp | |||
| @@ -4,12 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | |||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/memory.h" | ||
| 12 | #include "core/hle/config_mem.h" | ||
| 13 | #include "core/hle/shared_page.h" | 7 | #include "core/hle/shared_page.h" |
| 14 | 8 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index fd2ab66a2..db6a5340b 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h | |||
| @@ -10,9 +10,12 @@ | |||
| 10 | * write access, according to 3dbrew; this is not emulated) | 10 | * write access, according to 3dbrew; this is not emulated) |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include "common/common_funcs.h" | ||
| 13 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 14 | #include "common/swap.h" | 15 | #include "common/swap.h" |
| 15 | 16 | ||
| 17 | #include "core/memory.h" | ||
| 18 | |||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 17 | 20 | ||
| 18 | namespace SharedPage { | 21 | namespace SharedPage { |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 6cde4fc87..bb64fdfb7 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "core/hle/kernel/shared_memory.h" | 22 | #include "core/hle/kernel/shared_memory.h" |
| 23 | #include "core/hle/kernel/thread.h" | 23 | #include "core/hle/kernel/thread.h" |
| 24 | #include "core/hle/kernel/timer.h" | 24 | #include "core/hle/kernel/timer.h" |
| 25 | #include "core/hle/kernel/vm_manager.h" | ||
| 25 | 26 | ||
| 26 | #include "core/hle/function_wrappers.h" | 27 | #include "core/hle/function_wrappers.h" |
| 27 | #include "core/hle/result.h" | 28 | #include "core/hle/result.h" |
| @@ -333,7 +334,7 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle | |||
| 333 | 334 | ||
| 334 | /// Get resource limit current values | 335 | /// Get resource limit current values |
| 335 | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names, | 336 | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names, |
| 336 | s32 name_count) { | 337 | u32 name_count) { |
| 337 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", | 338 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", |
| 338 | resource_limit_handle, names, name_count); | 339 | resource_limit_handle, names, name_count); |
| 339 | 340 | ||
| @@ -349,7 +350,7 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim | |||
| 349 | 350 | ||
| 350 | /// Get resource limit max values | 351 | /// Get resource limit max values |
| 351 | static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, | 352 | static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, |
| 352 | s32 name_count) { | 353 | u32 name_count) { |
| 353 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", | 354 | LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", |
| 354 | resource_limit_handle, names, name_count); | 355 | resource_limit_handle, names, name_count); |
| 355 | 356 | ||
| @@ -529,12 +530,33 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) | |||
| 529 | return RESULT_SUCCESS; | 530 | return RESULT_SUCCESS; |
| 530 | } | 531 | } |
| 531 | 532 | ||
| 532 | /// Query memory | 533 | /// Query process memory |
| 533 | static ResultCode QueryMemory(void* info, void* out, u32 addr) { | 534 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) { |
| 534 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); | 535 | using Kernel::Process; |
| 536 | Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); | ||
| 537 | if (process == nullptr) | ||
| 538 | return ERR_INVALID_HANDLE; | ||
| 539 | |||
| 540 | auto vma = process->address_space->FindVMA(addr); | ||
| 541 | |||
| 542 | if (vma == process->address_space->vma_map.end()) | ||
| 543 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 544 | |||
| 545 | memory_info->base_address = vma->second.base; | ||
| 546 | memory_info->permission = static_cast<u32>(vma->second.permissions); | ||
| 547 | memory_info->size = vma->second.size; | ||
| 548 | memory_info->state = static_cast<u32>(vma->second.meminfo_state); | ||
| 549 | |||
| 550 | page_info->flags = 0; | ||
| 551 | LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr); | ||
| 535 | return RESULT_SUCCESS; | 552 | return RESULT_SUCCESS; |
| 536 | } | 553 | } |
| 537 | 554 | ||
| 555 | /// Query memory | ||
| 556 | static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) { | ||
| 557 | return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr); | ||
| 558 | } | ||
| 559 | |||
| 538 | /// Create an event | 560 | /// Create an event |
| 539 | static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { | 561 | static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { |
| 540 | using Kernel::Event; | 562 | using Kernel::Event; |
| @@ -806,13 +828,12 @@ static const FunctionDef SVC_Table[] = { | |||
| 806 | {0x7A, nullptr, "AddCodeSegment"}, | 828 | {0x7A, nullptr, "AddCodeSegment"}, |
| 807 | {0x7B, nullptr, "Backdoor"}, | 829 | {0x7B, nullptr, "Backdoor"}, |
| 808 | {0x7C, nullptr, "KernelSetState"}, | 830 | {0x7C, nullptr, "KernelSetState"}, |
| 809 | {0x7D, nullptr, "QueryProcessMemory"}, | 831 | {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"}, |
| 810 | }; | 832 | }; |
| 811 | 833 | ||
| 812 | Common::Profiling::TimingCategory profiler_svc("SVC Calls"); | 834 | Common::Profiling::TimingCategory profiler_svc("SVC Calls"); |
| 813 | 835 | ||
| 814 | static const FunctionDef* GetSVCInfo(u32 opcode) { | 836 | static const FunctionDef* GetSVCInfo(u32 func_num) { |
| 815 | u32 func_num = opcode & 0xFFFFFF; // 8 bits | ||
| 816 | if (func_num >= ARRAY_SIZE(SVC_Table)) { | 837 | if (func_num >= ARRAY_SIZE(SVC_Table)) { |
| 817 | LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); | 838 | LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); |
| 818 | return nullptr; | 839 | return nullptr; |
| @@ -820,10 +841,10 @@ static const FunctionDef* GetSVCInfo(u32 opcode) { | |||
| 820 | return &SVC_Table[func_num]; | 841 | return &SVC_Table[func_num]; |
| 821 | } | 842 | } |
| 822 | 843 | ||
| 823 | void CallSVC(u32 opcode) { | 844 | void CallSVC(u32 immediate) { |
| 824 | Common::Profiling::ScopeTimer timer_svc(profiler_svc); | 845 | Common::Profiling::ScopeTimer timer_svc(profiler_svc); |
| 825 | 846 | ||
| 826 | const FunctionDef *info = GetSVCInfo(opcode); | 847 | const FunctionDef* info = GetSVCInfo(immediate); |
| 827 | if (info) { | 848 | if (info) { |
| 828 | if (info->func) { | 849 | if (info->func) { |
| 829 | info->func(); | 850 | info->func(); |
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h index 4389aa73d..12de9ffbe 100644 --- a/src/core/hle/svc.h +++ b/src/core/hle/svc.h | |||
| @@ -41,6 +41,6 @@ enum ArbitrationType { | |||
| 41 | 41 | ||
| 42 | namespace SVC { | 42 | namespace SVC { |
| 43 | 43 | ||
| 44 | void CallSVC(u32 opcode); | 44 | void CallSVC(u32 immediate); |
| 45 | 45 | ||
| 46 | } // namespace | 46 | } // namespace |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 7471def57..3ccbc03b2 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -2,17 +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 <cstring> | ||
| 6 | #include <type_traits> | ||
| 7 | |||
| 5 | #include "common/color.h" | 8 | #include "common/color.h" |
| 6 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 7 | 10 | #include "common/logging/log.h" | |
| 8 | #include "core/arm/arm_interface.h" | 11 | #include "common/vector_math.h" |
| 9 | 12 | ||
| 10 | #include "core/settings.h" | 13 | #include "core/settings.h" |
| 11 | #include "core/core.h" | ||
| 12 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| 13 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 14 | 16 | ||
| 15 | #include "core/hle/hle.h" | ||
| 16 | #include "core/hle/service/gsp_gpu.h" | 17 | #include "core/hle/service/gsp_gpu.h" |
| 17 | #include "core/hle/service/dsp_dsp.h" | 18 | #include "core/hle/service/dsp_dsp.h" |
| 18 | #include "core/hle/service/hid/hid.h" | 19 | #include "core/hle/service/hid/hid.h" |
| @@ -20,10 +21,17 @@ | |||
| 20 | #include "core/hw/hw.h" | 21 | #include "core/hw/hw.h" |
| 21 | #include "core/hw/gpu.h" | 22 | #include "core/hw/gpu.h" |
| 22 | 23 | ||
| 24 | #include "core/tracer/recorder.h" | ||
| 25 | |||
| 23 | #include "video_core/command_processor.h" | 26 | #include "video_core/command_processor.h" |
| 27 | #include "video_core/hwrasterizer_base.h" | ||
| 28 | #include "video_core/renderer_base.h" | ||
| 24 | #include "video_core/utils.h" | 29 | #include "video_core/utils.h" |
| 25 | #include "video_core/video_core.h" | 30 | #include "video_core/video_core.h" |
| 26 | 31 | ||
| 32 | #include "video_core/debug_utils/debug_utils.h" | ||
| 33 | |||
| 34 | |||
| 27 | namespace GPU { | 35 | namespace GPU { |
| 28 | 36 | ||
| 29 | Regs g_regs; | 37 | Regs g_regs; |
| @@ -53,6 +61,29 @@ inline void Read(T &var, const u32 raw_addr) { | |||
| 53 | var = g_regs[addr / 4]; | 61 | var = g_regs[addr / 4]; |
| 54 | } | 62 | } |
| 55 | 63 | ||
| 64 | static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) { | ||
| 65 | switch (input_format) { | ||
| 66 | case Regs::PixelFormat::RGBA8: | ||
| 67 | return Color::DecodeRGBA8(src_pixel); | ||
| 68 | |||
| 69 | case Regs::PixelFormat::RGB8: | ||
| 70 | return Color::DecodeRGB8(src_pixel); | ||
| 71 | |||
| 72 | case Regs::PixelFormat::RGB565: | ||
| 73 | return Color::DecodeRGB565(src_pixel); | ||
| 74 | |||
| 75 | case Regs::PixelFormat::RGB5A1: | ||
| 76 | return Color::DecodeRGB5A1(src_pixel); | ||
| 77 | |||
| 78 | case Regs::PixelFormat::RGBA4: | ||
| 79 | return Color::DecodeRGBA4(src_pixel); | ||
| 80 | |||
| 81 | default: | ||
| 82 | LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", input_format); | ||
| 83 | return {0, 0, 0, 0}; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 56 | template <typename T> | 87 | template <typename T> |
| 57 | inline void Write(u32 addr, const T data) { | 88 | inline void Write(u32 addr, const T data) { |
| 58 | addr -= HW::VADDR_GPU; | 89 | addr -= HW::VADDR_GPU; |
| @@ -75,39 +106,43 @@ inline void Write(u32 addr, const T data) { | |||
| 75 | const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger)); | 106 | const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger)); |
| 76 | auto& config = g_regs.memory_fill_config[is_second_filler]; | 107 | auto& config = g_regs.memory_fill_config[is_second_filler]; |
| 77 | 108 | ||
| 78 | if (config.address_start && config.trigger) { | 109 | if (config.trigger) { |
| 79 | u8* start = Memory::GetPhysicalPointer(config.GetStartAddress()); | 110 | if (config.address_start) { // Some games pass invalid values here |
| 80 | u8* end = Memory::GetPhysicalPointer(config.GetEndAddress()); | 111 | u8* start = Memory::GetPhysicalPointer(config.GetStartAddress()); |
| 81 | 112 | u8* end = Memory::GetPhysicalPointer(config.GetEndAddress()); | |
| 82 | if (config.fill_24bit) { | 113 | |
| 83 | // fill with 24-bit values | 114 | if (config.fill_24bit) { |
| 84 | for (u8* ptr = start; ptr < end; ptr += 3) { | 115 | // fill with 24-bit values |
| 85 | ptr[0] = config.value_24bit_r; | 116 | for (u8* ptr = start; ptr < end; ptr += 3) { |
| 86 | ptr[1] = config.value_24bit_g; | 117 | ptr[0] = config.value_24bit_r; |
| 87 | ptr[2] = config.value_24bit_b; | 118 | ptr[1] = config.value_24bit_g; |
| 119 | ptr[2] = config.value_24bit_b; | ||
| 120 | } | ||
| 121 | } else if (config.fill_32bit) { | ||
| 122 | // fill with 32-bit values | ||
| 123 | for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr) | ||
| 124 | *ptr = config.value_32bit; | ||
| 125 | } else { | ||
| 126 | // fill with 16-bit values | ||
| 127 | for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr) | ||
| 128 | *ptr = config.value_16bit; | ||
| 88 | } | 129 | } |
| 89 | } else if (config.fill_32bit) { | ||
| 90 | // fill with 32-bit values | ||
| 91 | for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr) | ||
| 92 | *ptr = config.value_32bit; | ||
| 93 | } else { | ||
| 94 | // fill with 16-bit values | ||
| 95 | for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr) | ||
| 96 | *ptr = config.value_16bit; | ||
| 97 | } | ||
| 98 | 130 | ||
| 99 | LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); | 131 | LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); |
| 100 | 132 | ||
| 101 | config.trigger = 0; | 133 | if (!is_second_filler) { |
| 102 | config.finished = 1; | 134 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0); |
| 135 | } else { | ||
| 136 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); | ||
| 137 | } | ||
| 103 | 138 | ||
| 104 | if (!is_second_filler) { | 139 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); |
| 105 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0); | ||
| 106 | } else { | ||
| 107 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); | ||
| 108 | } | 140 | } |
| 109 | 141 | ||
| 110 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); | 142 | // Reset "trigger" flag and set the "finish" flag |
| 143 | // NOTE: This was confirmed to happen on hardware even if "address_start" is zero. | ||
| 144 | config.trigger = 0; | ||
| 145 | config.finished = 1; | ||
| 111 | } | 146 | } |
| 112 | break; | 147 | break; |
| 113 | } | 148 | } |
| @@ -116,6 +151,10 @@ inline void Write(u32 addr, const T data) { | |||
| 116 | { | 151 | { |
| 117 | const auto& config = g_regs.display_transfer_config; | 152 | const auto& config = g_regs.display_transfer_config; |
| 118 | if (config.trigger & 1) { | 153 | if (config.trigger & 1) { |
| 154 | |||
| 155 | if (Pica::g_debug_context) | ||
| 156 | Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::IncomingDisplayTransfer, nullptr); | ||
| 157 | |||
| 119 | u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress()); | 158 | u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress()); |
| 120 | u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress()); | 159 | u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress()); |
| 121 | 160 | ||
| @@ -125,11 +164,18 @@ inline void Write(u32 addr, const T data) { | |||
| 125 | break; | 164 | break; |
| 126 | } | 165 | } |
| 127 | 166 | ||
| 128 | unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; | 167 | if (config.output_tiled && |
| 129 | unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; | 168 | (config.scaling == config.ScaleXY || config.scaling == config.ScaleX)) { |
| 169 | LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input"); | ||
| 170 | UNIMPLEMENTED(); | ||
| 171 | break; | ||
| 172 | } | ||
| 130 | 173 | ||
| 131 | u32 output_width = config.output_width / horizontal_scale; | 174 | bool horizontal_scale = config.scaling != config.NoScale; |
| 132 | u32 output_height = config.output_height / vertical_scale; | 175 | bool vertical_scale = config.scaling == config.ScaleXY; |
| 176 | |||
| 177 | u32 output_width = config.output_width >> horizontal_scale; | ||
| 178 | u32 output_height = config.output_height >> vertical_scale; | ||
| 133 | 179 | ||
| 134 | u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); | 180 | u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); |
| 135 | u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); | 181 | u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); |
| @@ -153,16 +199,14 @@ inline void Write(u32 addr, const T data) { | |||
| 153 | break; | 199 | break; |
| 154 | } | 200 | } |
| 155 | 201 | ||
| 156 | // TODO(Subv): Implement the box filter when scaling is enabled | ||
| 157 | // right now we're just skipping the extra pixels. | ||
| 158 | for (u32 y = 0; y < output_height; ++y) { | 202 | for (u32 y = 0; y < output_height; ++y) { |
| 159 | for (u32 x = 0; x < output_width; ++x) { | 203 | for (u32 x = 0; x < output_width; ++x) { |
| 160 | Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; | 204 | Math::Vec4<u8> src_color; |
| 161 | 205 | ||
| 162 | // Calculate the [x,y] position of the input image | 206 | // Calculate the [x,y] position of the input image |
| 163 | // based on the current output position and the scale | 207 | // based on the current output position and the scale |
| 164 | u32 input_x = x * horizontal_scale; | 208 | u32 input_x = x << horizontal_scale; |
| 165 | u32 input_y = y * vertical_scale; | 209 | u32 input_y = y << vertical_scale; |
| 166 | 210 | ||
| 167 | if (config.flip_vertically) { | 211 | if (config.flip_vertically) { |
| 168 | // Flip the y value of the output data, | 212 | // Flip the y value of the output data, |
| @@ -177,46 +221,49 @@ inline void Write(u32 addr, const T data) { | |||
| 177 | u32 dst_offset; | 221 | u32 dst_offset; |
| 178 | 222 | ||
| 179 | if (config.output_tiled) { | 223 | if (config.output_tiled) { |
| 180 | // Interpret the input as linear and the output as tiled | 224 | if (!config.dont_swizzle) { |
| 181 | u32 coarse_y = y & ~7; | 225 | // Interpret the input as linear and the output as tiled |
| 182 | u32 stride = output_width * dst_bytes_per_pixel; | 226 | u32 coarse_y = y & ~7; |
| 183 | 227 | u32 stride = output_width * dst_bytes_per_pixel; | |
| 184 | src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; | 228 | |
| 185 | dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; | 229 | src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; |
| 230 | dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; | ||
| 231 | } else { | ||
| 232 | // Both input and output are linear | ||
| 233 | src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; | ||
| 234 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; | ||
| 235 | } | ||
| 186 | } else { | 236 | } else { |
| 187 | // Interpret the input as tiled and the output as linear | 237 | if (!config.dont_swizzle) { |
| 188 | u32 coarse_y = input_y & ~7; | 238 | // Interpret the input as tiled and the output as linear |
| 189 | u32 stride = config.input_width * src_bytes_per_pixel; | 239 | u32 coarse_y = input_y & ~7; |
| 190 | 240 | u32 stride = config.input_width * src_bytes_per_pixel; | |
| 191 | src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; | 241 | |
| 192 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; | 242 | src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; |
| 243 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; | ||
| 244 | } else { | ||
| 245 | // Both input and output are tiled | ||
| 246 | u32 out_coarse_y = y & ~7; | ||
| 247 | u32 out_stride = output_width * dst_bytes_per_pixel; | ||
| 248 | |||
| 249 | u32 in_coarse_y = input_y & ~7; | ||
| 250 | u32 in_stride = config.input_width * src_bytes_per_pixel; | ||
| 251 | |||
| 252 | src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + in_coarse_y * in_stride; | ||
| 253 | dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + out_coarse_y * out_stride; | ||
| 254 | } | ||
| 193 | } | 255 | } |
| 194 | 256 | ||
| 195 | const u8* src_pixel = src_pointer + src_offset; | 257 | const u8* src_pixel = src_pointer + src_offset; |
| 196 | switch (config.input_format) { | 258 | src_color = DecodePixel(config.input_format, src_pixel); |
| 197 | case Regs::PixelFormat::RGBA8: | 259 | if (config.scaling == config.ScaleX) { |
| 198 | src_color = Color::DecodeRGBA8(src_pixel); | 260 | Math::Vec4<u8> pixel = DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel); |
| 199 | break; | 261 | src_color = ((src_color + pixel) / 2).Cast<u8>(); |
| 200 | 262 | } else if (config.scaling == config.ScaleXY) { | |
| 201 | case Regs::PixelFormat::RGB8: | 263 | Math::Vec4<u8> pixel1 = DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel); |
| 202 | src_color = Color::DecodeRGB8(src_pixel); | 264 | Math::Vec4<u8> pixel2 = DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel); |
| 203 | break; | 265 | Math::Vec4<u8> pixel3 = DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel); |
| 204 | 266 | src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>(); | |
| 205 | case Regs::PixelFormat::RGB565: | ||
| 206 | src_color = Color::DecodeRGB565(src_pixel); | ||
| 207 | break; | ||
| 208 | |||
| 209 | case Regs::PixelFormat::RGB5A1: | ||
| 210 | src_color = Color::DecodeRGB5A1(src_pixel); | ||
| 211 | break; | ||
| 212 | |||
| 213 | case Regs::PixelFormat::RGBA4: | ||
| 214 | src_color = Color::DecodeRGBA4(src_pixel); | ||
| 215 | break; | ||
| 216 | |||
| 217 | default: | ||
| 218 | LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value()); | ||
| 219 | break; | ||
| 220 | } | 267 | } |
| 221 | 268 | ||
| 222 | u8* dst_pixel = dst_pointer + dst_offset; | 269 | u8* dst_pixel = dst_pointer + dst_offset; |
| @@ -254,6 +301,7 @@ inline void Write(u32 addr, const T data) { | |||
| 254 | config.GetPhysicalOutputAddress(), output_width, output_height, | 301 | config.GetPhysicalOutputAddress(), output_width, output_height, |
| 255 | config.output_format.Value(), config.flags); | 302 | config.output_format.Value(), config.flags); |
| 256 | 303 | ||
| 304 | g_regs.display_transfer_config.trigger = 0; | ||
| 257 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); | 305 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); |
| 258 | 306 | ||
| 259 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size); | 307 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size); |
| @@ -268,7 +316,14 @@ inline void Write(u32 addr, const T data) { | |||
| 268 | if (config.trigger & 1) | 316 | if (config.trigger & 1) |
| 269 | { | 317 | { |
| 270 | u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress()); | 318 | u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress()); |
| 319 | |||
| 320 | if (Pica::g_debug_context && Pica::g_debug_context->recorder) { | ||
| 321 | Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress()); | ||
| 322 | } | ||
| 323 | |||
| 271 | Pica::CommandProcessor::ProcessCommandList(buffer, config.size); | 324 | Pica::CommandProcessor::ProcessCommandList(buffer, config.size); |
| 325 | |||
| 326 | g_regs.command_processor_config.trigger = 0; | ||
| 272 | } | 327 | } |
| 273 | break; | 328 | break; |
| 274 | } | 329 | } |
| @@ -276,6 +331,13 @@ inline void Write(u32 addr, const T data) { | |||
| 276 | default: | 331 | default: |
| 277 | break; | 332 | break; |
| 278 | } | 333 | } |
| 334 | |||
| 335 | // Notify tracer about the register write | ||
| 336 | // This is happening *after* handling the write to make sure we properly catch all memory reads. | ||
| 337 | if (Pica::g_debug_context && Pica::g_debug_context->recorder) { | ||
| 338 | // addr + GPU VBase - IO VBase + IO PBase | ||
| 339 | Pica::g_debug_context->recorder->RegisterWritten<T>(addr + 0x1EF00000 - 0x1EC00000 + 0x10100000, data); | ||
| 340 | } | ||
| 279 | } | 341 | } |
| 280 | 342 | ||
| 281 | // Explicitly instantiate template functions because we aren't defining this in the header: | 343 | // Explicitly instantiate template functions because we aren't defining this in the header: |
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 699bcd2a5..daad506fe 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <type_traits> | ||
| 8 | 9 | ||
| 9 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 10 | #include "common/bit_field.h" | 11 | #include "common/bit_field.h" |
| @@ -202,6 +203,7 @@ struct Regs { | |||
| 202 | BitField< 0, 1, u32> flip_vertically; // flips input data vertically | 203 | BitField< 0, 1, u32> flip_vertically; // flips input data vertically |
| 203 | BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format | 204 | BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format |
| 204 | BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing | 205 | BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing |
| 206 | BitField< 5, 1, u32> dont_swizzle; | ||
| 205 | BitField< 8, 3, PixelFormat> input_format; | 207 | BitField< 8, 3, PixelFormat> input_format; |
| 206 | BitField<12, 3, PixelFormat> output_format; | 208 | BitField<12, 3, PixelFormat> output_format; |
| 207 | 209 | ||
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index c7006a498..b5fdbf9c1 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp | |||
| @@ -15,6 +15,21 @@ template <typename T> | |||
| 15 | inline void Read(T &var, const u32 addr) { | 15 | inline void Read(T &var, const u32 addr) { |
| 16 | switch (addr & 0xFFFFF000) { | 16 | switch (addr & 0xFFFFF000) { |
| 17 | case VADDR_GPU: | 17 | case VADDR_GPU: |
| 18 | case VADDR_GPU + 0x1000: | ||
| 19 | case VADDR_GPU + 0x2000: | ||
| 20 | case VADDR_GPU + 0x3000: | ||
| 21 | case VADDR_GPU + 0x4000: | ||
| 22 | case VADDR_GPU + 0x5000: | ||
| 23 | case VADDR_GPU + 0x6000: | ||
| 24 | case VADDR_GPU + 0x7000: | ||
| 25 | case VADDR_GPU + 0x8000: | ||
| 26 | case VADDR_GPU + 0x9000: | ||
| 27 | case VADDR_GPU + 0xA000: | ||
| 28 | case VADDR_GPU + 0xB000: | ||
| 29 | case VADDR_GPU + 0xC000: | ||
| 30 | case VADDR_GPU + 0xD000: | ||
| 31 | case VADDR_GPU + 0xE000: | ||
| 32 | case VADDR_GPU + 0xF000: | ||
| 18 | GPU::Read(var, addr); | 33 | GPU::Read(var, addr); |
| 19 | break; | 34 | break; |
| 20 | case VADDR_LCD: | 35 | case VADDR_LCD: |
| @@ -29,6 +44,21 @@ template <typename T> | |||
| 29 | inline void Write(u32 addr, const T data) { | 44 | inline void Write(u32 addr, const T data) { |
| 30 | switch (addr & 0xFFFFF000) { | 45 | switch (addr & 0xFFFFF000) { |
| 31 | case VADDR_GPU: | 46 | case VADDR_GPU: |
| 47 | case VADDR_GPU + 0x1000: | ||
| 48 | case VADDR_GPU + 0x2000: | ||
| 49 | case VADDR_GPU + 0x3000: | ||
| 50 | case VADDR_GPU + 0x4000: | ||
| 51 | case VADDR_GPU + 0x5000: | ||
| 52 | case VADDR_GPU + 0x6000: | ||
| 53 | case VADDR_GPU + 0x7000: | ||
| 54 | case VADDR_GPU + 0x8000: | ||
| 55 | case VADDR_GPU + 0x9000: | ||
| 56 | case VADDR_GPU + 0xA000: | ||
| 57 | case VADDR_GPU + 0xB000: | ||
| 58 | case VADDR_GPU + 0xC000: | ||
| 59 | case VADDR_GPU + 0xD000: | ||
| 60 | case VADDR_GPU + 0xE000: | ||
| 61 | case VADDR_GPU + 0xF000: | ||
| 32 | GPU::Write(addr, data); | 62 | GPU::Write(addr, data); |
| 33 | break; | 63 | break; |
| 34 | case VADDR_LCD: | 64 | case VADDR_LCD: |
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp index 963c8d981..6f93709e3 100644 --- a/src/core/hw/lcd.cpp +++ b/src/core/hw/lcd.cpp | |||
| @@ -7,11 +7,12 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | 9 | ||
| 10 | #include "core/arm/arm_interface.h" | ||
| 11 | #include "core/hle/hle.h" | ||
| 12 | #include "core/hw/hw.h" | 10 | #include "core/hw/hw.h" |
| 13 | #include "core/hw/lcd.h" | 11 | #include "core/hw/lcd.h" |
| 14 | 12 | ||
| 13 | #include "core/tracer/recorder.h" | ||
| 14 | #include "video_core/debug_utils/debug_utils.h" | ||
| 15 | |||
| 15 | namespace LCD { | 16 | namespace LCD { |
| 16 | 17 | ||
| 17 | Regs g_regs; | 18 | Regs g_regs; |
| @@ -42,6 +43,13 @@ inline void Write(u32 addr, const T data) { | |||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | g_regs[index] = static_cast<u32>(data); | 45 | g_regs[index] = static_cast<u32>(data); |
| 46 | |||
| 47 | // Notify tracer about the register write | ||
| 48 | // This is happening *after* handling the write to make sure we properly catch all memory reads. | ||
| 49 | if (Pica::g_debug_context && Pica::g_debug_context->recorder) { | ||
| 50 | // addr + GPU VBase - IO VBase + IO PBase | ||
| 51 | Pica::g_debug_context->recorder->RegisterWritten<T>(addr + HW::VADDR_LCD - 0x1EC00000 + 0x10100000, data); | ||
| 52 | } | ||
| 45 | } | 53 | } |
| 46 | 54 | ||
| 47 | // Explicitly instantiate template functions because we aren't defining this in the header: | 55 | // Explicitly instantiate template functions because we aren't defining this in the header: |
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h index 8631eb201..bcce6d8cf 100644 --- a/src/core/hw/lcd.h +++ b/src/core/hw/lcd.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <type_traits> | ||
| 8 | 9 | ||
| 9 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp index 5b7fb39e1..f80e26ecd 100644 --- a/src/core/hw/y2r.cpp +++ b/src/core/hw/y2r.cpp | |||
| @@ -2,8 +2,10 @@ | |||
| 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 <algorithm> | ||
| 5 | #include <array> | 6 | #include <array> |
| 6 | #include <numeric> | 7 | #include <cstddef> |
| 8 | #include <memory> | ||
| 7 | 9 | ||
| 8 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 9 | #include "common/color.h" | 11 | #include "common/color.h" |
| @@ -109,7 +111,7 @@ static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data | |||
| 109 | while (output < unit_end) { | 111 | while (output < unit_end) { |
| 110 | u32 color = *input++; | 112 | u32 color = *input++; |
| 111 | Math::Vec4<u8> col_vec{ | 113 | Math::Vec4<u8> col_vec{ |
| 112 | (color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF, alpha, | 114 | (u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha |
| 113 | }; | 115 | }; |
| 114 | 116 | ||
| 115 | switch (output_format) { | 117 | switch (output_format) { |
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 14aeebebb..530837d08 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | namespace Loader { | 20 | namespace Loader { |
| 21 | 21 | ||
| 22 | /** | 22 | /* |
| 23 | * File layout: | 23 | * File layout: |
| 24 | * - File header | 24 | * - File header |
| 25 | * - Code, rodata and data relocation table headers | 25 | * - Code, rodata and data relocation table headers |
| @@ -39,13 +39,16 @@ namespace Loader { | |||
| 39 | * The entrypoint is always the start of the code segment. | 39 | * The entrypoint is always the start of the code segment. |
| 40 | * The BSS section must be cleared manually by the application. | 40 | * The BSS section must be cleared manually by the application. |
| 41 | */ | 41 | */ |
| 42 | |||
| 42 | enum THREEDSX_Error { | 43 | enum THREEDSX_Error { |
| 43 | ERROR_NONE = 0, | 44 | ERROR_NONE = 0, |
| 44 | ERROR_READ = 1, | 45 | ERROR_READ = 1, |
| 45 | ERROR_FILE = 2, | 46 | ERROR_FILE = 2, |
| 46 | ERROR_ALLOC = 3 | 47 | ERROR_ALLOC = 3 |
| 47 | }; | 48 | }; |
| 49 | |||
| 48 | static const u32 RELOCBUFSIZE = 512; | 50 | static const u32 RELOCBUFSIZE = 512; |
| 51 | static const unsigned int NUM_SEGMENTS = 3; | ||
| 49 | 52 | ||
| 50 | // File header | 53 | // File header |
| 51 | #pragma pack(1) | 54 | #pragma pack(1) |
| @@ -98,7 +101,10 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) | |||
| 98 | return loadinfo->seg_addrs[2] + addr - offsets[1]; | 101 | return loadinfo->seg_addrs[2] + addr - offsets[1]; |
| 99 | } | 102 | } |
| 100 | 103 | ||
| 101 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | 104 | using Kernel::SharedPtr; |
| 105 | using Kernel::CodeSet; | ||
| 106 | |||
| 107 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset) | ||
| 102 | { | 108 | { |
| 103 | if (!file.IsOpen()) | 109 | if (!file.IsOpen()) |
| 104 | return ERROR_FILE; | 110 | return ERROR_FILE; |
| @@ -116,15 +122,13 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 116 | loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF; | 122 | loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF; |
| 117 | loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF; | 123 | loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF; |
| 118 | u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] }; | 124 | u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] }; |
| 119 | u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF; | 125 | u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32); |
| 120 | u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size; | 126 | std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); |
| 121 | u32 n_reloc_tables = hdr.reloc_hdr_size / 4; | ||
| 122 | std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables); | ||
| 123 | 127 | ||
| 124 | loadinfo.seg_addrs[0] = base_addr; | 128 | loadinfo.seg_addrs[0] = base_addr; |
| 125 | loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; | 129 | loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; |
| 126 | loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1]; | 130 | loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1]; |
| 127 | loadinfo.seg_ptrs[0] = &all_mem[0]; | 131 | loadinfo.seg_ptrs[0] = program_image.data(); |
| 128 | loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0]; | 132 | loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0]; |
| 129 | loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1]; | 133 | loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1]; |
| 130 | 134 | ||
| @@ -132,10 +136,9 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 132 | file.Seek(hdr.header_size, SEEK_SET); | 136 | file.Seek(hdr.header_size, SEEK_SET); |
| 133 | 137 | ||
| 134 | // Read the relocation headers | 138 | // Read the relocation headers |
| 135 | u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size); | 139 | std::vector<u32> relocs(n_reloc_tables * NUM_SEGMENTS); |
| 136 | 140 | for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) { | |
| 137 | for (unsigned current_segment : {0, 1, 2}) { | 141 | size_t size = n_reloc_tables * sizeof(u32); |
| 138 | size_t size = n_reloc_tables * 4; | ||
| 139 | if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size) | 142 | if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size) |
| 140 | return ERROR_READ; | 143 | return ERROR_READ; |
| 141 | } | 144 | } |
| @@ -152,7 +155,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 152 | memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); | 155 | memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); |
| 153 | 156 | ||
| 154 | // Relocate the segments | 157 | // Relocate the segments |
| 155 | for (unsigned current_segment : {0, 1, 2}) { | 158 | for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) { |
| 156 | for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { | 159 | for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { |
| 157 | u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; | 160 | u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; |
| 158 | if (current_segment_reloc_table >= 2) { | 161 | if (current_segment_reloc_table >= 2) { |
| @@ -160,7 +163,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 160 | file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); | 163 | file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); |
| 161 | continue; | 164 | continue; |
| 162 | } | 165 | } |
| 163 | static THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; | 166 | THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; |
| 164 | 167 | ||
| 165 | u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; | 168 | u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; |
| 166 | const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); | 169 | const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); |
| @@ -179,7 +182,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 179 | pos += table.skip; | 182 | pos += table.skip; |
| 180 | s32 num_patches = table.patch; | 183 | s32 num_patches = table.patch; |
| 181 | while (0 < num_patches && pos < end_pos) { | 184 | while (0 < num_patches && pos < end_pos) { |
| 182 | u32 in_addr = (char*)pos - (char*)&all_mem[0]; | 185 | u32 in_addr = (u8*)pos - program_image.data(); |
| 183 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); | 186 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); |
| 184 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", | 187 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", |
| 185 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); | 188 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); |
| @@ -188,7 +191,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 188 | *pos = (addr); | 191 | *pos = (addr); |
| 189 | break; | 192 | break; |
| 190 | case 1: | 193 | case 1: |
| 191 | *pos = (addr - in_addr); | 194 | *pos = static_cast<u32>(addr - in_addr); |
| 192 | break; | 195 | break; |
| 193 | default: | 196 | default: |
| 194 | break; //this should never happen | 197 | break; //this should never happen |
| @@ -201,14 +204,29 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) | |||
| 201 | } | 204 | } |
| 202 | } | 205 | } |
| 203 | 206 | ||
| 204 | // Write the data | 207 | // Create the CodeSet |
| 205 | memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); | 208 | SharedPtr<CodeSet> code_set = CodeSet::Create("", 0); |
| 209 | |||
| 210 | code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data(); | ||
| 211 | code_set->code.addr = loadinfo.seg_addrs[0]; | ||
| 212 | code_set->code.size = loadinfo.seg_sizes[0]; | ||
| 213 | |||
| 214 | code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data(); | ||
| 215 | code_set->rodata.addr = loadinfo.seg_addrs[1]; | ||
| 216 | code_set->rodata.size = loadinfo.seg_sizes[1]; | ||
| 206 | 217 | ||
| 207 | LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000); | 218 | code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data(); |
| 208 | LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000); | 219 | code_set->data.addr = loadinfo.seg_addrs[2]; |
| 209 | LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000); | 220 | code_set->data.size = loadinfo.seg_sizes[2]; |
| 210 | LOG_DEBUG(Loader, "BSS: %u pages\n", bss_load_size / 0x1000); | ||
| 211 | 221 | ||
| 222 | code_set->entrypoint = code_set->code.addr; | ||
| 223 | code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||
| 224 | |||
| 225 | LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]); | ||
| 226 | LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]); | ||
| 227 | LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size); | ||
| 228 | |||
| 229 | *out_codeset = code_set; | ||
| 212 | return ERROR_NONE; | 230 | return ERROR_NONE; |
| 213 | } | 231 | } |
| 214 | 232 | ||
| @@ -228,19 +246,22 @@ ResultStatus AppLoader_THREEDSX::Load() { | |||
| 228 | if (is_loaded) | 246 | if (is_loaded) |
| 229 | return ResultStatus::ErrorAlreadyLoaded; | 247 | return ResultStatus::ErrorAlreadyLoaded; |
| 230 | 248 | ||
| 231 | if (!file->IsOpen()) | 249 | if (!file.IsOpen()) |
| 250 | return ResultStatus::Error; | ||
| 251 | |||
| 252 | SharedPtr<CodeSet> codeset; | ||
| 253 | if (Load3DSXFile(file, Memory::PROCESS_IMAGE_VADDR, &codeset) != ERROR_NONE) | ||
| 232 | return ResultStatus::Error; | 254 | return ResultStatus::Error; |
| 255 | codeset->name = filename; | ||
| 233 | 256 | ||
| 234 | Kernel::g_current_process = Kernel::Process::Create(filename, 0); | 257 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); |
| 235 | Kernel::g_current_process->svc_access_mask.set(); | 258 | Kernel::g_current_process->svc_access_mask.set(); |
| 236 | Kernel::g_current_process->address_mappings = default_address_mappings; | 259 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 237 | 260 | ||
| 238 | // Attach the default resource limit (APPLICATION) to the process | 261 | // Attach the default resource limit (APPLICATION) to the process |
| 239 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 262 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 240 | 263 | ||
| 241 | Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR); | 264 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); |
| 242 | |||
| 243 | Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); | ||
| 244 | 265 | ||
| 245 | is_loaded = true; | 266 | is_loaded = true; |
| 246 | return ResultStatus::Success; | 267 | return ResultStatus::Success; |
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h index 096b3ec20..a0aa0c533 100644 --- a/src/core/loader/3dsx.h +++ b/src/core/loader/3dsx.h | |||
| @@ -17,7 +17,7 @@ namespace Loader { | |||
| 17 | /// Loads an 3DSX file | 17 | /// Loads an 3DSX file |
| 18 | class AppLoader_THREEDSX final : public AppLoader { | 18 | class AppLoader_THREEDSX final : public AppLoader { |
| 19 | public: | 19 | public: |
| 20 | AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename) | 20 | AppLoader_THREEDSX(FileUtil::IOFile&& file, std::string filename) |
| 21 | : AppLoader(std::move(file)), filename(std::move(filename)) {} | 21 | : AppLoader(std::move(file)), filename(std::move(filename)) {} |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index f00753a79..5d7264f12 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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 <cstring> | ||
| 5 | #include <string> | 6 | #include <string> |
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | 8 | ||
| @@ -10,11 +11,14 @@ | |||
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 11 | #include "common/symbols.h" | 12 | #include "common/symbols.h" |
| 12 | 13 | ||
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/resource_limit.h" | 15 | #include "core/hle/kernel/resource_limit.h" |
| 15 | #include "core/loader/elf.h" | 16 | #include "core/loader/elf.h" |
| 16 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 17 | 18 | ||
| 19 | using Kernel::SharedPtr; | ||
| 20 | using Kernel::CodeSet; | ||
| 21 | |||
| 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 22 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 19 | // ELF Header Constants | 23 | // ELF Header Constants |
| 20 | 24 | ||
| @@ -96,6 +100,12 @@ enum ElfSectionFlags | |||
| 96 | #define PT_LOPROC 0x70000000 | 100 | #define PT_LOPROC 0x70000000 |
| 97 | #define PT_HIPROC 0x7FFFFFFF | 101 | #define PT_HIPROC 0x7FFFFFFF |
| 98 | 102 | ||
| 103 | // Segment flags | ||
| 104 | #define PF_X 0x1 | ||
| 105 | #define PF_W 0x2 | ||
| 106 | #define PF_R 0x4 | ||
| 107 | #define PF_MASKPROC 0xF0000000 | ||
| 108 | |||
| 99 | typedef unsigned int Elf32_Addr; | 109 | typedef unsigned int Elf32_Addr; |
| 100 | typedef unsigned short Elf32_Half; | 110 | typedef unsigned short Elf32_Half; |
| 101 | typedef unsigned int Elf32_Off; | 111 | typedef unsigned int Elf32_Off; |
| @@ -192,7 +202,7 @@ public: | |||
| 192 | ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } | 202 | ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } |
| 193 | u32 GetEntryPoint() const { return entryPoint; } | 203 | u32 GetEntryPoint() const { return entryPoint; } |
| 194 | u32 GetFlags() const { return (u32)(header->e_flags); } | 204 | u32 GetFlags() const { return (u32)(header->e_flags); } |
| 195 | void LoadInto(u32 vaddr); | 205 | SharedPtr<CodeSet> LoadInto(u32 vaddr); |
| 196 | bool LoadSymbols(); | 206 | bool LoadSymbols(); |
| 197 | 207 | ||
| 198 | int GetNumSegments() const { return (int)(header->e_phnum); } | 208 | int GetNumSegments() const { return (int)(header->e_phnum); } |
| @@ -248,7 +258,7 @@ const char *ElfReader::GetSectionName(int section) const { | |||
| 248 | return nullptr; | 258 | return nullptr; |
| 249 | } | 259 | } |
| 250 | 260 | ||
| 251 | void ElfReader::LoadInto(u32 vaddr) { | 261 | SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { |
| 252 | LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx); | 262 | LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx); |
| 253 | 263 | ||
| 254 | // Should we relocate? | 264 | // Should we relocate? |
| @@ -263,22 +273,63 @@ void ElfReader::LoadInto(u32 vaddr) { | |||
| 263 | LOG_DEBUG(Loader, "%i segments:", header->e_phnum); | 273 | LOG_DEBUG(Loader, "%i segments:", header->e_phnum); |
| 264 | 274 | ||
| 265 | // First pass : Get the bits into RAM | 275 | // First pass : Get the bits into RAM |
| 266 | u32 segment_addr[32]; | ||
| 267 | u32 base_addr = relocate ? vaddr : 0; | 276 | u32 base_addr = relocate ? vaddr : 0; |
| 268 | 277 | ||
| 269 | for (unsigned i = 0; i < header->e_phnum; i++) { | 278 | u32 total_image_size = 0; |
| 270 | Elf32_Phdr* p = segments + i; | 279 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 271 | LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, | 280 | Elf32_Phdr* p = &segments[i]; |
| 281 | if (p->p_type == PT_LOAD) { | ||
| 282 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | std::vector<u8> program_image(total_image_size); | ||
| 287 | size_t current_image_position = 0; | ||
| 288 | |||
| 289 | SharedPtr<CodeSet> codeset = CodeSet::Create("", 0); | ||
| 290 | |||
| 291 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | ||
| 292 | Elf32_Phdr* p = &segments[i]; | ||
| 293 | LOG_DEBUG(Loader, "Type: %i Vaddr: %08X Filesz: %8X Memsz: %8X ", p->p_type, p->p_vaddr, | ||
| 272 | p->p_filesz, p->p_memsz); | 294 | p->p_filesz, p->p_memsz); |
| 273 | 295 | ||
| 274 | if (p->p_type == PT_LOAD) { | 296 | if (p->p_type == PT_LOAD) { |
| 275 | segment_addr[i] = base_addr + p->p_vaddr; | 297 | CodeSet::Segment* codeset_segment; |
| 276 | memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); | 298 | u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); |
| 277 | LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], | 299 | if (permission_flags == (PF_R | PF_X)) { |
| 278 | p->p_memsz); | 300 | codeset_segment = &codeset->code; |
| 301 | } else if (permission_flags == (PF_R)) { | ||
| 302 | codeset_segment = &codeset->rodata; | ||
| 303 | } else if (permission_flags == (PF_R | PF_W)) { | ||
| 304 | codeset_segment = &codeset->data; | ||
| 305 | } else { | ||
| 306 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, p->p_flags); | ||
| 307 | continue; | ||
| 308 | } | ||
| 309 | |||
| 310 | if (codeset_segment->size != 0) { | ||
| 311 | LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra segment (id %i)", i); | ||
| 312 | continue; | ||
| 313 | } | ||
| 314 | |||
| 315 | u32 segment_addr = base_addr + p->p_vaddr; | ||
| 316 | u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; | ||
| 317 | |||
| 318 | codeset_segment->offset = current_image_position; | ||
| 319 | codeset_segment->addr = segment_addr; | ||
| 320 | codeset_segment->size = aligned_size; | ||
| 321 | |||
| 322 | memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz); | ||
| 323 | current_image_position += aligned_size; | ||
| 279 | } | 324 | } |
| 280 | } | 325 | } |
| 326 | |||
| 327 | codeset->entrypoint = base_addr + header->e_entry; | ||
| 328 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||
| 329 | |||
| 281 | LOG_DEBUG(Loader, "Done loading."); | 330 | LOG_DEBUG(Loader, "Done loading."); |
| 331 | |||
| 332 | return codeset; | ||
| 282 | } | 333 | } |
| 283 | 334 | ||
| 284 | SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { | 335 | SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { |
| @@ -340,29 +391,29 @@ ResultStatus AppLoader_ELF::Load() { | |||
| 340 | if (is_loaded) | 391 | if (is_loaded) |
| 341 | return ResultStatus::ErrorAlreadyLoaded; | 392 | return ResultStatus::ErrorAlreadyLoaded; |
| 342 | 393 | ||
| 343 | if (!file->IsOpen()) | 394 | if (!file.IsOpen()) |
| 344 | return ResultStatus::Error; | 395 | return ResultStatus::Error; |
| 345 | 396 | ||
| 346 | // Reset read pointer in case this file has been read before. | 397 | // Reset read pointer in case this file has been read before. |
| 347 | file->Seek(0, SEEK_SET); | 398 | file.Seek(0, SEEK_SET); |
| 348 | 399 | ||
| 349 | u32 size = static_cast<u32>(file->GetSize()); | 400 | size_t size = file.GetSize(); |
| 350 | std::unique_ptr<u8[]> buffer(new u8[size]); | 401 | std::unique_ptr<u8[]> buffer(new u8[size]); |
| 351 | if (file->ReadBytes(&buffer[0], size) != size) | 402 | if (file.ReadBytes(&buffer[0], size) != size) |
| 352 | return ResultStatus::Error; | 403 | return ResultStatus::Error; |
| 353 | 404 | ||
| 354 | Kernel::g_current_process = Kernel::Process::Create(filename, 0); | 405 | ElfReader elf_reader(&buffer[0]); |
| 406 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); | ||
| 407 | codeset->name = filename; | ||
| 408 | |||
| 409 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); | ||
| 355 | Kernel::g_current_process->svc_access_mask.set(); | 410 | Kernel::g_current_process->svc_access_mask.set(); |
| 356 | Kernel::g_current_process->address_mappings = default_address_mappings; | 411 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 357 | 412 | ||
| 358 | // Attach the default resource limit (APPLICATION) to the process | 413 | // Attach the default resource limit (APPLICATION) to the process |
| 359 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 414 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 360 | 415 | ||
| 361 | ElfReader elf_reader(&buffer[0]); | 416 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); |
| 362 | elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); | ||
| 363 | // TODO: Fill application title | ||
| 364 | |||
| 365 | Kernel::g_current_process->Run(elf_reader.GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE); | ||
| 366 | 417 | ||
| 367 | is_loaded = true; | 418 | is_loaded = true; |
| 368 | return ResultStatus::Success; | 419 | return ResultStatus::Success; |
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index 32841606a..c6a5ebe99 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h | |||
| @@ -17,7 +17,7 @@ namespace Loader { | |||
| 17 | /// Loads an ELF/AXF file | 17 | /// Loads an ELF/AXF file |
| 18 | class AppLoader_ELF final : public AppLoader { | 18 | class AppLoader_ELF final : public AppLoader { |
| 19 | public: | 19 | public: |
| 20 | AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename) | 20 | AppLoader_ELF(FileUtil::IOFile&& file, std::string filename) |
| 21 | : AppLoader(std::move(file)), filename(std::move(filename)) { } | 21 | : AppLoader(std::move(file)), filename(std::move(filename)) { } |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 8b14edf00..f5b349a77 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -2,10 +2,12 @@ | |||
| 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 <memory> | ||
| 5 | #include <string> | 6 | #include <string> |
| 6 | 7 | ||
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "common/make_unique.h" | 9 | #include "common/make_unique.h" |
| 10 | #include "common/string_util.h" | ||
| 9 | 11 | ||
| 10 | #include "core/file_sys/archive_romfs.h" | 12 | #include "core/file_sys/archive_romfs.h" |
| 11 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| @@ -54,18 +56,18 @@ static FileType IdentifyFile(FileUtil::IOFile& file) { | |||
| 54 | static FileType GuessFromExtension(const std::string& extension_) { | 56 | static FileType GuessFromExtension(const std::string& extension_) { |
| 55 | std::string extension = Common::ToLower(extension_); | 57 | std::string extension = Common::ToLower(extension_); |
| 56 | 58 | ||
| 57 | if (extension == ".elf") | 59 | if (extension == ".elf" || extension == ".axf") |
| 58 | return FileType::ELF; | 60 | return FileType::ELF; |
| 59 | else if (extension == ".axf") | 61 | |
| 60 | return FileType::ELF; | 62 | if (extension == ".cci" || extension == ".3ds") |
| 61 | else if (extension == ".cxi") | ||
| 62 | return FileType::CXI; | ||
| 63 | else if (extension == ".cci") | ||
| 64 | return FileType::CCI; | ||
| 65 | else if (extension == ".3ds") | ||
| 66 | return FileType::CCI; | 63 | return FileType::CCI; |
| 67 | else if (extension == ".3dsx") | 64 | |
| 65 | if (extension == ".cxi") | ||
| 66 | return FileType::CXI; | ||
| 67 | |||
| 68 | if (extension == ".3dsx") | ||
| 68 | return FileType::THREEDSX; | 69 | return FileType::THREEDSX; |
| 70 | |||
| 69 | return FileType::Unknown; | 71 | return FileType::Unknown; |
| 70 | } | 72 | } |
| 71 | 73 | ||
| @@ -88,8 +90,8 @@ static const char* GetFileTypeString(FileType type) { | |||
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | ResultStatus LoadFile(const std::string& filename) { | 92 | ResultStatus LoadFile(const std::string& filename) { |
| 91 | std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb")); | 93 | FileUtil::IOFile file(filename, "rb"); |
| 92 | if (!file->IsOpen()) { | 94 | if (!file.IsOpen()) { |
| 93 | LOG_ERROR(Loader, "Failed to load file %s", filename.c_str()); | 95 | LOG_ERROR(Loader, "Failed to load file %s", filename.c_str()); |
| 94 | return ResultStatus::Error; | 96 | return ResultStatus::Error; |
| 95 | } | 97 | } |
| @@ -97,7 +99,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 97 | std::string filename_filename, filename_extension; | 99 | std::string filename_filename, filename_extension; |
| 98 | Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension); | 100 | Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension); |
| 99 | 101 | ||
| 100 | FileType type = IdentifyFile(*file); | 102 | FileType type = IdentifyFile(file); |
| 101 | FileType filename_type = GuessFromExtension(filename_extension); | 103 | FileType filename_type = GuessFromExtension(filename_extension); |
| 102 | 104 | ||
| 103 | if (type != filename_type) { | 105 | if (type != filename_type) { |
| @@ -122,7 +124,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 122 | case FileType::CXI: | 124 | case FileType::CXI: |
| 123 | case FileType::CCI: | 125 | case FileType::CCI: |
| 124 | { | 126 | { |
| 125 | AppLoader_NCCH app_loader(std::move(file)); | 127 | AppLoader_NCCH app_loader(std::move(file), filename); |
| 126 | 128 | ||
| 127 | // Load application and RomFS | 129 | // Load application and RomFS |
| 128 | if (ResultStatus::Success == app_loader.Load()) { | 130 | if (ResultStatus::Success == app_loader.Load()) { |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 87e16fb98..a37d3348c 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -4,12 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 8 | #include <initializer_list> | ||
| 9 | #include <memory> | ||
| 10 | #include <string> | ||
| 7 | #include <vector> | 11 | #include <vector> |
| 8 | 12 | ||
| 9 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 10 | #include "common/file_util.h" | 14 | #include "common/file_util.h" |
| 11 | 15 | ||
| 12 | #include "core/hle/kernel/process.h" | 16 | namespace Kernel { |
| 17 | struct AddressMapping; | ||
| 18 | } | ||
| 13 | 19 | ||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 20 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 15 | // Loader namespace | 21 | // Loader namespace |
| @@ -46,7 +52,7 @@ static inline u32 MakeMagic(char a, char b, char c, char d) { | |||
| 46 | /// Interface for loading an application | 52 | /// Interface for loading an application |
| 47 | class AppLoader : NonCopyable { | 53 | class AppLoader : NonCopyable { |
| 48 | public: | 54 | public: |
| 49 | AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { } | 55 | AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { } |
| 50 | virtual ~AppLoader() { } | 56 | virtual ~AppLoader() { } |
| 51 | 57 | ||
| 52 | /** | 58 | /** |
| @@ -60,7 +66,7 @@ public: | |||
| 60 | * @param buffer Reference to buffer to store data | 66 | * @param buffer Reference to buffer to store data |
| 61 | * @return ResultStatus result of function | 67 | * @return ResultStatus result of function |
| 62 | */ | 68 | */ |
| 63 | virtual ResultStatus ReadCode(std::vector<u8>& buffer) const { | 69 | virtual ResultStatus ReadCode(std::vector<u8>& buffer) { |
| 64 | return ResultStatus::ErrorNotImplemented; | 70 | return ResultStatus::ErrorNotImplemented; |
| 65 | } | 71 | } |
| 66 | 72 | ||
| @@ -69,7 +75,7 @@ public: | |||
| 69 | * @param buffer Reference to buffer to store data | 75 | * @param buffer Reference to buffer to store data |
| 70 | * @return ResultStatus result of function | 76 | * @return ResultStatus result of function |
| 71 | */ | 77 | */ |
| 72 | virtual ResultStatus ReadIcon(std::vector<u8>& buffer) const { | 78 | virtual ResultStatus ReadIcon(std::vector<u8>& buffer) { |
| 73 | return ResultStatus::ErrorNotImplemented; | 79 | return ResultStatus::ErrorNotImplemented; |
| 74 | } | 80 | } |
| 75 | 81 | ||
| @@ -78,7 +84,7 @@ public: | |||
| 78 | * @param buffer Reference to buffer to store data | 84 | * @param buffer Reference to buffer to store data |
| 79 | * @return ResultStatus result of function | 85 | * @return ResultStatus result of function |
| 80 | */ | 86 | */ |
| 81 | virtual ResultStatus ReadBanner(std::vector<u8>& buffer) const { | 87 | virtual ResultStatus ReadBanner(std::vector<u8>& buffer) { |
| 82 | return ResultStatus::ErrorNotImplemented; | 88 | return ResultStatus::ErrorNotImplemented; |
| 83 | } | 89 | } |
| 84 | 90 | ||
| @@ -87,22 +93,25 @@ public: | |||
| 87 | * @param buffer Reference to buffer to store data | 93 | * @param buffer Reference to buffer to store data |
| 88 | * @return ResultStatus result of function | 94 | * @return ResultStatus result of function |
| 89 | */ | 95 | */ |
| 90 | virtual ResultStatus ReadLogo(std::vector<u8>& buffer) const { | 96 | virtual ResultStatus ReadLogo(std::vector<u8>& buffer) { |
| 91 | return ResultStatus::ErrorNotImplemented; | 97 | return ResultStatus::ErrorNotImplemented; |
| 92 | } | 98 | } |
| 93 | 99 | ||
| 94 | /** | 100 | /** |
| 95 | * Get the RomFS of the application | 101 | * Get the RomFS of the application |
| 96 | * @param buffer Reference to buffer to store data | 102 | * Since the RomFS can be huge, we return a file reference instead of copying to a buffer |
| 103 | * @param romfs_file The file containing the RomFS | ||
| 104 | * @param offset The offset the romfs begins on | ||
| 105 | * @param size The size of the romfs | ||
| 97 | * @return ResultStatus result of function | 106 | * @return ResultStatus result of function |
| 98 | */ | 107 | */ |
| 99 | virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const { | 108 | virtual ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { |
| 100 | return ResultStatus::ErrorNotImplemented; | 109 | return ResultStatus::ErrorNotImplemented; |
| 101 | } | 110 | } |
| 102 | 111 | ||
| 103 | protected: | 112 | protected: |
| 104 | std::unique_ptr<FileUtil::IOFile> file; | 113 | FileUtil::IOFile file; |
| 105 | bool is_loaded = false; | 114 | bool is_loaded = false; |
| 106 | }; | 115 | }; |
| 107 | 116 | ||
| 108 | /** | 117 | /** |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 08993c4fa..094d74100 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cstring> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | 8 | ||
| 8 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| @@ -10,7 +11,7 @@ | |||
| 10 | #include "common/string_util.h" | 11 | #include "common/string_util.h" |
| 11 | #include "common/swap.h" | 12 | #include "common/swap.h" |
| 12 | 13 | ||
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/resource_limit.h" | 15 | #include "core/hle/kernel/resource_limit.h" |
| 15 | #include "core/loader/ncch.h" | 16 | #include "core/loader/ncch.h" |
| 16 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| @@ -116,7 +117,10 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) { | |||
| 116 | return FileType::Error; | 117 | return FileType::Error; |
| 117 | } | 118 | } |
| 118 | 119 | ||
| 119 | ResultStatus AppLoader_NCCH::LoadExec() const { | 120 | ResultStatus AppLoader_NCCH::LoadExec() { |
| 121 | using Kernel::SharedPtr; | ||
| 122 | using Kernel::CodeSet; | ||
| 123 | |||
| 120 | if (!is_loaded) | 124 | if (!is_loaded) |
| 121 | return ResultStatus::ErrorNotLoaded; | 125 | return ResultStatus::ErrorNotLoaded; |
| 122 | 126 | ||
| @@ -125,7 +129,30 @@ ResultStatus AppLoader_NCCH::LoadExec() const { | |||
| 125 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( | 129 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( |
| 126 | (const char*)exheader_header.codeset_info.name, 8); | 130 | (const char*)exheader_header.codeset_info.name, 8); |
| 127 | u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); | 131 | u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); |
| 128 | Kernel::g_current_process = Kernel::Process::Create(process_name, program_id); | 132 | |
| 133 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id); | ||
| 134 | |||
| 135 | codeset->code.offset = 0; | ||
| 136 | codeset->code.addr = exheader_header.codeset_info.text.address; | ||
| 137 | codeset->code.size = exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE; | ||
| 138 | |||
| 139 | codeset->rodata.offset = codeset->code.offset + codeset->code.size; | ||
| 140 | codeset->rodata.addr = exheader_header.codeset_info.ro.address; | ||
| 141 | codeset->rodata.size = exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE; | ||
| 142 | |||
| 143 | // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just | ||
| 144 | // to the regular size. Playing it safe for now. | ||
| 145 | u32 bss_page_size = (exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF; | ||
| 146 | code.resize(code.size() + bss_page_size, 0); | ||
| 147 | |||
| 148 | codeset->data.offset = codeset->rodata.offset + codeset->rodata.size; | ||
| 149 | codeset->data.addr = exheader_header.codeset_info.data.address; | ||
| 150 | codeset->data.size = exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size; | ||
| 151 | |||
| 152 | codeset->entrypoint = codeset->code.addr; | ||
| 153 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); | ||
| 154 | |||
| 155 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); | ||
| 129 | 156 | ||
| 130 | // Attach a resource limit to the process based on the resource limit category | 157 | // Attach a resource limit to the process based on the resource limit category |
| 131 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( | 158 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( |
| @@ -136,18 +163,16 @@ ResultStatus AppLoader_NCCH::LoadExec() const { | |||
| 136 | std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); | 163 | std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); |
| 137 | Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); | 164 | Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); |
| 138 | 165 | ||
| 139 | Memory::WriteBlock(entry_point, &code[0], code.size()); | ||
| 140 | |||
| 141 | s32 priority = exheader_header.arm11_system_local_caps.priority; | 166 | s32 priority = exheader_header.arm11_system_local_caps.priority; |
| 142 | u32 stack_size = exheader_header.codeset_info.stack_size; | 167 | u32 stack_size = exheader_header.codeset_info.stack_size; |
| 143 | Kernel::g_current_process->Run(entry_point, priority, stack_size); | 168 | Kernel::g_current_process->Run(priority, stack_size); |
| 144 | return ResultStatus::Success; | 169 | return ResultStatus::Success; |
| 145 | } | 170 | } |
| 146 | return ResultStatus::Error; | 171 | return ResultStatus::Error; |
| 147 | } | 172 | } |
| 148 | 173 | ||
| 149 | ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { | 174 | ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) { |
| 150 | if (!file->IsOpen()) | 175 | if (!file.IsOpen()) |
| 151 | return ResultStatus::Error; | 176 | return ResultStatus::Error; |
| 152 | 177 | ||
| 153 | LOG_DEBUG(Loader, "%d sections:", kMaxSections); | 178 | LOG_DEBUG(Loader, "%d sections:", kMaxSections); |
| @@ -161,7 +186,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& | |||
| 161 | section.offset, section.size, section.name); | 186 | section.offset, section.size, section.name); |
| 162 | 187 | ||
| 163 | s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset); | 188 | s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset); |
| 164 | file->Seek(section_offset, SEEK_SET); | 189 | file.Seek(section_offset, SEEK_SET); |
| 165 | 190 | ||
| 166 | if (is_compressed) { | 191 | if (is_compressed) { |
| 167 | // Section is compressed, read compressed .code section... | 192 | // Section is compressed, read compressed .code section... |
| @@ -172,7 +197,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& | |||
| 172 | return ResultStatus::ErrorMemoryAllocationFailed; | 197 | return ResultStatus::ErrorMemoryAllocationFailed; |
| 173 | } | 198 | } |
| 174 | 199 | ||
| 175 | if (file->ReadBytes(&temp_buffer[0], section.size) != section.size) | 200 | if (file.ReadBytes(&temp_buffer[0], section.size) != section.size) |
| 176 | return ResultStatus::Error; | 201 | return ResultStatus::Error; |
| 177 | 202 | ||
| 178 | // Decompress .code section... | 203 | // Decompress .code section... |
| @@ -183,7 +208,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& | |||
| 183 | } else { | 208 | } else { |
| 184 | // Section is uncompressed... | 209 | // Section is uncompressed... |
| 185 | buffer.resize(section.size); | 210 | buffer.resize(section.size); |
| 186 | if (file->ReadBytes(&buffer[0], section.size) != section.size) | 211 | if (file.ReadBytes(&buffer[0], section.size) != section.size) |
| 187 | return ResultStatus::Error; | 212 | return ResultStatus::Error; |
| 188 | } | 213 | } |
| 189 | return ResultStatus::Success; | 214 | return ResultStatus::Success; |
| @@ -196,21 +221,21 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 196 | if (is_loaded) | 221 | if (is_loaded) |
| 197 | return ResultStatus::ErrorAlreadyLoaded; | 222 | return ResultStatus::ErrorAlreadyLoaded; |
| 198 | 223 | ||
| 199 | if (!file->IsOpen()) | 224 | if (!file.IsOpen()) |
| 200 | return ResultStatus::Error; | 225 | return ResultStatus::Error; |
| 201 | 226 | ||
| 202 | // Reset read pointer in case this file has been read before. | 227 | // Reset read pointer in case this file has been read before. |
| 203 | file->Seek(0, SEEK_SET); | 228 | file.Seek(0, SEEK_SET); |
| 204 | 229 | ||
| 205 | if (file->ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header)) | 230 | if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header)) |
| 206 | return ResultStatus::Error; | 231 | return ResultStatus::Error; |
| 207 | 232 | ||
| 208 | // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... | 233 | // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... |
| 209 | if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { | 234 | if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { |
| 210 | LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); | 235 | LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); |
| 211 | ncch_offset = 0x4000; | 236 | ncch_offset = 0x4000; |
| 212 | file->Seek(ncch_offset, SEEK_SET); | 237 | file.Seek(ncch_offset, SEEK_SET); |
| 213 | file->ReadBytes(&ncch_header, sizeof(NCCH_Header)); | 238 | file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); |
| 214 | } | 239 | } |
| 215 | 240 | ||
| 216 | // Verify we are loading the correct file type... | 241 | // Verify we are loading the correct file type... |
| @@ -219,7 +244,7 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 219 | 244 | ||
| 220 | // Read ExHeader... | 245 | // Read ExHeader... |
| 221 | 246 | ||
| 222 | if (file->ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header)) | 247 | if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header)) |
| 223 | return ResultStatus::Error; | 248 | return ResultStatus::Error; |
| 224 | 249 | ||
| 225 | is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; | 250 | is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; |
| @@ -239,7 +264,6 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 239 | LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); | 264 | LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); |
| 240 | LOG_DEBUG(Loader, "Core version: %d" , core_version); | 265 | LOG_DEBUG(Loader, "Core version: %d" , core_version); |
| 241 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); | 266 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); |
| 242 | LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor); | ||
| 243 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); | 267 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); |
| 244 | 268 | ||
| 245 | // Read ExeFS... | 269 | // Read ExeFS... |
| @@ -250,8 +274,8 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 250 | LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset); | 274 | LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset); |
| 251 | LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size); | 275 | LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size); |
| 252 | 276 | ||
| 253 | file->Seek(exefs_offset + ncch_offset, SEEK_SET); | 277 | file.Seek(exefs_offset + ncch_offset, SEEK_SET); |
| 254 | if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header)) | 278 | if (file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header)) |
| 255 | return ResultStatus::Error; | 279 | return ResultStatus::Error; |
| 256 | 280 | ||
| 257 | is_loaded = true; // Set state to loaded | 281 | is_loaded = true; // Set state to loaded |
| @@ -259,24 +283,24 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 259 | return LoadExec(); // Load the executable into memory for booting | 283 | return LoadExec(); // Load the executable into memory for booting |
| 260 | } | 284 | } |
| 261 | 285 | ||
| 262 | ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const { | 286 | ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) { |
| 263 | return LoadSectionExeFS(".code", buffer); | 287 | return LoadSectionExeFS(".code", buffer); |
| 264 | } | 288 | } |
| 265 | 289 | ||
| 266 | ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) const { | 290 | ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) { |
| 267 | return LoadSectionExeFS("icon", buffer); | 291 | return LoadSectionExeFS("icon", buffer); |
| 268 | } | 292 | } |
| 269 | 293 | ||
| 270 | ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) const { | 294 | ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) { |
| 271 | return LoadSectionExeFS("banner", buffer); | 295 | return LoadSectionExeFS("banner", buffer); |
| 272 | } | 296 | } |
| 273 | 297 | ||
| 274 | ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const { | 298 | ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) { |
| 275 | return LoadSectionExeFS("logo", buffer); | 299 | return LoadSectionExeFS("logo", buffer); |
| 276 | } | 300 | } |
| 277 | 301 | ||
| 278 | ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { | 302 | ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { |
| 279 | if (!file->IsOpen()) | 303 | if (!file.IsOpen()) |
| 280 | return ResultStatus::Error; | 304 | return ResultStatus::Error; |
| 281 | 305 | ||
| 282 | // Check if the NCCH has a RomFS... | 306 | // Check if the NCCH has a RomFS... |
| @@ -287,12 +311,17 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { | |||
| 287 | LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); | 311 | LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); |
| 288 | LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); | 312 | LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); |
| 289 | 313 | ||
| 290 | buffer.resize(romfs_size); | 314 | if (file.GetSize () < romfs_offset + romfs_size) |
| 315 | return ResultStatus::Error; | ||
| 291 | 316 | ||
| 292 | file->Seek(romfs_offset, SEEK_SET); | 317 | // We reopen the file, to allow its position to be independent from file's |
| 293 | if (file->ReadBytes(&buffer[0], romfs_size) != romfs_size) | 318 | romfs_file = std::make_shared<FileUtil::IOFile>(filepath, "rb"); |
| 319 | if (!romfs_file->IsOpen()) | ||
| 294 | return ResultStatus::Error; | 320 | return ResultStatus::Error; |
| 295 | 321 | ||
| 322 | offset = romfs_offset; | ||
| 323 | size = romfs_size; | ||
| 324 | |||
| 296 | return ResultStatus::Success; | 325 | return ResultStatus::Success; |
| 297 | } | 326 | } |
| 298 | LOG_DEBUG(Loader, "NCCH has no RomFS"); | 327 | LOG_DEBUG(Loader, "NCCH has no RomFS"); |
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index 29e39d2c0..b4374a476 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h | |||
| @@ -163,7 +163,8 @@ namespace Loader { | |||
| 163 | /// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) | 163 | /// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) |
| 164 | class AppLoader_NCCH final : public AppLoader { | 164 | class AppLoader_NCCH final : public AppLoader { |
| 165 | public: | 165 | public: |
| 166 | AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { } | 166 | AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath) |
| 167 | : AppLoader(std::move(file)), filepath(filepath) { } | ||
| 167 | 168 | ||
| 168 | /** | 169 | /** |
| 169 | * Returns the type of the file | 170 | * Returns the type of the file |
| @@ -183,35 +184,35 @@ public: | |||
| 183 | * @param buffer Reference to buffer to store data | 184 | * @param buffer Reference to buffer to store data |
| 184 | * @return ResultStatus result of function | 185 | * @return ResultStatus result of function |
| 185 | */ | 186 | */ |
| 186 | ResultStatus ReadCode(std::vector<u8>& buffer) const override; | 187 | ResultStatus ReadCode(std::vector<u8>& buffer) override; |
| 187 | 188 | ||
| 188 | /** | 189 | /** |
| 189 | * Get the icon (typically icon section) of the application | 190 | * Get the icon (typically icon section) of the application |
| 190 | * @param buffer Reference to buffer to store data | 191 | * @param buffer Reference to buffer to store data |
| 191 | * @return ResultStatus result of function | 192 | * @return ResultStatus result of function |
| 192 | */ | 193 | */ |
| 193 | ResultStatus ReadIcon(std::vector<u8>& buffer) const override; | 194 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 194 | 195 | ||
| 195 | /** | 196 | /** |
| 196 | * Get the banner (typically banner section) of the application | 197 | * Get the banner (typically banner section) of the application |
| 197 | * @param buffer Reference to buffer to store data | 198 | * @param buffer Reference to buffer to store data |
| 198 | * @return ResultStatus result of function | 199 | * @return ResultStatus result of function |
| 199 | */ | 200 | */ |
| 200 | ResultStatus ReadBanner(std::vector<u8>& buffer) const override; | 201 | ResultStatus ReadBanner(std::vector<u8>& buffer) override; |
| 201 | 202 | ||
| 202 | /** | 203 | /** |
| 203 | * Get the logo (typically logo section) of the application | 204 | * Get the logo (typically logo section) of the application |
| 204 | * @param buffer Reference to buffer to store data | 205 | * @param buffer Reference to buffer to store data |
| 205 | * @return ResultStatus result of function | 206 | * @return ResultStatus result of function |
| 206 | */ | 207 | */ |
| 207 | ResultStatus ReadLogo(std::vector<u8>& buffer) const override; | 208 | ResultStatus ReadLogo(std::vector<u8>& buffer) override; |
| 208 | 209 | ||
| 209 | /** | 210 | /** |
| 210 | * Get the RomFS of the application | 211 | * Get the RomFS of the application |
| 211 | * @param buffer Reference to buffer to store data | 212 | * @param buffer Reference to buffer to store data |
| 212 | * @return ResultStatus result of function | 213 | * @return ResultStatus result of function |
| 213 | */ | 214 | */ |
| 214 | ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; | 215 | ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override; |
| 215 | 216 | ||
| 216 | private: | 217 | private: |
| 217 | 218 | ||
| @@ -221,13 +222,13 @@ private: | |||
| 221 | * @param buffer Vector to read data into | 222 | * @param buffer Vector to read data into |
| 222 | * @return ResultStatus result of function | 223 | * @return ResultStatus result of function |
| 223 | */ | 224 | */ |
| 224 | ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const; | 225 | ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer); |
| 225 | 226 | ||
| 226 | /** | 227 | /** |
| 227 | * Loads .code section into memory for booting | 228 | * Loads .code section into memory for booting |
| 228 | * @return ResultStatus result of function | 229 | * @return ResultStatus result of function |
| 229 | */ | 230 | */ |
| 230 | ResultStatus LoadExec() const; | 231 | ResultStatus LoadExec(); |
| 231 | 232 | ||
| 232 | bool is_compressed = false; | 233 | bool is_compressed = false; |
| 233 | 234 | ||
| @@ -244,6 +245,8 @@ private: | |||
| 244 | NCCH_Header ncch_header; | 245 | NCCH_Header ncch_header; |
| 245 | ExeFs_Header exefs_header; | 246 | ExeFs_Header exefs_header; |
| 246 | ExHeader_Header exheader_header; | 247 | ExHeader_Header exheader_header; |
| 248 | |||
| 249 | std::string filepath; | ||
| 247 | }; | 250 | }; |
| 248 | 251 | ||
| 249 | } // namespace Loader | 252 | } // namespace Loader |
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index bf814b945..cbe993fbe 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp | |||
| @@ -3,13 +3,14 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <map> | 5 | #include <map> |
| 6 | #include <memory> | ||
| 7 | #include <utility> | ||
| 8 | #include <vector> | ||
| 6 | 9 | ||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 9 | 12 | ||
| 10 | #include "core/hle/config_mem.h" | 13 | #include "core/hle/config_mem.h" |
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/shared_memory.h" | ||
| 13 | #include "core/hle/kernel/vm_manager.h" | 14 | #include "core/hle/kernel/vm_manager.h" |
| 14 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 15 | #include "core/hle/shared_page.h" | 16 | #include "core/hle/shared_page.h" |
| @@ -31,7 +32,6 @@ struct MemoryArea { | |||
| 31 | 32 | ||
| 32 | // We don't declare the IO regions in here since its handled by other means. | 33 | // We don't declare the IO regions in here since its handled by other means. |
| 33 | static MemoryArea memory_areas[] = { | 34 | static MemoryArea memory_areas[] = { |
| 34 | {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here | ||
| 35 | {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory) | 35 | {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory) |
| 36 | {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory | 36 | {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory |
| 37 | {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory) | 37 | {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory) |
| @@ -131,13 +131,13 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { | |||
| 131 | return addr | 0x80000000; | 131 | return addr | 0x80000000; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | // TODO(yuriks): Move this into Process | ||
| 135 | static Kernel::VMManager address_space; | ||
| 136 | |||
| 137 | void Init() { | 134 | void Init() { |
| 138 | using namespace Kernel; | ||
| 139 | |||
| 140 | InitMemoryMap(); | 135 | InitMemoryMap(); |
| 136 | LOG_DEBUG(HW_Memory, "initialized OK"); | ||
| 137 | } | ||
| 138 | |||
| 139 | void InitLegacyAddressSpace(Kernel::VMManager& address_space) { | ||
| 140 | using namespace Kernel; | ||
| 141 | 141 | ||
| 142 | for (MemoryArea& area : memory_areas) { | 142 | for (MemoryArea& area : memory_areas) { |
| 143 | auto block = std::make_shared<std::vector<u8>>(area.size); | 143 | auto block = std::make_shared<std::vector<u8>>(area.size); |
| @@ -151,14 +151,11 @@ void Init() { | |||
| 151 | auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, | 151 | auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, |
| 152 | (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); | 152 | (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); |
| 153 | address_space.Reprotect(shared_page_vma, VMAPermission::Read); | 153 | address_space.Reprotect(shared_page_vma, VMAPermission::Read); |
| 154 | |||
| 155 | LOG_DEBUG(HW_Memory, "initialized OK"); | ||
| 156 | } | 154 | } |
| 157 | 155 | ||
| 158 | void Shutdown() { | 156 | void Shutdown() { |
| 159 | heap_map.clear(); | 157 | heap_map.clear(); |
| 160 | heap_linear_map.clear(); | 158 | heap_linear_map.clear(); |
| 161 | address_space.Reset(); | ||
| 162 | 159 | ||
| 163 | LOG_DEBUG(HW_Memory, "shutdown OK"); | 160 | LOG_DEBUG(HW_Memory, "shutdown OK"); |
| 164 | } | 161 | } |
diff --git a/src/core/mem_map.h b/src/core/mem_map.h index ba50914a8..229ef82c5 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h | |||
| @@ -6,9 +6,14 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | 8 | ||
| 9 | namespace Kernel { | ||
| 10 | class VMManager; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Memory { | 13 | namespace Memory { |
| 10 | 14 | ||
| 11 | void Init(); | 15 | void Init(); |
| 16 | void InitLegacyAddressSpace(Kernel::VMManager& address_space); | ||
| 12 | void Shutdown(); | 17 | void Shutdown(); |
| 13 | 18 | ||
| 14 | /** | 19 | /** |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 28844a915..1f66bb27d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -9,9 +9,6 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | 11 | ||
| 12 | #include "core/hle/config_mem.h" | ||
| 13 | #include "core/hle/shared_page.h" | ||
| 14 | #include "core/hw/hw.h" | ||
| 15 | #include "core/mem_map.h" | 12 | #include "core/mem_map.h" |
| 16 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| 17 | #include "core/memory_setup.h" | 14 | #include "core/memory_setup.h" |
| @@ -62,14 +59,12 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | |||
| 62 | while (base != end) { | 59 | while (base != end) { |
| 63 | ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); | 60 | ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); |
| 64 | 61 | ||
| 65 | if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) { | ||
| 66 | LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); | ||
| 67 | } | ||
| 68 | current_page_table->attributes[base] = type; | 62 | current_page_table->attributes[base] = type; |
| 69 | current_page_table->pointers[base] = memory; | 63 | current_page_table->pointers[base] = memory; |
| 70 | 64 | ||
| 71 | base += 1; | 65 | base += 1; |
| 72 | memory += PAGE_SIZE; | 66 | if (memory != nullptr) |
| 67 | memory += PAGE_SIZE; | ||
| 73 | } | 68 | } |
| 74 | } | 69 | } |
| 75 | 70 | ||
diff --git a/src/core/memory.h b/src/core/memory.h index 0b8ff9ec4..418609de0 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | namespace Memory { | 11 | namespace Memory { |
diff --git a/src/core/settings.h b/src/core/settings.h index 5a70d157a..2775ee257 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -5,34 +5,42 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <array> | ||
| 8 | 9 | ||
| 9 | namespace Settings { | 10 | namespace Settings { |
| 10 | 11 | ||
| 12 | namespace NativeInput { | ||
| 13 | enum Values { | ||
| 14 | A, B, X, Y, | ||
| 15 | L, R, ZL, ZR, | ||
| 16 | START, SELECT, HOME, | ||
| 17 | DUP, DDOWN, DLEFT, DRIGHT, | ||
| 18 | SUP, SDOWN, SLEFT, SRIGHT, | ||
| 19 | CUP, CDOWN, CLEFT, CRIGHT, | ||
| 20 | NUM_INPUTS | ||
| 21 | }; | ||
| 22 | static const std::array<const char*, NUM_INPUTS> Mapping = { | ||
| 23 | "pad_a", "pad_b", "pad_x", "pad_y", | ||
| 24 | "pad_l", "pad_r", "pad_zl", "pad_zr", | ||
| 25 | "pad_start", "pad_select", "pad_home", | ||
| 26 | "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", | ||
| 27 | "pad_sup", "pad_sdown", "pad_sleft", "pad_sright", | ||
| 28 | "pad_cup", "pad_cdown", "pad_cleft", "pad_cright" | ||
| 29 | }; | ||
| 30 | static const std::array<Values, NUM_INPUTS> All = { | ||
| 31 | A, B, X, Y, | ||
| 32 | L, R, ZL, ZR, | ||
| 33 | START, SELECT, HOME, | ||
| 34 | DUP, DDOWN, DLEFT, DRIGHT, | ||
| 35 | SUP, SDOWN, SLEFT, SRIGHT, | ||
| 36 | CUP, CDOWN, CLEFT, CRIGHT | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | |||
| 11 | struct Values { | 41 | struct Values { |
| 12 | // Controls | 42 | // Controls |
| 13 | int pad_a_key; | 43 | std::array<int, NativeInput::NUM_INPUTS> input_mappings; |
| 14 | int pad_b_key; | ||
| 15 | int pad_x_key; | ||
| 16 | int pad_y_key; | ||
| 17 | int pad_l_key; | ||
| 18 | int pad_r_key; | ||
| 19 | int pad_zl_key; | ||
| 20 | int pad_zr_key; | ||
| 21 | int pad_start_key; | ||
| 22 | int pad_select_key; | ||
| 23 | int pad_home_key; | ||
| 24 | int pad_dup_key; | ||
| 25 | int pad_ddown_key; | ||
| 26 | int pad_dleft_key; | ||
| 27 | int pad_dright_key; | ||
| 28 | int pad_sup_key; | ||
| 29 | int pad_sdown_key; | ||
| 30 | int pad_sleft_key; | ||
| 31 | int pad_sright_key; | ||
| 32 | int pad_cup_key; | ||
| 33 | int pad_cdown_key; | ||
| 34 | int pad_cleft_key; | ||
| 35 | int pad_cright_key; | ||
| 36 | 44 | ||
| 37 | // Core | 45 | // Core |
| 38 | int frame_skip; | 46 | int frame_skip; |
diff --git a/src/core/tracer/citrace.h b/src/core/tracer/citrace.h new file mode 100644 index 000000000..5deb6ce9e --- /dev/null +++ b/src/core/tracer/citrace.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstdint> | ||
| 8 | |||
| 9 | namespace CiTrace { | ||
| 10 | |||
| 11 | // NOTE: Things are stored in little-endian | ||
| 12 | |||
| 13 | #pragma pack(1) | ||
| 14 | |||
| 15 | struct CTHeader { | ||
| 16 | static const char* ExpectedMagicWord() { | ||
| 17 | return "CiTr"; | ||
| 18 | } | ||
| 19 | |||
| 20 | static uint32_t ExpectedVersion() { | ||
| 21 | return 1; | ||
| 22 | } | ||
| 23 | |||
| 24 | char magic[4]; | ||
| 25 | uint32_t version; | ||
| 26 | uint32_t header_size; | ||
| 27 | |||
| 28 | struct { | ||
| 29 | // NOTE: Register range sizes are technically hardware-constants, but the actual limits | ||
| 30 | // aren't known. Hence we store the presumed limits along the offsets. | ||
| 31 | // Sizes are given in uint32_t units. | ||
| 32 | uint32_t gpu_registers; | ||
| 33 | uint32_t gpu_registers_size; | ||
| 34 | uint32_t lcd_registers; | ||
| 35 | uint32_t lcd_registers_size; | ||
| 36 | uint32_t pica_registers; | ||
| 37 | uint32_t pica_registers_size; | ||
| 38 | uint32_t default_attributes; | ||
| 39 | uint32_t default_attributes_size; | ||
| 40 | uint32_t vs_program_binary; | ||
| 41 | uint32_t vs_program_binary_size; | ||
| 42 | uint32_t vs_swizzle_data; | ||
| 43 | uint32_t vs_swizzle_data_size; | ||
| 44 | uint32_t vs_float_uniforms; | ||
| 45 | uint32_t vs_float_uniforms_size; | ||
| 46 | uint32_t gs_program_binary; | ||
| 47 | uint32_t gs_program_binary_size; | ||
| 48 | uint32_t gs_swizzle_data; | ||
| 49 | uint32_t gs_swizzle_data_size; | ||
| 50 | uint32_t gs_float_uniforms; | ||
| 51 | uint32_t gs_float_uniforms_size; | ||
| 52 | |||
| 53 | // Other things we might want to store here: | ||
| 54 | // - Initial framebuffer data, maybe even a full copy of FCRAM/VRAM | ||
| 55 | // - Lookup tables for fragment lighting | ||
| 56 | // - Lookup tables for procedural textures | ||
| 57 | } initial_state_offsets; | ||
| 58 | |||
| 59 | uint32_t stream_offset; | ||
| 60 | uint32_t stream_size; | ||
| 61 | }; | ||
| 62 | |||
| 63 | enum CTStreamElementType : uint32_t { | ||
| 64 | FrameMarker = 0xE1, | ||
| 65 | MemoryLoad = 0xE2, | ||
| 66 | RegisterWrite = 0xE3, | ||
| 67 | }; | ||
| 68 | |||
| 69 | struct CTMemoryLoad { | ||
| 70 | uint32_t file_offset; | ||
| 71 | uint32_t size; | ||
| 72 | uint32_t physical_address; | ||
| 73 | uint32_t pad; | ||
| 74 | }; | ||
| 75 | |||
| 76 | struct CTRegisterWrite { | ||
| 77 | uint32_t physical_address; | ||
| 78 | |||
| 79 | enum : uint32_t { | ||
| 80 | SIZE_8 = 0xD1, | ||
| 81 | SIZE_16 = 0xD2, | ||
| 82 | SIZE_32 = 0xD3, | ||
| 83 | SIZE_64 = 0xD4 | ||
| 84 | } size; | ||
| 85 | |||
| 86 | // TODO: Make it clearer which bits of this member are used for sizes other than 32 bits | ||
| 87 | uint64_t value; | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct CTStreamElement { | ||
| 91 | CTStreamElementType type; | ||
| 92 | |||
| 93 | union { | ||
| 94 | CTMemoryLoad memory_load; | ||
| 95 | CTRegisterWrite register_write; | ||
| 96 | }; | ||
| 97 | }; | ||
| 98 | |||
| 99 | #pragma pack() | ||
| 100 | |||
| 101 | } | ||
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp new file mode 100644 index 000000000..656706c0c --- /dev/null +++ b/src/core/tracer/recorder.cpp | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | #include "common/logging/log.h" | ||
| 10 | |||
| 11 | #include "recorder.h" | ||
| 12 | |||
| 13 | namespace CiTrace { | ||
| 14 | |||
| 15 | Recorder::Recorder(const InitialState& initial_state) : initial_state(initial_state) { | ||
| 16 | |||
| 17 | } | ||
| 18 | |||
| 19 | void Recorder::Finish(const std::string& filename) { | ||
| 20 | // Setup CiTrace header | ||
| 21 | CTHeader header; | ||
| 22 | std::memcpy(header.magic, CTHeader::ExpectedMagicWord(), 4); | ||
| 23 | header.version = CTHeader::ExpectedVersion(); | ||
| 24 | header.header_size = sizeof(CTHeader); | ||
| 25 | |||
| 26 | // Calculate file offsets | ||
| 27 | auto& initial = header.initial_state_offsets; | ||
| 28 | |||
| 29 | initial.gpu_registers_size = initial_state.gpu_registers.size(); | ||
| 30 | initial.lcd_registers_size = initial_state.lcd_registers.size(); | ||
| 31 | initial.pica_registers_size = initial_state.pica_registers.size(); | ||
| 32 | initial.default_attributes_size = initial_state.default_attributes.size(); | ||
| 33 | initial.vs_program_binary_size = initial_state.vs_program_binary.size(); | ||
| 34 | initial.vs_swizzle_data_size = initial_state.vs_swizzle_data.size(); | ||
| 35 | initial.vs_float_uniforms_size = initial_state.vs_float_uniforms.size(); | ||
| 36 | initial.gs_program_binary_size = initial_state.gs_program_binary.size(); | ||
| 37 | initial.gs_swizzle_data_size = initial_state.gs_swizzle_data.size(); | ||
| 38 | initial.gs_float_uniforms_size = initial_state.gs_float_uniforms.size(); | ||
| 39 | header.stream_size = stream.size(); | ||
| 40 | |||
| 41 | initial.gpu_registers = sizeof(header); | ||
| 42 | initial.lcd_registers = initial.gpu_registers + initial.gpu_registers_size * sizeof(u32); | ||
| 43 | initial.pica_registers = initial.lcd_registers + initial.lcd_registers_size * sizeof(u32);; | ||
| 44 | initial.default_attributes = initial.pica_registers + initial.pica_registers_size * sizeof(u32); | ||
| 45 | initial.vs_program_binary = initial.default_attributes + initial.default_attributes_size * sizeof(u32); | ||
| 46 | initial.vs_swizzle_data = initial.vs_program_binary + initial.vs_program_binary_size * sizeof(u32); | ||
| 47 | initial.vs_float_uniforms = initial.vs_swizzle_data + initial.vs_swizzle_data_size * sizeof(u32); | ||
| 48 | initial.gs_program_binary = initial.vs_float_uniforms + initial.vs_float_uniforms_size * sizeof(u32); | ||
| 49 | initial.gs_swizzle_data = initial.gs_program_binary + initial.gs_program_binary_size * sizeof(u32); | ||
| 50 | initial.gs_float_uniforms = initial.gs_swizzle_data + initial.gs_swizzle_data_size * sizeof(u32); | ||
| 51 | header.stream_offset = initial.gs_float_uniforms + initial.gs_float_uniforms_size * sizeof(u32); | ||
| 52 | |||
| 53 | // Iterate through stream elements, update relevant stream element data | ||
| 54 | for (auto& stream_element : stream) { | ||
| 55 | switch (stream_element.data.type) { | ||
| 56 | case MemoryLoad: | ||
| 57 | { | ||
| 58 | auto& file_offset = memory_regions[stream_element.hash]; | ||
| 59 | if (!stream_element.uses_existing_data) { | ||
| 60 | file_offset = header.stream_offset; | ||
| 61 | } | ||
| 62 | stream_element.data.memory_load.file_offset = file_offset; | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | |||
| 66 | default: | ||
| 67 | // Other commands don't use any extra data | ||
| 68 | DEBUG_ASSERT(stream_element.extra_data.size() == 0); | ||
| 69 | break; | ||
| 70 | } | ||
| 71 | header.stream_offset += stream_element.extra_data.size(); | ||
| 72 | } | ||
| 73 | |||
| 74 | try { | ||
| 75 | // Open file and write header | ||
| 76 | FileUtil::IOFile file(filename, "wb"); | ||
| 77 | size_t written = file.WriteObject(header); | ||
| 78 | if (written != 1 || file.Tell() != initial.gpu_registers) | ||
| 79 | throw "Failed to write header"; | ||
| 80 | |||
| 81 | // Write initial state | ||
| 82 | written = file.WriteArray(initial_state.gpu_registers.data(), initial_state.gpu_registers.size()); | ||
| 83 | if (written != initial_state.gpu_registers.size() || file.Tell() != initial.lcd_registers) | ||
| 84 | throw "Failed to write GPU registers"; | ||
| 85 | |||
| 86 | written = file.WriteArray(initial_state.lcd_registers.data(), initial_state.lcd_registers.size()); | ||
| 87 | if (written != initial_state.lcd_registers.size() || file.Tell() != initial.pica_registers) | ||
| 88 | throw "Failed to write LCD registers"; | ||
| 89 | |||
| 90 | written = file.WriteArray(initial_state.pica_registers.data(), initial_state.pica_registers.size()); | ||
| 91 | if (written != initial_state.pica_registers.size() || file.Tell() != initial.default_attributes) | ||
| 92 | throw "Failed to write Pica registers"; | ||
| 93 | |||
| 94 | written = file.WriteArray(initial_state.default_attributes.data(), initial_state.default_attributes.size()); | ||
| 95 | if (written != initial_state.default_attributes.size() || file.Tell() != initial.vs_program_binary) | ||
| 96 | throw "Failed to write default vertex attributes"; | ||
| 97 | |||
| 98 | written = file.WriteArray(initial_state.vs_program_binary.data(), initial_state.vs_program_binary.size()); | ||
| 99 | if (written != initial_state.vs_program_binary.size() || file.Tell() != initial.vs_swizzle_data) | ||
| 100 | throw "Failed to write vertex shader program binary"; | ||
| 101 | |||
| 102 | written = file.WriteArray(initial_state.vs_swizzle_data.data(), initial_state.vs_swizzle_data.size()); | ||
| 103 | if (written != initial_state.vs_swizzle_data.size() || file.Tell() != initial.vs_float_uniforms) | ||
| 104 | throw "Failed to write vertex shader swizzle data"; | ||
| 105 | |||
| 106 | written = file.WriteArray(initial_state.vs_float_uniforms.data(), initial_state.vs_float_uniforms.size()); | ||
| 107 | if (written != initial_state.vs_float_uniforms.size() || file.Tell() != initial.gs_program_binary) | ||
| 108 | throw "Failed to write vertex shader float uniforms"; | ||
| 109 | |||
| 110 | written = file.WriteArray(initial_state.gs_program_binary.data(), initial_state.gs_program_binary.size()); | ||
| 111 | if (written != initial_state.gs_program_binary.size() || file.Tell() != initial.gs_swizzle_data) | ||
| 112 | throw "Failed to write geomtry shader program binary"; | ||
| 113 | |||
| 114 | written = file.WriteArray(initial_state.gs_swizzle_data.data(), initial_state.gs_swizzle_data.size()); | ||
| 115 | if (written != initial_state.gs_swizzle_data.size() || file.Tell() != initial.gs_float_uniforms) | ||
| 116 | throw "Failed to write geometry shader swizzle data"; | ||
| 117 | |||
| 118 | written = file.WriteArray(initial_state.gs_float_uniforms.data(), initial_state.gs_float_uniforms.size()); | ||
| 119 | if (written != initial_state.gs_float_uniforms.size() || file.Tell() != initial.gs_float_uniforms + sizeof(u32) * initial.gs_float_uniforms_size) | ||
| 120 | throw "Failed to write geometry shader float uniforms"; | ||
| 121 | |||
| 122 | // Iterate through stream elements, write "extra data" | ||
| 123 | for (const auto& stream_element : stream) { | ||
| 124 | if (stream_element.extra_data.size() == 0) | ||
| 125 | continue; | ||
| 126 | |||
| 127 | written = file.WriteBytes(stream_element.extra_data.data(), stream_element.extra_data.size()); | ||
| 128 | if (written != stream_element.extra_data.size()) | ||
| 129 | throw "Failed to write extra data"; | ||
| 130 | } | ||
| 131 | |||
| 132 | if (file.Tell() != header.stream_offset) | ||
| 133 | throw "Unexpected end of extra data"; | ||
| 134 | |||
| 135 | // Write actual stream elements | ||
| 136 | for (const auto& stream_element : stream) { | ||
| 137 | if (1 != file.WriteObject(stream_element.data)) | ||
| 138 | throw "Failed to write stream element"; | ||
| 139 | } | ||
| 140 | } catch(const char* str) { | ||
| 141 | LOG_ERROR(HW_GPU, "Writing CiTrace file failed: %s", str); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | void Recorder::FrameFinished() { | ||
| 146 | stream.push_back( { FrameMarker } ); | ||
| 147 | } | ||
| 148 | |||
| 149 | void Recorder::MemoryAccessed(const u8* data, u32 size, u32 physical_address) { | ||
| 150 | StreamElement element = { MemoryLoad }; | ||
| 151 | element.data.memory_load.size = size; | ||
| 152 | element.data.memory_load.physical_address = physical_address; | ||
| 153 | |||
| 154 | // Compute hash over given memory region to check if the contents are already stored internally | ||
| 155 | boost::crc_32_type result; | ||
| 156 | result.process_bytes(data, size); | ||
| 157 | element.hash = result.checksum(); | ||
| 158 | |||
| 159 | element.uses_existing_data = (memory_regions.find(element.hash) != memory_regions.end()); | ||
| 160 | if (!element.uses_existing_data) { | ||
| 161 | element.extra_data.resize(size); | ||
| 162 | memcpy(element.extra_data.data(), data, size); | ||
| 163 | memory_regions.insert({element.hash, 0}); // file offset will be initialized in Finish() | ||
| 164 | } | ||
| 165 | |||
| 166 | stream.push_back(element); | ||
| 167 | } | ||
| 168 | |||
| 169 | template<typename T> | ||
| 170 | void Recorder::RegisterWritten(u32 physical_address, T value) { | ||
| 171 | StreamElement element = { RegisterWrite }; | ||
| 172 | element.data.register_write.size = (sizeof(T) == 1) ? CTRegisterWrite::SIZE_8 | ||
| 173 | : (sizeof(T) == 2) ? CTRegisterWrite::SIZE_16 | ||
| 174 | : (sizeof(T) == 4) ? CTRegisterWrite::SIZE_32 | ||
| 175 | : CTRegisterWrite::SIZE_64; | ||
| 176 | element.data.register_write.physical_address = physical_address; | ||
| 177 | element.data.register_write.value = value; | ||
| 178 | |||
| 179 | stream.push_back(element); | ||
| 180 | } | ||
| 181 | |||
| 182 | template void Recorder::RegisterWritten(u32,u8); | ||
| 183 | template void Recorder::RegisterWritten(u32,u16); | ||
| 184 | template void Recorder::RegisterWritten(u32,u32); | ||
| 185 | template void Recorder::RegisterWritten(u32,u64); | ||
| 186 | |||
| 187 | } | ||
diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h new file mode 100644 index 000000000..6e4b70015 --- /dev/null +++ b/src/core/tracer/recorder.h | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <unordered_map> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include <boost/crc.hpp> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | |||
| 14 | #include "citrace.h" | ||
| 15 | |||
| 16 | namespace CiTrace { | ||
| 17 | |||
| 18 | class Recorder { | ||
| 19 | public: | ||
| 20 | struct InitialState { | ||
| 21 | std::vector<u32> gpu_registers; | ||
| 22 | std::vector<u32> lcd_registers; | ||
| 23 | std::vector<u32> pica_registers; | ||
| 24 | std::vector<u32> default_attributes; | ||
| 25 | std::vector<u32> vs_program_binary; | ||
| 26 | std::vector<u32> vs_swizzle_data; | ||
| 27 | std::vector<u32> vs_float_uniforms; | ||
| 28 | std::vector<u32> gs_program_binary; | ||
| 29 | std::vector<u32> gs_swizzle_data; | ||
| 30 | std::vector<u32> gs_float_uniforms; | ||
| 31 | }; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Recorder constructor | ||
| 35 | * @param default_attributes Pointer to an array of 32-bit-aligned 24-bit floating point values. | ||
| 36 | * @param vs_float_uniforms Pointer to an array of 32-bit-aligned 24-bit floating point values. | ||
| 37 | */ | ||
| 38 | Recorder(const InitialState& initial_state); | ||
| 39 | |||
| 40 | /// Finish recording of this Citrace and save it using the given filename. | ||
| 41 | void Finish(const std::string& filename); | ||
| 42 | |||
| 43 | /// Mark end of a frame | ||
| 44 | void FrameFinished(); | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Store a copy of the given memory range in the recording. | ||
| 48 | * @note Use this whenever the GPU is about to access a particular memory region. | ||
| 49 | * @note The implementation will make sure to minimize redundant memory updates. | ||
| 50 | */ | ||
| 51 | void MemoryAccessed(const u8* data, u32 size, u32 physical_address); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Record a register write. | ||
| 55 | * @note Use this whenever a GPU-related MMIO register has been written to. | ||
| 56 | */ | ||
| 57 | template<typename T> | ||
| 58 | void RegisterWritten(u32 physical_address, T value); | ||
| 59 | |||
| 60 | private: | ||
| 61 | // Initial state of recording start | ||
| 62 | InitialState initial_state; | ||
| 63 | |||
| 64 | // Command stream | ||
| 65 | struct StreamElement { | ||
| 66 | CTStreamElement data; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Extra data to store along "core" data. | ||
| 70 | * This is e.g. used for data used in MemoryUpdates. | ||
| 71 | */ | ||
| 72 | std::vector<u8> extra_data; | ||
| 73 | |||
| 74 | /// Optional CRC hash (e.g. for hashing memory regions) | ||
| 75 | boost::crc_32_type::value_type hash; | ||
| 76 | |||
| 77 | /// If true, refer to data already written to the output file instead of extra_data | ||
| 78 | bool uses_existing_data; | ||
| 79 | }; | ||
| 80 | |||
| 81 | std::vector<StreamElement> stream; | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Internal cache which maps hashes of memory contents to file offsets at which those memory | ||
| 85 | * contents are stored. | ||
| 86 | */ | ||
| 87 | std::unordered_map<boost::crc_32_type::value_type /*hash*/, u32 /*file_offset*/> memory_regions; | ||
| 88 | }; | ||
| 89 | |||
| 90 | } // namespace | ||
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 5c7f4ae18..162108301 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -2,7 +2,6 @@ set(SRCS | |||
| 2 | renderer_opengl/generated/gl_3_2_core.c | 2 | renderer_opengl/generated/gl_3_2_core.c |
| 3 | renderer_opengl/gl_rasterizer.cpp | 3 | renderer_opengl/gl_rasterizer.cpp |
| 4 | renderer_opengl/gl_rasterizer_cache.cpp | 4 | renderer_opengl/gl_rasterizer_cache.cpp |
| 5 | renderer_opengl/gl_resource_manager.cpp | ||
| 6 | renderer_opengl/gl_shader_util.cpp | 5 | renderer_opengl/gl_shader_util.cpp |
| 7 | renderer_opengl/gl_state.cpp | 6 | renderer_opengl/gl_state.cpp |
| 8 | renderer_opengl/renderer_opengl.cpp | 7 | renderer_opengl/renderer_opengl.cpp |
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp index 943f3eb35..558b49d60 100644 --- a/src/video_core/clipper.cpp +++ b/src/video_core/clipper.cpp | |||
| @@ -94,7 +94,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { | |||
| 94 | // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value. | 94 | // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value. |
| 95 | // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest | 95 | // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest |
| 96 | // epsilon possible within float24 accuracy. | 96 | // epsilon possible within float24 accuracy. |
| 97 | static const float24 EPSILON = float24::FromFloat32(0.00001); | 97 | static const float24 EPSILON = float24::FromFloat32(0.00001f); |
| 98 | static const float24 f0 = float24::FromFloat32(0.0); | 98 | static const float24 f0 = float24::FromFloat32(0.0); |
| 99 | static const float24 f1 = float24::FromFloat32(1.0); | 99 | static const float24 f1 = float24::FromFloat32(1.0); |
| 100 | static const std::array<ClippingEdge, 7> clipping_edges = {{ | 100 | static const std::array<ClippingEdge, 7> clipping_edges = {{ |
| @@ -153,7 +153,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { | |||
| 153 | "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), " | 153 | "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), " |
| 154 | "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " | 154 | "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " |
| 155 | "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", | 155 | "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", |
| 156 | i, output_list->size(), | 156 | i + 1, output_list->size() - 2, |
| 157 | vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(), | 157 | vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(), |
| 158 | vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(), | 158 | vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(), |
| 159 | vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(), | 159 | vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(), |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index b46fadd9f..ef9584abd 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -6,18 +6,20 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/profiler.h" | 7 | #include "common/profiler.h" |
| 8 | 8 | ||
| 9 | #include "core/hle/service/gsp_gpu.h" | ||
| 10 | #include "core/hw/gpu.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | #include "debug_utils/debug_utils.h" | ||
| 14 | |||
| 9 | #include "clipper.h" | 15 | #include "clipper.h" |
| 10 | #include "command_processor.h" | 16 | #include "command_processor.h" |
| 11 | #include "math.h" | 17 | #include "math.h" |
| 12 | #include "pica.h" | 18 | #include "pica.h" |
| 13 | #include "primitive_assembly.h" | 19 | #include "primitive_assembly.h" |
| 20 | #include "renderer_base.h" | ||
| 14 | #include "vertex_shader.h" | 21 | #include "vertex_shader.h" |
| 15 | #include "video_core.h" | 22 | #include "video_core.h" |
| 16 | #include "core/hle/service/gsp_gpu.h" | ||
| 17 | #include "core/hw/gpu.h" | ||
| 18 | #include "core/settings.h" | ||
| 19 | |||
| 20 | #include "debug_utils/debug_utils.h" | ||
| 21 | 23 | ||
| 22 | namespace Pica { | 24 | namespace Pica { |
| 23 | 25 | ||
| @@ -43,12 +45,12 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 43 | if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq)) | 45 | if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq)) |
| 44 | return; | 46 | return; |
| 45 | 47 | ||
| 46 | // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value | 48 | // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value |
| 47 | u32 old_value = regs[id]; | 49 | u32 old_value = regs[id]; |
| 48 | regs[id] = (old_value & ~mask) | (value & mask); | 50 | regs[id] = (old_value & ~mask) | (value & mask); |
| 49 | 51 | ||
| 50 | if (g_debug_context) | 52 | if (g_debug_context) |
| 51 | g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id)); | 53 | g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id)); |
| 52 | 54 | ||
| 53 | DebugUtils::OnPicaRegWrite(id, regs[id]); | 55 | DebugUtils::OnPicaRegWrite(id, regs[id]); |
| 54 | 56 | ||
| @@ -58,10 +60,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 58 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); | 60 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); |
| 59 | break; | 61 | break; |
| 60 | 62 | ||
| 63 | // Load default vertex input attributes | ||
| 64 | case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): | ||
| 65 | case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): | ||
| 66 | case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): | ||
| 67 | { | ||
| 68 | // TODO: Does actual hardware indeed keep an intermediate buffer or does | ||
| 69 | // it directly write the values? | ||
| 70 | default_attr_write_buffer[default_attr_counter++] = value; | ||
| 71 | |||
| 72 | // Default attributes are written in a packed format such that four float24 values are encoded in | ||
| 73 | // three 32-bit numbers. We write to internal memory once a full such vector is | ||
| 74 | // written. | ||
| 75 | if (default_attr_counter >= 3) { | ||
| 76 | default_attr_counter = 0; | ||
| 77 | |||
| 78 | auto& setup = regs.vs_default_attributes_setup; | ||
| 79 | |||
| 80 | if (setup.index >= 16) { | ||
| 81 | LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); | ||
| 82 | break; | ||
| 83 | } | ||
| 84 | |||
| 85 | Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; | ||
| 86 | |||
| 87 | // NOTE: The destination component order indeed is "backwards" | ||
| 88 | attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); | ||
| 89 | attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); | ||
| 90 | attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF)); | ||
| 91 | attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF); | ||
| 92 | |||
| 93 | LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index, | ||
| 94 | attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(), | ||
| 95 | attribute.w.ToFloat32()); | ||
| 96 | |||
| 97 | // TODO: Verify that this actually modifies the register! | ||
| 98 | setup.index = setup.index + 1; | ||
| 99 | } | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | |||
| 61 | case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): | 103 | case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): |
| 62 | case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): | 104 | case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): |
| 63 | { | 105 | { |
| 64 | unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); | 106 | unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0])); |
| 65 | u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); | 107 | u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); |
| 66 | g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; | 108 | g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; |
| 67 | g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); | 109 | g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); |
| @@ -74,7 +116,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 74 | { | 116 | { |
| 75 | Common::Profiling::ScopeTimer scope_timer(category_drawing); | 117 | Common::Profiling::ScopeTimer scope_timer(category_drawing); |
| 76 | 118 | ||
| 119 | #if PICA_LOG_TEV | ||
| 77 | DebugUtils::DumpTevStageConfig(regs.GetTevStages()); | 120 | DebugUtils::DumpTevStageConfig(regs.GetTevStages()); |
| 121 | #endif | ||
| 78 | 122 | ||
| 79 | if (g_debug_context) | 123 | if (g_debug_context) |
| 80 | g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); | 124 | g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); |
| @@ -117,9 +161,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 117 | const u16* index_address_16 = (u16*)index_address_8; | 161 | const u16* index_address_16 = (u16*)index_address_8; |
| 118 | bool index_u16 = index_info.format != 0; | 162 | bool index_u16 = index_info.format != 0; |
| 119 | 163 | ||
| 164 | #if PICA_DUMP_GEOMETRY | ||
| 120 | DebugUtils::GeometryDumper geometry_dumper; | 165 | DebugUtils::GeometryDumper geometry_dumper; |
| 121 | PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); | ||
| 122 | PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); | 166 | PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); |
| 167 | #endif | ||
| 168 | PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); | ||
| 169 | |||
| 170 | if (g_debug_context) { | ||
| 171 | for (int i = 0; i < 3; ++i) { | ||
| 172 | const auto texture = regs.GetTextures()[i]; | ||
| 173 | if (!texture.enabled) | ||
| 174 | continue; | ||
| 175 | |||
| 176 | u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); | ||
| 177 | if (g_debug_context && Pica::g_debug_context->recorder) | ||
| 178 | g_debug_context->recorder->MemoryAccessed(texture_data, Pica::Regs::NibblesPerPixel(texture.format) * texture.config.width / 2 * texture.config.height, texture.config.GetPhysicalAddress()); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | class { | ||
| 183 | /// Combine overlapping and close ranges | ||
| 184 | void SimplifyRanges() { | ||
| 185 | for (auto it = ranges.begin(); it != ranges.end(); ++it) { | ||
| 186 | // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too | ||
| 187 | auto it2 = std::next(it); | ||
| 188 | while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) { | ||
| 189 | it->second = std::max(it->second, it2->first + it2->second - it->first); | ||
| 190 | it2 = ranges.erase(it2); | ||
| 191 | } | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | public: | ||
| 196 | /// Record a particular memory access in the list | ||
| 197 | void AddAccess(u32 paddr, u32 size) { | ||
| 198 | // Create new range or extend existing one | ||
| 199 | ranges[paddr] = std::max(ranges[paddr], size); | ||
| 200 | |||
| 201 | // Simplify ranges... | ||
| 202 | SimplifyRanges(); | ||
| 203 | } | ||
| 204 | |||
| 205 | /// Map of accessed ranges (mapping start address to range size) | ||
| 206 | std::map<u32, u32> ranges; | ||
| 207 | } memory_accesses; | ||
| 123 | 208 | ||
| 124 | for (unsigned int index = 0; index < regs.num_vertices; ++index) | 209 | for (unsigned int index = 0; index < regs.num_vertices; ++index) |
| 125 | { | 210 | { |
| @@ -127,6 +212,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 127 | 212 | ||
| 128 | if (is_indexed) { | 213 | if (is_indexed) { |
| 129 | // TODO: Implement some sort of vertex cache! | 214 | // TODO: Implement some sort of vertex cache! |
| 215 | if (g_debug_context && Pica::g_debug_context->recorder) { | ||
| 216 | int size = index_u16 ? 2 : 1; | ||
| 217 | memory_accesses.AddAccess(base_address + index_info.offset + size * index, size); | ||
| 218 | } | ||
| 130 | } | 219 | } |
| 131 | 220 | ||
| 132 | // Initialize data for the current vertex | 221 | // Initialize data for the current vertex |
| @@ -149,7 +238,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 149 | 238 | ||
| 150 | // Load per-vertex data from the loader arrays | 239 | // Load per-vertex data from the loader arrays |
| 151 | for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { | 240 | for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { |
| 152 | const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); | 241 | u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; |
| 242 | const u8* srcdata = Memory::GetPhysicalPointer(source_addr); | ||
| 243 | |||
| 244 | if (g_debug_context && Pica::g_debug_context->recorder) { | ||
| 245 | memory_accesses.AddAccess(source_addr, | ||
| 246 | (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4 | ||
| 247 | : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1); | ||
| 248 | } | ||
| 153 | 249 | ||
| 154 | const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : | 250 | const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : |
| 155 | (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : | 251 | (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : |
| @@ -179,6 +275,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 179 | if (g_debug_context) | 275 | if (g_debug_context) |
| 180 | g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input); | 276 | g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input); |
| 181 | 277 | ||
| 278 | #if PICA_DUMP_GEOMETRY | ||
| 182 | // NOTE: When dumping geometry, we simply assume that the first input attribute | 279 | // NOTE: When dumping geometry, we simply assume that the first input attribute |
| 183 | // corresponds to the position for now. | 280 | // corresponds to the position for now. |
| 184 | DebugUtils::GeometryDumper::Vertex dumped_vertex = { | 281 | DebugUtils::GeometryDumper::Vertex dumped_vertex = { |
| @@ -188,9 +285,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 188 | dumping_primitive_assembler.SubmitVertex(dumped_vertex, | 285 | dumping_primitive_assembler.SubmitVertex(dumped_vertex, |
| 189 | std::bind(&DebugUtils::GeometryDumper::AddTriangle, | 286 | std::bind(&DebugUtils::GeometryDumper::AddTriangle, |
| 190 | &geometry_dumper, _1, _2, _3)); | 287 | &geometry_dumper, _1, _2, _3)); |
| 288 | #endif | ||
| 191 | 289 | ||
| 192 | // Send to vertex shader | 290 | // Send to vertex shader |
| 193 | VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes()); | 291 | VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes(), g_state.regs.vs, g_state.vs); |
| 194 | 292 | ||
| 195 | if (is_indexed) { | 293 | if (is_indexed) { |
| 196 | // TODO: Add processed vertex to vertex cache! | 294 | // TODO: Add processed vertex to vertex cache! |
| @@ -211,47 +309,55 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 211 | } | 309 | } |
| 212 | } | 310 | } |
| 213 | 311 | ||
| 312 | for (auto& range : memory_accesses.ranges) { | ||
| 313 | g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first), | ||
| 314 | range.second, range.first); | ||
| 315 | } | ||
| 316 | |||
| 214 | if (Settings::values.use_hw_renderer) { | 317 | if (Settings::values.use_hw_renderer) { |
| 215 | VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); | 318 | VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); |
| 216 | } | 319 | } |
| 217 | 320 | ||
| 321 | #if PICA_DUMP_GEOMETRY | ||
| 218 | geometry_dumper.Dump(); | 322 | geometry_dumper.Dump(); |
| 323 | #endif | ||
| 219 | 324 | ||
| 220 | if (g_debug_context) | 325 | if (g_debug_context) { |
| 221 | g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); | 326 | g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); |
| 327 | } | ||
| 222 | 328 | ||
| 223 | break; | 329 | break; |
| 224 | } | 330 | } |
| 225 | 331 | ||
| 226 | case PICA_REG_INDEX(vs_bool_uniforms): | 332 | case PICA_REG_INDEX(vs.bool_uniforms): |
| 227 | for (unsigned i = 0; i < 16; ++i) | 333 | for (unsigned i = 0; i < 16; ++i) |
| 228 | g_state.vs.uniforms.b[i] = (regs.vs_bool_uniforms.Value() & (1 << i)) != 0; | 334 | g_state.vs.uniforms.b[i] = (regs.vs.bool_uniforms.Value() & (1 << i)) != 0; |
| 229 | 335 | ||
| 230 | break; | 336 | break; |
| 231 | 337 | ||
| 232 | case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1): | 338 | case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1): |
| 233 | case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[1], 0x2b2): | 339 | case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[1], 0x2b2): |
| 234 | case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[2], 0x2b3): | 340 | case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[2], 0x2b3): |
| 235 | case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[3], 0x2b4): | 341 | case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[3], 0x2b4): |
| 236 | { | 342 | { |
| 237 | int index = (id - PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1)); | 343 | int index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1)); |
| 238 | auto values = regs.vs_int_uniforms[index]; | 344 | auto values = regs.vs.int_uniforms[index]; |
| 239 | g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w); | 345 | g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w); |
| 240 | LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x", | 346 | LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x", |
| 241 | index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value()); | 347 | index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value()); |
| 242 | break; | 348 | break; |
| 243 | } | 349 | } |
| 244 | 350 | ||
| 245 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[0], 0x2c1): | 351 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[0], 0x2c1): |
| 246 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[1], 0x2c2): | 352 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[1], 0x2c2): |
| 247 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[2], 0x2c3): | 353 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[2], 0x2c3): |
| 248 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[3], 0x2c4): | 354 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[3], 0x2c4): |
| 249 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[4], 0x2c5): | 355 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[4], 0x2c5): |
| 250 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[5], 0x2c6): | 356 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[5], 0x2c6): |
| 251 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[6], 0x2c7): | 357 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[6], 0x2c7): |
| 252 | case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[7], 0x2c8): | 358 | case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[7], 0x2c8): |
| 253 | { | 359 | { |
| 254 | auto& uniform_setup = regs.vs_uniform_setup; | 360 | auto& uniform_setup = regs.vs.uniform_setup; |
| 255 | 361 | ||
| 256 | // TODO: Does actual hardware indeed keep an intermediate buffer or does | 362 | // TODO: Does actual hardware indeed keep an intermediate buffer or does |
| 257 | // it directly write the values? | 363 | // it directly write the values? |
| @@ -293,73 +399,33 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 293 | break; | 399 | break; |
| 294 | } | 400 | } |
| 295 | 401 | ||
| 296 | // Load default vertex input attributes | ||
| 297 | case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): | ||
| 298 | case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): | ||
| 299 | case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): | ||
| 300 | { | ||
| 301 | // TODO: Does actual hardware indeed keep an intermediate buffer or does | ||
| 302 | // it directly write the values? | ||
| 303 | default_attr_write_buffer[default_attr_counter++] = value; | ||
| 304 | |||
| 305 | // Default attributes are written in a packed format such that four float24 values are encoded in | ||
| 306 | // three 32-bit numbers. We write to internal memory once a full such vector is | ||
| 307 | // written. | ||
| 308 | if (default_attr_counter >= 3) { | ||
| 309 | default_attr_counter = 0; | ||
| 310 | |||
| 311 | auto& setup = regs.vs_default_attributes_setup; | ||
| 312 | |||
| 313 | if (setup.index >= 16) { | ||
| 314 | LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); | ||
| 315 | break; | ||
| 316 | } | ||
| 317 | |||
| 318 | Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; | ||
| 319 | |||
| 320 | // NOTE: The destination component order indeed is "backwards" | ||
| 321 | attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); | ||
| 322 | attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); | ||
| 323 | attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF)); | ||
| 324 | attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF); | ||
| 325 | |||
| 326 | LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index, | ||
| 327 | attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(), | ||
| 328 | attribute.w.ToFloat32()); | ||
| 329 | |||
| 330 | // TODO: Verify that this actually modifies the register! | ||
| 331 | setup.index = setup.index + 1; | ||
| 332 | } | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | |||
| 336 | // Load shader program code | 402 | // Load shader program code |
| 337 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc): | 403 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[0], 0x2cc): |
| 338 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[1], 0x2cd): | 404 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[1], 0x2cd): |
| 339 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[2], 0x2ce): | 405 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[2], 0x2ce): |
| 340 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[3], 0x2cf): | 406 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[3], 0x2cf): |
| 341 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[4], 0x2d0): | 407 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[4], 0x2d0): |
| 342 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[5], 0x2d1): | 408 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[5], 0x2d1): |
| 343 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[6], 0x2d2): | 409 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[6], 0x2d2): |
| 344 | case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[7], 0x2d3): | 410 | case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[7], 0x2d3): |
| 345 | { | 411 | { |
| 346 | g_state.vs.program_code[regs.vs_program.offset] = value; | 412 | g_state.vs.program_code[regs.vs.program.offset] = value; |
| 347 | regs.vs_program.offset++; | 413 | regs.vs.program.offset++; |
| 348 | break; | 414 | break; |
| 349 | } | 415 | } |
| 350 | 416 | ||
| 351 | // Load swizzle pattern data | 417 | // Load swizzle pattern data |
| 352 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[0], 0x2d6): | 418 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[0], 0x2d6): |
| 353 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[1], 0x2d7): | 419 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[1], 0x2d7): |
| 354 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[2], 0x2d8): | 420 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[2], 0x2d8): |
| 355 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[3], 0x2d9): | 421 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[3], 0x2d9): |
| 356 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[4], 0x2da): | 422 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[4], 0x2da): |
| 357 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[5], 0x2db): | 423 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[5], 0x2db): |
| 358 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[6], 0x2dc): | 424 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[6], 0x2dc): |
| 359 | case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[7], 0x2dd): | 425 | case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[7], 0x2dd): |
| 360 | { | 426 | { |
| 361 | g_state.vs.swizzle_data[regs.vs_swizzle_patterns.offset] = value; | 427 | g_state.vs.swizzle_data[regs.vs.swizzle_patterns.offset] = value; |
| 362 | regs.vs_swizzle_patterns.offset++; | 428 | regs.vs.swizzle_patterns.offset++; |
| 363 | break; | 429 | break; |
| 364 | } | 430 | } |
| 365 | 431 | ||
| @@ -370,7 +436,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 370 | VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); | 436 | VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); |
| 371 | 437 | ||
| 372 | if (g_debug_context) | 438 | if (g_debug_context) |
| 373 | g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); | 439 | g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id)); |
| 374 | } | 440 | } |
| 375 | 441 | ||
| 376 | void ProcessCommandList(const u32* list, u32 size) { | 442 | void ProcessCommandList(const u32* list, u32 size) { |
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h index bb3d4150f..022a71f5e 100644 --- a/src/video_core/command_processor.h +++ b/src/video_core/command_processor.h | |||
| @@ -4,11 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <type_traits> | ||
| 8 | |||
| 7 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 8 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 9 | 11 | ||
| 10 | #include "pica.h" | ||
| 11 | |||
| 12 | namespace Pica { | 12 | namespace Pica { |
| 13 | 13 | ||
| 14 | namespace CommandProcessor { | 14 | namespace CommandProcessor { |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 7b8ab72b6..e9a858411 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "common/vector_math.h" | 23 | #include "common/vector_math.h" |
| 24 | 24 | ||
| 25 | #include "video_core/pica.h" | 25 | #include "video_core/pica.h" |
| 26 | #include "video_core/renderer_base.h" | ||
| 26 | #include "video_core/utils.h" | 27 | #include "video_core/utils.h" |
| 27 | #include "video_core/video_core.h" | 28 | #include "video_core/video_core.h" |
| 28 | 29 | ||
| @@ -84,15 +85,11 @@ void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) { | |||
| 84 | vertices.push_back(v1); | 85 | vertices.push_back(v1); |
| 85 | vertices.push_back(v2); | 86 | vertices.push_back(v2); |
| 86 | 87 | ||
| 87 | int num_vertices = vertices.size(); | 88 | int num_vertices = (int)vertices.size(); |
| 88 | faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 }); | 89 | faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 }); |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | void GeometryDumper::Dump() { | 92 | void GeometryDumper::Dump() { |
| 92 | // NOTE: Permanently enabling this just trashes the hard disk for no reason. | ||
| 93 | // Hence, this is currently disabled. | ||
| 94 | return; | ||
| 95 | |||
| 96 | static int index = 0; | 93 | static int index = 0; |
| 97 | std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj"; | 94 | std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj"; |
| 98 | 95 | ||
| @@ -115,10 +112,6 @@ void GeometryDumper::Dump() { | |||
| 115 | void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, | 112 | void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, |
| 116 | u32 main_offset, const Regs::VSOutputAttributes* output_attributes) | 113 | u32 main_offset, const Regs::VSOutputAttributes* output_attributes) |
| 117 | { | 114 | { |
| 118 | // NOTE: Permanently enabling this just trashes hard disks for no reason. | ||
| 119 | // Hence, this is currently disabled. | ||
| 120 | return; | ||
| 121 | |||
| 122 | struct StuffToWrite { | 115 | struct StuffToWrite { |
| 123 | u8* pointer; | 116 | u8* pointer; |
| 124 | u32 size; | 117 | u32 size; |
| @@ -240,8 +233,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data | |||
| 240 | 233 | ||
| 241 | dvle.main_offset_words = main_offset; | 234 | dvle.main_offset_words = main_offset; |
| 242 | dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; | 235 | dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; |
| 243 | dvle.output_register_table_size = output_info_table.size(); | 236 | dvle.output_register_table_size = static_cast<uint32_t>(output_info_table.size()); |
| 244 | QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo)); | 237 | QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo))); |
| 245 | 238 | ||
| 246 | // TODO: Create a label table for "main" | 239 | // TODO: Create a label table for "main" |
| 247 | 240 | ||
| @@ -496,31 +489,31 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture | |||
| 496 | // Lookup base value | 489 | // Lookup base value |
| 497 | Math::Vec3<int> ret; | 490 | Math::Vec3<int> ret; |
| 498 | if (differential_mode) { | 491 | if (differential_mode) { |
| 499 | ret.r() = differential.r; | 492 | ret.r() = static_cast<int>(differential.r); |
| 500 | ret.g() = differential.g; | 493 | ret.g() = static_cast<int>(differential.g); |
| 501 | ret.b() = differential.b; | 494 | ret.b() = static_cast<int>(differential.b); |
| 502 | if (x >= 2) { | 495 | if (x >= 2) { |
| 503 | ret.r() += differential.dr; | 496 | ret.r() += static_cast<int>(differential.dr); |
| 504 | ret.g() += differential.dg; | 497 | ret.g() += static_cast<int>(differential.dg); |
| 505 | ret.b() += differential.db; | 498 | ret.b() += static_cast<int>(differential.db); |
| 506 | } | 499 | } |
| 507 | ret.r() = Color::Convert5To8(ret.r()); | 500 | ret.r() = Color::Convert5To8(ret.r()); |
| 508 | ret.g() = Color::Convert5To8(ret.g()); | 501 | ret.g() = Color::Convert5To8(ret.g()); |
| 509 | ret.b() = Color::Convert5To8(ret.b()); | 502 | ret.b() = Color::Convert5To8(ret.b()); |
| 510 | } else { | 503 | } else { |
| 511 | if (x < 2) { | 504 | if (x < 2) { |
| 512 | ret.r() = Color::Convert4To8(separate.r1); | 505 | ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1)); |
| 513 | ret.g() = Color::Convert4To8(separate.g1); | 506 | ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1)); |
| 514 | ret.b() = Color::Convert4To8(separate.b1); | 507 | ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1)); |
| 515 | } else { | 508 | } else { |
| 516 | ret.r() = Color::Convert4To8(separate.r2); | 509 | ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2)); |
| 517 | ret.g() = Color::Convert4To8(separate.g2); | 510 | ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2)); |
| 518 | ret.b() = Color::Convert4To8(separate.b2); | 511 | ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2)); |
| 519 | } | 512 | } |
| 520 | } | 513 | } |
| 521 | 514 | ||
| 522 | // Add modifier | 515 | // Add modifier |
| 523 | unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value(); | 516 | unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value()); |
| 524 | 517 | ||
| 525 | static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ | 518 | static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ |
| 526 | { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, | 519 | { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, |
| @@ -564,10 +557,6 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config, | |||
| 564 | } | 557 | } |
| 565 | 558 | ||
| 566 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | 559 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { |
| 567 | // NOTE: Permanently enabling this just trashes hard disks for no reason. | ||
| 568 | // Hence, this is currently disabled. | ||
| 569 | return; | ||
| 570 | |||
| 571 | #ifndef HAVE_PNG | 560 | #ifndef HAVE_PNG |
| 572 | return; | 561 | return; |
| 573 | #else | 562 | #else |
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index 7926d64ec..81eea30a9 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | 14 | ||
| 15 | #include "common/vector_math.h" | 15 | #include "common/vector_math.h" |
| 16 | 16 | ||
| 17 | #include "core/tracer/recorder.h" | ||
| 18 | |||
| 17 | #include "video_core/pica.h" | 19 | #include "video_core/pica.h" |
| 18 | 20 | ||
| 19 | namespace Pica { | 21 | namespace Pica { |
| @@ -23,11 +25,14 @@ public: | |||
| 23 | enum class Event { | 25 | enum class Event { |
| 24 | FirstEvent = 0, | 26 | FirstEvent = 0, |
| 25 | 27 | ||
| 26 | CommandLoaded = FirstEvent, | 28 | PicaCommandLoaded = FirstEvent, |
| 27 | CommandProcessed, | 29 | PicaCommandProcessed, |
| 28 | IncomingPrimitiveBatch, | 30 | IncomingPrimitiveBatch, |
| 29 | FinishedPrimitiveBatch, | 31 | FinishedPrimitiveBatch, |
| 30 | VertexLoaded, | 32 | VertexLoaded, |
| 33 | IncomingDisplayTransfer, | ||
| 34 | GSPCommandProcessed, | ||
| 35 | BufferSwapped, | ||
| 31 | 36 | ||
| 32 | NumEvents | 37 | NumEvents |
| 33 | }; | 38 | }; |
| @@ -129,6 +134,8 @@ public: | |||
| 129 | Event active_breakpoint; | 134 | Event active_breakpoint; |
| 130 | bool at_breakpoint = false; | 135 | bool at_breakpoint = false; |
| 131 | 136 | ||
| 137 | std::shared_ptr<CiTrace::Recorder> recorder = nullptr; | ||
| 138 | |||
| 132 | private: | 139 | private: |
| 133 | /** | 140 | /** |
| 134 | * Private default constructor to make sure people always construct this through Construct() | 141 | * Private default constructor to make sure people always construct this through Construct() |
| @@ -150,6 +157,11 @@ extern std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this g | |||
| 150 | 157 | ||
| 151 | namespace DebugUtils { | 158 | namespace DebugUtils { |
| 152 | 159 | ||
| 160 | #define PICA_DUMP_GEOMETRY 0 | ||
| 161 | #define PICA_DUMP_SHADERS 0 | ||
| 162 | #define PICA_DUMP_TEXTURES 0 | ||
| 163 | #define PICA_LOG_TEV 0 | ||
| 164 | |||
| 153 | // Simple utility class for dumping geometry data to an OBJ file | 165 | // Simple utility class for dumping geometry data to an OBJ file |
| 154 | class GeometryDumper { | 166 | class GeometryDumper { |
| 155 | public: | 167 | public: |
diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h index dec193f8b..c8746c608 100644 --- a/src/video_core/hwrasterizer_base.h +++ b/src/video_core/hwrasterizer_base.h | |||
| @@ -4,8 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/emu_window.h" | 7 | #include "common/common_types.h" |
| 8 | #include "video_core/vertex_shader.h" | 8 | |
| 9 | namespace Pica { | ||
| 10 | namespace VertexShader { | ||
| 11 | struct OutputVertex; | ||
| 12 | } | ||
| 13 | } | ||
| 9 | 14 | ||
| 10 | class HWRasterizer { | 15 | class HWRasterizer { |
| 11 | public: | 16 | public: |
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp index 543d9c443..17cb66780 100644 --- a/src/video_core/pica.cpp +++ b/src/video_core/pica.cpp | |||
| @@ -2,7 +2,8 @@ | |||
| 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 <string.h> | 5 | #include <cstring> |
| 6 | #include <unordered_map> | ||
| 6 | 7 | ||
| 7 | #include "pica.h" | 8 | #include "pica.h" |
| 8 | 9 | ||
| @@ -10,6 +11,75 @@ namespace Pica { | |||
| 10 | 11 | ||
| 11 | State g_state; | 12 | State g_state; |
| 12 | 13 | ||
| 14 | std::string Regs::GetCommandName(int index) { | ||
| 15 | static std::unordered_map<u32, std::string> map; | ||
| 16 | |||
| 17 | if (map.empty()) { | ||
| 18 | #define ADD_FIELD(name) \ | ||
| 19 | map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \ | ||
| 20 | /* TODO: change to Regs::name when VS2015 and other compilers support it */ \ | ||
| 21 | for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \ | ||
| 22 | map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \ | ||
| 23 | |||
| 24 | ADD_FIELD(trigger_irq); | ||
| 25 | ADD_FIELD(cull_mode); | ||
| 26 | ADD_FIELD(viewport_size_x); | ||
| 27 | ADD_FIELD(viewport_size_y); | ||
| 28 | ADD_FIELD(viewport_depth_range); | ||
| 29 | ADD_FIELD(viewport_depth_far_plane); | ||
| 30 | ADD_FIELD(viewport_corner); | ||
| 31 | ADD_FIELD(texture0_enable); | ||
| 32 | ADD_FIELD(texture0); | ||
| 33 | ADD_FIELD(texture0_format); | ||
| 34 | ADD_FIELD(texture1); | ||
| 35 | ADD_FIELD(texture1_format); | ||
| 36 | ADD_FIELD(texture2); | ||
| 37 | ADD_FIELD(texture2_format); | ||
| 38 | ADD_FIELD(tev_stage0); | ||
| 39 | ADD_FIELD(tev_stage1); | ||
| 40 | ADD_FIELD(tev_stage2); | ||
| 41 | ADD_FIELD(tev_stage3); | ||
| 42 | ADD_FIELD(tev_combiner_buffer_input); | ||
| 43 | ADD_FIELD(tev_stage4); | ||
| 44 | ADD_FIELD(tev_stage5); | ||
| 45 | ADD_FIELD(tev_combiner_buffer_color); | ||
| 46 | ADD_FIELD(output_merger); | ||
| 47 | ADD_FIELD(framebuffer); | ||
| 48 | ADD_FIELD(vertex_attributes); | ||
| 49 | ADD_FIELD(index_array); | ||
| 50 | ADD_FIELD(num_vertices); | ||
| 51 | ADD_FIELD(trigger_draw); | ||
| 52 | ADD_FIELD(trigger_draw_indexed); | ||
| 53 | ADD_FIELD(vs_default_attributes_setup); | ||
| 54 | ADD_FIELD(command_buffer); | ||
| 55 | ADD_FIELD(triangle_topology); | ||
| 56 | ADD_FIELD(gs.bool_uniforms); | ||
| 57 | ADD_FIELD(gs.int_uniforms); | ||
| 58 | ADD_FIELD(gs.main_offset); | ||
| 59 | ADD_FIELD(gs.input_register_map); | ||
| 60 | ADD_FIELD(gs.uniform_setup); | ||
| 61 | ADD_FIELD(gs.program); | ||
| 62 | ADD_FIELD(gs.swizzle_patterns); | ||
| 63 | ADD_FIELD(vs.bool_uniforms); | ||
| 64 | ADD_FIELD(vs.int_uniforms); | ||
| 65 | ADD_FIELD(vs.main_offset); | ||
| 66 | ADD_FIELD(vs.input_register_map); | ||
| 67 | ADD_FIELD(vs.uniform_setup); | ||
| 68 | ADD_FIELD(vs.program); | ||
| 69 | ADD_FIELD(vs.swizzle_patterns); | ||
| 70 | |||
| 71 | #undef ADD_FIELD | ||
| 72 | } | ||
| 73 | |||
| 74 | // Return empty string if no match is found | ||
| 75 | auto it = map.find(index); | ||
| 76 | if (it != map.end()) { | ||
| 77 | return it->second; | ||
| 78 | } else { | ||
| 79 | return std::string(); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 13 | void Init() { | 83 | void Init() { |
| 14 | } | 84 | } |
| 15 | 85 | ||
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 9628a7589..34b02b2f8 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -5,10 +5,9 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cmath> | ||
| 8 | #include <cstddef> | 9 | #include <cstddef> |
| 9 | #include <initializer_list> | 10 | #include <string> |
| 10 | #include <map> | ||
| 11 | #include <vector> | ||
| 12 | 11 | ||
| 13 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 14 | #include "common/bit_field.h" | 13 | #include "common/bit_field.h" |
| @@ -114,11 +113,22 @@ struct Regs { | |||
| 114 | struct TextureConfig { | 113 | struct TextureConfig { |
| 115 | enum WrapMode : u32 { | 114 | enum WrapMode : u32 { |
| 116 | ClampToEdge = 0, | 115 | ClampToEdge = 0, |
| 116 | ClampToBorder = 1, | ||
| 117 | Repeat = 2, | 117 | Repeat = 2, |
| 118 | MirroredRepeat = 3, | 118 | MirroredRepeat = 3, |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | INSERT_PADDING_WORDS(0x1); | 121 | enum TextureFilter : u32 { |
| 122 | Nearest = 0, | ||
| 123 | Linear = 1 | ||
| 124 | }; | ||
| 125 | |||
| 126 | union { | ||
| 127 | BitField< 0, 8, u32> r; | ||
| 128 | BitField< 8, 8, u32> g; | ||
| 129 | BitField<16, 8, u32> b; | ||
| 130 | BitField<24, 8, u32> a; | ||
| 131 | } border_color; | ||
| 122 | 132 | ||
| 123 | union { | 133 | union { |
| 124 | BitField< 0, 16, u32> height; | 134 | BitField< 0, 16, u32> height; |
| @@ -126,8 +136,10 @@ struct Regs { | |||
| 126 | }; | 136 | }; |
| 127 | 137 | ||
| 128 | union { | 138 | union { |
| 129 | BitField< 8, 2, WrapMode> wrap_s; | 139 | BitField< 1, 1, TextureFilter> mag_filter; |
| 130 | BitField<12, 2, WrapMode> wrap_t; | 140 | BitField< 2, 1, TextureFilter> min_filter; |
| 141 | BitField< 8, 2, WrapMode> wrap_t; | ||
| 142 | BitField<12, 2, WrapMode> wrap_s; | ||
| 131 | }; | 143 | }; |
| 132 | 144 | ||
| 133 | INSERT_PADDING_WORDS(0x1); | 145 | INSERT_PADDING_WORDS(0x1); |
| @@ -194,6 +206,7 @@ struct Regs { | |||
| 194 | case TextureFormat::IA8: | 206 | case TextureFormat::IA8: |
| 195 | return 4; | 207 | return 4; |
| 196 | 208 | ||
| 209 | case TextureFormat::I4: | ||
| 197 | case TextureFormat::A4: | 210 | case TextureFormat::A4: |
| 198 | return 1; | 211 | return 1; |
| 199 | 212 | ||
| @@ -284,6 +297,7 @@ struct Regs { | |||
| 284 | AddSigned = 3, | 297 | AddSigned = 3, |
| 285 | Lerp = 4, | 298 | Lerp = 4, |
| 286 | Subtract = 5, | 299 | Subtract = 5, |
| 300 | Dot3_RGB = 6, | ||
| 287 | 301 | ||
| 288 | MultiplyThenAdd = 8, | 302 | MultiplyThenAdd = 8, |
| 289 | AddThenMultiply = 9, | 303 | AddThenMultiply = 9, |
| @@ -414,6 +428,11 @@ struct Regs { | |||
| 414 | GreaterThanOrEqual = 7, | 428 | GreaterThanOrEqual = 7, |
| 415 | }; | 429 | }; |
| 416 | 430 | ||
| 431 | enum class StencilAction : u32 { | ||
| 432 | Keep = 0, | ||
| 433 | Xor = 5, | ||
| 434 | }; | ||
| 435 | |||
| 417 | struct { | 436 | struct { |
| 418 | union { | 437 | union { |
| 419 | // If false, logic blending is used | 438 | // If false, logic blending is used |
| @@ -448,15 +467,35 @@ struct Regs { | |||
| 448 | BitField< 8, 8, u32> ref; | 467 | BitField< 8, 8, u32> ref; |
| 449 | } alpha_test; | 468 | } alpha_test; |
| 450 | 469 | ||
| 451 | union { | 470 | struct { |
| 452 | BitField< 0, 1, u32> stencil_test_enable; | 471 | union { |
| 453 | BitField< 4, 3, CompareFunc> stencil_test_func; | 472 | // If true, enable stencil testing |
| 454 | BitField< 8, 8, u32> stencil_replacement_value; | 473 | BitField< 0, 1, u32> enable; |
| 455 | BitField<16, 8, u32> stencil_reference_value; | ||
| 456 | BitField<24, 8, u32> stencil_mask; | ||
| 457 | } stencil_test; | ||
| 458 | 474 | ||
| 459 | INSERT_PADDING_WORDS(0x1); | 475 | // Comparison operation for stencil testing |
| 476 | BitField< 4, 3, CompareFunc> func; | ||
| 477 | |||
| 478 | // Value to calculate the new stencil value from | ||
| 479 | BitField< 8, 8, u32> replacement_value; | ||
| 480 | |||
| 481 | // Value to compare against for stencil testing | ||
| 482 | BitField<16, 8, u32> reference_value; | ||
| 483 | |||
| 484 | // Mask to apply on stencil test inputs | ||
| 485 | BitField<24, 8, u32> mask; | ||
| 486 | }; | ||
| 487 | |||
| 488 | union { | ||
| 489 | // Action to perform when the stencil test fails | ||
| 490 | BitField< 0, 3, StencilAction> action_stencil_fail; | ||
| 491 | |||
| 492 | // Action to perform when stencil testing passed but depth testing fails | ||
| 493 | BitField< 4, 3, StencilAction> action_depth_fail; | ||
| 494 | |||
| 495 | // Action to perform when both stencil and depth testing pass | ||
| 496 | BitField< 8, 3, StencilAction> action_depth_pass; | ||
| 497 | }; | ||
| 498 | } stencil_test; | ||
| 460 | 499 | ||
| 461 | union { | 500 | union { |
| 462 | BitField< 0, 1, u32> depth_test_enable; | 501 | BitField< 0, 1, u32> depth_test_enable; |
| @@ -506,7 +545,7 @@ struct Regs { | |||
| 506 | struct { | 545 | struct { |
| 507 | INSERT_PADDING_WORDS(0x6); | 546 | INSERT_PADDING_WORDS(0x6); |
| 508 | 547 | ||
| 509 | DepthFormat depth_format; | 548 | DepthFormat depth_format; // TODO: Should be a BitField! |
| 510 | BitField<16, 3, ColorFormat> color_format; | 549 | BitField<16, 3, ColorFormat> color_format; |
| 511 | 550 | ||
| 512 | INSERT_PADDING_WORDS(0x4); | 551 | INSERT_PADDING_WORDS(0x4); |
| @@ -752,171 +791,123 @@ struct Regs { | |||
| 752 | INSERT_PADDING_WORDS(0x20); | 791 | INSERT_PADDING_WORDS(0x20); |
| 753 | 792 | ||
| 754 | enum class TriangleTopology : u32 { | 793 | enum class TriangleTopology : u32 { |
| 755 | List = 0, | 794 | List = 0, |
| 756 | Strip = 1, | 795 | Strip = 1, |
| 757 | Fan = 2, | 796 | Fan = 2, |
| 758 | ListIndexed = 3, // TODO: No idea if this is correct | 797 | Shader = 3, // Programmable setup unit implemented in a geometry shader |
| 759 | }; | 798 | }; |
| 760 | 799 | ||
| 761 | BitField<8, 2, TriangleTopology> triangle_topology; | 800 | BitField<8, 2, TriangleTopology> triangle_topology; |
| 762 | 801 | ||
| 763 | INSERT_PADDING_WORDS(0x51); | 802 | INSERT_PADDING_WORDS(0x21); |
| 764 | 803 | ||
| 765 | BitField<0, 16, u32> vs_bool_uniforms; | 804 | struct ShaderConfig { |
| 766 | union { | 805 | BitField<0, 16, u32> bool_uniforms; |
| 767 | BitField< 0, 8, u32> x; | ||
| 768 | BitField< 8, 8, u32> y; | ||
| 769 | BitField<16, 8, u32> z; | ||
| 770 | BitField<24, 8, u32> w; | ||
| 771 | } vs_int_uniforms[4]; | ||
| 772 | 806 | ||
| 773 | INSERT_PADDING_WORDS(0x5); | 807 | union { |
| 808 | BitField< 0, 8, u32> x; | ||
| 809 | BitField< 8, 8, u32> y; | ||
| 810 | BitField<16, 8, u32> z; | ||
| 811 | BitField<24, 8, u32> w; | ||
| 812 | } int_uniforms[4]; | ||
| 774 | 813 | ||
| 775 | // Offset to shader program entry point (in words) | 814 | INSERT_PADDING_WORDS(0x5); |
| 776 | BitField<0, 16, u32> vs_main_offset; | ||
| 777 | 815 | ||
| 778 | union { | 816 | // Offset to shader program entry point (in words) |
| 779 | BitField< 0, 4, u64> attribute0_register; | 817 | BitField<0, 16, u32> main_offset; |
| 780 | BitField< 4, 4, u64> attribute1_register; | 818 | |
| 781 | BitField< 8, 4, u64> attribute2_register; | 819 | union { |
| 782 | BitField<12, 4, u64> attribute3_register; | 820 | BitField< 0, 4, u64> attribute0_register; |
| 783 | BitField<16, 4, u64> attribute4_register; | 821 | BitField< 4, 4, u64> attribute1_register; |
| 784 | BitField<20, 4, u64> attribute5_register; | 822 | BitField< 8, 4, u64> attribute2_register; |
| 785 | BitField<24, 4, u64> attribute6_register; | 823 | BitField<12, 4, u64> attribute3_register; |
| 786 | BitField<28, 4, u64> attribute7_register; | 824 | BitField<16, 4, u64> attribute4_register; |
| 787 | BitField<32, 4, u64> attribute8_register; | 825 | BitField<20, 4, u64> attribute5_register; |
| 788 | BitField<36, 4, u64> attribute9_register; | 826 | BitField<24, 4, u64> attribute6_register; |
| 789 | BitField<40, 4, u64> attribute10_register; | 827 | BitField<28, 4, u64> attribute7_register; |
| 790 | BitField<44, 4, u64> attribute11_register; | 828 | BitField<32, 4, u64> attribute8_register; |
| 791 | BitField<48, 4, u64> attribute12_register; | 829 | BitField<36, 4, u64> attribute9_register; |
| 792 | BitField<52, 4, u64> attribute13_register; | 830 | BitField<40, 4, u64> attribute10_register; |
| 793 | BitField<56, 4, u64> attribute14_register; | 831 | BitField<44, 4, u64> attribute11_register; |
| 794 | BitField<60, 4, u64> attribute15_register; | 832 | BitField<48, 4, u64> attribute12_register; |
| 795 | 833 | BitField<52, 4, u64> attribute13_register; | |
| 796 | int GetRegisterForAttribute(int attribute_index) const { | 834 | BitField<56, 4, u64> attribute14_register; |
| 797 | u64 fields[] = { | 835 | BitField<60, 4, u64> attribute15_register; |
| 798 | attribute0_register, attribute1_register, attribute2_register, attribute3_register, | 836 | |
| 799 | attribute4_register, attribute5_register, attribute6_register, attribute7_register, | 837 | int GetRegisterForAttribute(int attribute_index) const { |
| 800 | attribute8_register, attribute9_register, attribute10_register, attribute11_register, | 838 | u64 fields[] = { |
| 801 | attribute12_register, attribute13_register, attribute14_register, attribute15_register, | 839 | attribute0_register, attribute1_register, attribute2_register, attribute3_register, |
| 840 | attribute4_register, attribute5_register, attribute6_register, attribute7_register, | ||
| 841 | attribute8_register, attribute9_register, attribute10_register, attribute11_register, | ||
| 842 | attribute12_register, attribute13_register, attribute14_register, attribute15_register, | ||
| 843 | }; | ||
| 844 | return (int)fields[attribute_index]; | ||
| 845 | } | ||
| 846 | } input_register_map; | ||
| 847 | |||
| 848 | // OUTMAP_MASK, 0x28E, CODETRANSFER_END | ||
| 849 | INSERT_PADDING_WORDS(0x3); | ||
| 850 | |||
| 851 | struct { | ||
| 852 | enum Format : u32 | ||
| 853 | { | ||
| 854 | FLOAT24 = 0, | ||
| 855 | FLOAT32 = 1 | ||
| 802 | }; | 856 | }; |
| 803 | return (int)fields[attribute_index]; | ||
| 804 | } | ||
| 805 | } vs_input_register_map; | ||
| 806 | 857 | ||
| 807 | INSERT_PADDING_WORDS(0x3); | 858 | bool IsFloat32() const { |
| 859 | return format == FLOAT32; | ||
| 860 | } | ||
| 808 | 861 | ||
| 809 | struct { | 862 | union { |
| 810 | enum Format : u32 | 863 | // Index of the next uniform to write to |
| 811 | { | 864 | // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices |
| 812 | FLOAT24 = 0, | 865 | // TODO: Maybe the uppermost index is for the geometry shader? Investigate! |
| 813 | FLOAT32 = 1 | 866 | BitField<0, 7, u32> index; |
| 814 | }; | ||
| 815 | 867 | ||
| 816 | bool IsFloat32() const { | 868 | BitField<31, 1, Format> format; |
| 817 | return format == FLOAT32; | 869 | }; |
| 818 | } | ||
| 819 | 870 | ||
| 820 | union { | 871 | // Writing to these registers sets the current uniform. |
| 821 | // Index of the next uniform to write to | 872 | u32 set_value[8]; |
| 822 | // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices | ||
| 823 | BitField<0, 7, u32> index; | ||
| 824 | 873 | ||
| 825 | BitField<31, 1, Format> format; | 874 | } uniform_setup; |
| 826 | }; | ||
| 827 | 875 | ||
| 828 | // Writing to these registers sets the "current" uniform. | 876 | INSERT_PADDING_WORDS(0x2); |
| 829 | // TODO: It's not clear how the hardware stores what the "current" uniform is. | ||
| 830 | u32 set_value[8]; | ||
| 831 | 877 | ||
| 832 | } vs_uniform_setup; | 878 | struct { |
| 879 | // Offset of the next instruction to write code to. | ||
| 880 | // Incremented with each instruction write. | ||
| 881 | u32 offset; | ||
| 833 | 882 | ||
| 834 | INSERT_PADDING_WORDS(0x2); | 883 | // Writing to these registers sets the "current" word in the shader program. |
| 884 | u32 set_word[8]; | ||
| 885 | } program; | ||
| 835 | 886 | ||
| 836 | struct { | 887 | INSERT_PADDING_WORDS(0x1); |
| 837 | // Offset of the next instruction to write code to. | ||
| 838 | // Incremented with each instruction write. | ||
| 839 | u32 offset; | ||
| 840 | 888 | ||
| 841 | // Writing to these registers sets the "current" word in the shader program. | 889 | // This register group is used to load an internal table of swizzling patterns, |
| 842 | // TODO: It's not clear how the hardware stores what the "current" word is. | 890 | // which are indexed by each shader instruction to specify vector component swizzling. |
| 843 | u32 set_word[8]; | 891 | struct { |
| 844 | } vs_program; | 892 | // Offset of the next swizzle pattern to write code to. |
| 893 | // Incremented with each instruction write. | ||
| 894 | u32 offset; | ||
| 845 | 895 | ||
| 846 | INSERT_PADDING_WORDS(0x1); | 896 | // Writing to these registers sets the current swizzle pattern in the table. |
| 897 | u32 set_word[8]; | ||
| 898 | } swizzle_patterns; | ||
| 847 | 899 | ||
| 848 | // This register group is used to load an internal table of swizzling patterns, | 900 | INSERT_PADDING_WORDS(0x2); |
| 849 | // which are indexed by each shader instruction to specify vector component swizzling. | 901 | }; |
| 850 | struct { | ||
| 851 | // Offset of the next swizzle pattern to write code to. | ||
| 852 | // Incremented with each instruction write. | ||
| 853 | u32 offset; | ||
| 854 | 902 | ||
| 855 | // Writing to these registers sets the "current" swizzle pattern in the table. | 903 | ShaderConfig gs; |
| 856 | // TODO: It's not clear how the hardware stores what the "current" swizzle pattern is. | 904 | ShaderConfig vs; |
| 857 | u32 set_word[8]; | ||
| 858 | } vs_swizzle_patterns; | ||
| 859 | 905 | ||
| 860 | INSERT_PADDING_WORDS(0x22); | 906 | INSERT_PADDING_WORDS(0x20); |
| 861 | 907 | ||
| 862 | // Map register indices to names readable by humans | 908 | // Map register indices to names readable by humans |
| 863 | // Used for debugging purposes, so performance is not an issue here | 909 | // Used for debugging purposes, so performance is not an issue here |
| 864 | static std::string GetCommandName(int index) { | 910 | static std::string GetCommandName(int index); |
| 865 | std::map<u32, std::string> map; | ||
| 866 | |||
| 867 | #define ADD_FIELD(name) \ | ||
| 868 | do { \ | ||
| 869 | map.insert({PICA_REG_INDEX(name), #name}); \ | ||
| 870 | /* TODO: change to Regs::name when VS2015 and other compilers support it */ \ | ||
| 871 | for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \ | ||
| 872 | map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \ | ||
| 873 | } while(false) | ||
| 874 | |||
| 875 | ADD_FIELD(trigger_irq); | ||
| 876 | ADD_FIELD(cull_mode); | ||
| 877 | ADD_FIELD(viewport_size_x); | ||
| 878 | ADD_FIELD(viewport_size_y); | ||
| 879 | ADD_FIELD(viewport_depth_range); | ||
| 880 | ADD_FIELD(viewport_depth_far_plane); | ||
| 881 | ADD_FIELD(viewport_corner); | ||
| 882 | ADD_FIELD(texture0_enable); | ||
| 883 | ADD_FIELD(texture0); | ||
| 884 | ADD_FIELD(texture0_format); | ||
| 885 | ADD_FIELD(texture1); | ||
| 886 | ADD_FIELD(texture1_format); | ||
| 887 | ADD_FIELD(texture2); | ||
| 888 | ADD_FIELD(texture2_format); | ||
| 889 | ADD_FIELD(tev_stage0); | ||
| 890 | ADD_FIELD(tev_stage1); | ||
| 891 | ADD_FIELD(tev_stage2); | ||
| 892 | ADD_FIELD(tev_stage3); | ||
| 893 | ADD_FIELD(tev_combiner_buffer_input); | ||
| 894 | ADD_FIELD(tev_stage4); | ||
| 895 | ADD_FIELD(tev_stage5); | ||
| 896 | ADD_FIELD(tev_combiner_buffer_color); | ||
| 897 | ADD_FIELD(output_merger); | ||
| 898 | ADD_FIELD(framebuffer); | ||
| 899 | ADD_FIELD(vertex_attributes); | ||
| 900 | ADD_FIELD(index_array); | ||
| 901 | ADD_FIELD(num_vertices); | ||
| 902 | ADD_FIELD(trigger_draw); | ||
| 903 | ADD_FIELD(trigger_draw_indexed); | ||
| 904 | ADD_FIELD(vs_default_attributes_setup); | ||
| 905 | ADD_FIELD(command_buffer); | ||
| 906 | ADD_FIELD(triangle_topology); | ||
| 907 | ADD_FIELD(vs_bool_uniforms); | ||
| 908 | ADD_FIELD(vs_int_uniforms); | ||
| 909 | ADD_FIELD(vs_main_offset); | ||
| 910 | ADD_FIELD(vs_input_register_map); | ||
| 911 | ADD_FIELD(vs_uniform_setup); | ||
| 912 | ADD_FIELD(vs_program); | ||
| 913 | ADD_FIELD(vs_swizzle_patterns); | ||
| 914 | |||
| 915 | #undef ADD_FIELD | ||
| 916 | |||
| 917 | // Return empty string if no match is found | ||
| 918 | return map[index]; | ||
| 919 | } | ||
| 920 | 911 | ||
| 921 | static inline size_t NumIds() { | 912 | static inline size_t NumIds() { |
| 922 | return sizeof(Regs) / sizeof(u32); | 913 | return sizeof(Regs) / sizeof(u32); |
| @@ -982,17 +973,14 @@ ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); | |||
| 982 | ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); | 973 | ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); |
| 983 | ASSERT_REG_POSITION(command_buffer, 0x238); | 974 | ASSERT_REG_POSITION(command_buffer, 0x238); |
| 984 | ASSERT_REG_POSITION(triangle_topology, 0x25e); | 975 | ASSERT_REG_POSITION(triangle_topology, 0x25e); |
| 985 | ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); | 976 | ASSERT_REG_POSITION(gs, 0x280); |
| 986 | ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); | 977 | ASSERT_REG_POSITION(vs, 0x2b0); |
| 987 | ASSERT_REG_POSITION(vs_main_offset, 0x2ba); | ||
| 988 | ASSERT_REG_POSITION(vs_input_register_map, 0x2bb); | ||
| 989 | ASSERT_REG_POSITION(vs_uniform_setup, 0x2c0); | ||
| 990 | ASSERT_REG_POSITION(vs_program, 0x2cb); | ||
| 991 | ASSERT_REG_POSITION(vs_swizzle_patterns, 0x2d5); | ||
| 992 | 978 | ||
| 993 | #undef ASSERT_REG_POSITION | 979 | #undef ASSERT_REG_POSITION |
| 994 | #endif // !defined(_MSC_VER) | 980 | #endif // !defined(_MSC_VER) |
| 995 | 981 | ||
| 982 | static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32), "ShaderConfig structure has incorrect size"); | ||
| 983 | |||
| 996 | // The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway. | 984 | // The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway. |
| 997 | static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); | 985 | static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); |
| 998 | static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); | 986 | static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); |
| @@ -1014,7 +1002,7 @@ struct float24 { | |||
| 1014 | u32 mantissa = hex & 0xFFFF; | 1002 | u32 mantissa = hex & 0xFFFF; |
| 1015 | u32 exponent = (hex >> 16) & 0x7F; | 1003 | u32 exponent = (hex >> 16) & 0x7F; |
| 1016 | u32 sign = hex >> 23; | 1004 | u32 sign = hex >> 23; |
| 1017 | ret.value = powf(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * powf(2.0f, -16.f)); | 1005 | ret.value = std::pow(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * std::pow(2.0f, -16.f)); |
| 1018 | if (sign) | 1006 | if (sign) |
| 1019 | ret.value = -ret.value; | 1007 | ret.value = -ret.value; |
| 1020 | } | 1008 | } |
| @@ -1102,7 +1090,7 @@ struct State { | |||
| 1102 | Regs regs; | 1090 | Regs regs; |
| 1103 | 1091 | ||
| 1104 | /// Vertex shader memory | 1092 | /// Vertex shader memory |
| 1105 | struct { | 1093 | struct ShaderSetup { |
| 1106 | struct { | 1094 | struct { |
| 1107 | Math::Vec4<float24> f[96]; | 1095 | Math::Vec4<float24> f[96]; |
| 1108 | std::array<bool, 16> b; | 1096 | std::array<bool, 16> b; |
| @@ -1113,7 +1101,10 @@ struct State { | |||
| 1113 | 1101 | ||
| 1114 | std::array<u32, 1024> program_code; | 1102 | std::array<u32, 1024> program_code; |
| 1115 | std::array<u32, 1024> swizzle_data; | 1103 | std::array<u32, 1024> swizzle_data; |
| 1116 | } vs; | 1104 | }; |
| 1105 | |||
| 1106 | ShaderSetup vs; | ||
| 1107 | ShaderSetup gs; | ||
| 1117 | 1108 | ||
| 1118 | /// Current Pica command list | 1109 | /// Current Pica command list |
| 1119 | struct { | 1110 | struct { |
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp index 0120f2896..2f22bdcce 100644 --- a/src/video_core/primitive_assembly.cpp +++ b/src/video_core/primitive_assembly.cpp | |||
| @@ -20,8 +20,9 @@ template<typename VertexType> | |||
| 20 | void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler) | 20 | void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler) |
| 21 | { | 21 | { |
| 22 | switch (topology) { | 22 | switch (topology) { |
| 23 | // TODO: Figure out what's different with TriangleTopology::Shader. | ||
| 23 | case Regs::TriangleTopology::List: | 24 | case Regs::TriangleTopology::List: |
| 24 | case Regs::TriangleTopology::ListIndexed: | 25 | case Regs::TriangleTopology::Shader: |
| 25 | if (buffer_index < 2) { | 26 | if (buffer_index < 2) { |
| 26 | buffer[buffer_index++] = vtx; | 27 | buffer[buffer_index++] = vtx; |
| 27 | } else { | 28 | } else { |
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 59d156ee7..68b7cc05d 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -126,6 +126,30 @@ static u32 GetDepth(int x, int y) { | |||
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | static u8 GetStencil(int x, int y) { | ||
| 130 | const auto& framebuffer = g_state.regs.framebuffer; | ||
| 131 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||
| 132 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||
| 133 | |||
| 134 | y = framebuffer.height - y; | ||
| 135 | |||
| 136 | const u32 coarse_y = y & ~7; | ||
| 137 | u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||
| 138 | u32 stride = framebuffer.width * bytes_per_pixel; | ||
| 139 | |||
| 140 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||
| 141 | u8* src_pixel = depth_buffer + src_offset; | ||
| 142 | |||
| 143 | switch (framebuffer.depth_format) { | ||
| 144 | case Regs::DepthFormat::D24S8: | ||
| 145 | return Color::DecodeD24S8(src_pixel).y; | ||
| 146 | |||
| 147 | default: | ||
| 148 | LOG_WARNING(HW_GPU, "GetStencil called for function which doesn't have a stencil component (format %u)", framebuffer.depth_format); | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 129 | static void SetDepth(int x, int y, u32 value) { | 153 | static void SetDepth(int x, int y, u32 value) { |
| 130 | const auto& framebuffer = g_state.regs.framebuffer; | 154 | const auto& framebuffer = g_state.regs.framebuffer; |
| 131 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | 155 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); |
| @@ -144,13 +168,15 @@ static void SetDepth(int x, int y, u32 value) { | |||
| 144 | case Regs::DepthFormat::D16: | 168 | case Regs::DepthFormat::D16: |
| 145 | Color::EncodeD16(value, dst_pixel); | 169 | Color::EncodeD16(value, dst_pixel); |
| 146 | break; | 170 | break; |
| 171 | |||
| 147 | case Regs::DepthFormat::D24: | 172 | case Regs::DepthFormat::D24: |
| 148 | Color::EncodeD24(value, dst_pixel); | 173 | Color::EncodeD24(value, dst_pixel); |
| 149 | break; | 174 | break; |
| 175 | |||
| 150 | case Regs::DepthFormat::D24S8: | 176 | case Regs::DepthFormat::D24S8: |
| 151 | // TODO(Subv): Implement the stencil buffer | 177 | Color::EncodeD24X8(value, dst_pixel); |
| 152 | Color::EncodeD24S8(value, 0, dst_pixel); | ||
| 153 | break; | 178 | break; |
| 179 | |||
| 154 | default: | 180 | default: |
| 155 | LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); | 181 | LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); |
| 156 | UNIMPLEMENTED(); | 182 | UNIMPLEMENTED(); |
| @@ -158,6 +184,53 @@ static void SetDepth(int x, int y, u32 value) { | |||
| 158 | } | 184 | } |
| 159 | } | 185 | } |
| 160 | 186 | ||
| 187 | static void SetStencil(int x, int y, u8 value) { | ||
| 188 | const auto& framebuffer = g_state.regs.framebuffer; | ||
| 189 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||
| 190 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||
| 191 | |||
| 192 | y = framebuffer.height - y; | ||
| 193 | |||
| 194 | const u32 coarse_y = y & ~7; | ||
| 195 | u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||
| 196 | u32 stride = framebuffer.width * bytes_per_pixel; | ||
| 197 | |||
| 198 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||
| 199 | u8* dst_pixel = depth_buffer + dst_offset; | ||
| 200 | |||
| 201 | switch (framebuffer.depth_format) { | ||
| 202 | case Pica::Regs::DepthFormat::D16: | ||
| 203 | case Pica::Regs::DepthFormat::D24: | ||
| 204 | // Nothing to do | ||
| 205 | break; | ||
| 206 | |||
| 207 | case Pica::Regs::DepthFormat::D24S8: | ||
| 208 | Color::EncodeX24S8(value, dst_pixel); | ||
| 209 | break; | ||
| 210 | |||
| 211 | default: | ||
| 212 | LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); | ||
| 213 | UNIMPLEMENTED(); | ||
| 214 | break; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | // TODO: Should the stencil mask be applied to the "dest" or "ref" operands? Most likely not! | ||
| 219 | static u8 PerformStencilAction(Regs::StencilAction action, u8 dest, u8 ref) { | ||
| 220 | switch (action) { | ||
| 221 | case Regs::StencilAction::Keep: | ||
| 222 | return dest; | ||
| 223 | |||
| 224 | case Regs::StencilAction::Xor: | ||
| 225 | return dest ^ ref; | ||
| 226 | |||
| 227 | default: | ||
| 228 | LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action); | ||
| 229 | UNIMPLEMENTED(); | ||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 161 | // NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values | 234 | // NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values |
| 162 | struct Fix12P4 { | 235 | struct Fix12P4 { |
| 163 | Fix12P4() {} | 236 | Fix12P4() {} |
| @@ -276,6 +349,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 276 | auto textures = regs.GetTextures(); | 349 | auto textures = regs.GetTextures(); |
| 277 | auto tev_stages = regs.GetTevStages(); | 350 | auto tev_stages = regs.GetTevStages(); |
| 278 | 351 | ||
| 352 | bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; | ||
| 353 | const auto stencil_test = g_state.regs.output_merger.stencil_test; | ||
| 354 | |||
| 279 | // Enter rasterization loop, starting at the center of the topleft bounding box corner. | 355 | // Enter rasterization loop, starting at the center of the topleft bounding box corner. |
| 280 | // TODO: Not sure if looping through x first might be faster | 356 | // TODO: Not sure if looping through x first might be faster |
| 281 | for (u16 y = min_y + 8; y < max_y; y += 0x10) { | 357 | for (u16 y = min_y + 8; y < max_y; y += 0x10) { |
| @@ -349,6 +425,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 349 | val = std::min(val, (int)size - 1); | 425 | val = std::min(val, (int)size - 1); |
| 350 | return val; | 426 | return val; |
| 351 | 427 | ||
| 428 | case Regs::TextureConfig::ClampToBorder: | ||
| 429 | return val; | ||
| 430 | |||
| 352 | case Regs::TextureConfig::Repeat: | 431 | case Regs::TextureConfig::Repeat: |
| 353 | return (int)((unsigned)val % size); | 432 | return (int)((unsigned)val % size); |
| 354 | 433 | ||
| @@ -367,17 +446,26 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 367 | } | 446 | } |
| 368 | }; | 447 | }; |
| 369 | 448 | ||
| 370 | // Textures are laid out from bottom to top, hence we invert the t coordinate. | 449 | if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && (s < 0 || s >= texture.config.width)) |
| 371 | // NOTE: This may not be the right place for the inversion. | 450 | || (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && (t < 0 || t >= texture.config.height))) { |
| 372 | // TODO: Check if this applies to ETC textures, too. | 451 | auto border_color = texture.config.border_color; |
| 373 | s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width); | 452 | texture_color[i] = { border_color.r, border_color.g, border_color.b, border_color.a }; |
| 374 | t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); | 453 | } else { |
| 375 | 454 | // Textures are laid out from bottom to top, hence we invert the t coordinate. | |
| 376 | u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); | 455 | // NOTE: This may not be the right place for the inversion. |
| 377 | auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format); | 456 | // TODO: Check if this applies to ETC textures, too. |
| 378 | 457 | s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width); | |
| 379 | texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); | 458 | t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); |
| 380 | DebugUtils::DumpTexture(texture.config, texture_data); | 459 | |
| 460 | u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); | ||
| 461 | auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format); | ||
| 462 | |||
| 463 | // TODO: Apply the min and mag filters to the texture | ||
| 464 | texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); | ||
| 465 | #if PICA_DUMP_TEXTURES | ||
| 466 | DebugUtils::DumpTexture(texture.config, texture_data); | ||
| 467 | #endif | ||
| 468 | } | ||
| 381 | } | 469 | } |
| 382 | 470 | ||
| 383 | // Texture environment - consists of 6 stages of color and alpha combining. | 471 | // Texture environment - consists of 6 stages of color and alpha combining. |
| @@ -556,7 +644,18 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 556 | result = (result * input[2].Cast<int>()) / 255; | 644 | result = (result * input[2].Cast<int>()) / 255; |
| 557 | return result.Cast<u8>(); | 645 | return result.Cast<u8>(); |
| 558 | } | 646 | } |
| 559 | 647 | case Operation::Dot3_RGB: | |
| 648 | { | ||
| 649 | // Not fully accurate. | ||
| 650 | // Worst case scenario seems to yield a +/-3 error | ||
| 651 | // Some HW results indicate that the per-component computation can't have a higher precision than 1/256, | ||
| 652 | // while dot3_rgb( (0x80,g0,b0),(0x7F,g1,b1) ) and dot3_rgb( (0x80,g0,b0),(0x80,g1,b1) ) give different results | ||
| 653 | int result = ((input[0].r() * 2 - 255) * (input[1].r() * 2 - 255) + 128) / 256 + | ||
| 654 | ((input[0].g() * 2 - 255) * (input[1].g() * 2 - 255) + 128) / 256 + | ||
| 655 | ((input[0].b() * 2 - 255) * (input[1].b() * 2 - 255) + 128) / 256; | ||
| 656 | result = std::max(0, std::min(255, result)); | ||
| 657 | return { (u8)result, (u8)result, (u8)result }; | ||
| 658 | } | ||
| 560 | default: | 659 | default: |
| 561 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); | 660 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); |
| 562 | UNIMPLEMENTED(); | 661 | UNIMPLEMENTED(); |
| @@ -638,6 +737,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 638 | } | 737 | } |
| 639 | 738 | ||
| 640 | const auto& output_merger = regs.output_merger; | 739 | const auto& output_merger = regs.output_merger; |
| 740 | // TODO: Does alpha testing happen before or after stencil? | ||
| 641 | if (output_merger.alpha_test.enable) { | 741 | if (output_merger.alpha_test.enable) { |
| 642 | bool pass = false; | 742 | bool pass = false; |
| 643 | 743 | ||
| @@ -679,6 +779,54 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 679 | continue; | 779 | continue; |
| 680 | } | 780 | } |
| 681 | 781 | ||
| 782 | u8 old_stencil = 0; | ||
| 783 | if (stencil_action_enable) { | ||
| 784 | old_stencil = GetStencil(x >> 4, y >> 4); | ||
| 785 | u8 dest = old_stencil & stencil_test.mask; | ||
| 786 | u8 ref = stencil_test.reference_value & stencil_test.mask; | ||
| 787 | |||
| 788 | bool pass = false; | ||
| 789 | switch (stencil_test.func) { | ||
| 790 | case Regs::CompareFunc::Never: | ||
| 791 | pass = false; | ||
| 792 | break; | ||
| 793 | |||
| 794 | case Regs::CompareFunc::Always: | ||
| 795 | pass = true; | ||
| 796 | break; | ||
| 797 | |||
| 798 | case Regs::CompareFunc::Equal: | ||
| 799 | pass = (ref == dest); | ||
| 800 | break; | ||
| 801 | |||
| 802 | case Regs::CompareFunc::NotEqual: | ||
| 803 | pass = (ref != dest); | ||
| 804 | break; | ||
| 805 | |||
| 806 | case Regs::CompareFunc::LessThan: | ||
| 807 | pass = (ref < dest); | ||
| 808 | break; | ||
| 809 | |||
| 810 | case Regs::CompareFunc::LessThanOrEqual: | ||
| 811 | pass = (ref <= dest); | ||
| 812 | break; | ||
| 813 | |||
| 814 | case Regs::CompareFunc::GreaterThan: | ||
| 815 | pass = (ref > dest); | ||
| 816 | break; | ||
| 817 | |||
| 818 | case Regs::CompareFunc::GreaterThanOrEqual: | ||
| 819 | pass = (ref >= dest); | ||
| 820 | break; | ||
| 821 | } | ||
| 822 | |||
| 823 | if (!pass) { | ||
| 824 | u8 new_stencil = PerformStencilAction(stencil_test.action_stencil_fail, old_stencil, stencil_test.replacement_value); | ||
| 825 | SetStencil(x >> 4, y >> 4, new_stencil); | ||
| 826 | continue; | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 682 | // TODO: Does depth indeed only get written even if depth testing is enabled? | 830 | // TODO: Does depth indeed only get written even if depth testing is enabled? |
| 683 | if (output_merger.depth_test_enable) { | 831 | if (output_merger.depth_test_enable) { |
| 684 | unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); | 832 | unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); |
| @@ -723,11 +871,22 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 723 | break; | 871 | break; |
| 724 | } | 872 | } |
| 725 | 873 | ||
| 726 | if (!pass) | 874 | if (!pass) { |
| 875 | if (stencil_action_enable) { | ||
| 876 | u8 new_stencil = PerformStencilAction(stencil_test.action_depth_fail, old_stencil, stencil_test.replacement_value); | ||
| 877 | SetStencil(x >> 4, y >> 4, new_stencil); | ||
| 878 | } | ||
| 727 | continue; | 879 | continue; |
| 880 | } | ||
| 728 | 881 | ||
| 729 | if (output_merger.depth_write_enable) | 882 | if (output_merger.depth_write_enable) |
| 730 | SetDepth(x >> 4, y >> 4, z); | 883 | SetDepth(x >> 4, y >> 4, z); |
| 884 | |||
| 885 | if (stencil_action_enable) { | ||
| 886 | // TODO: What happens if stencil testing is enabled, but depth testing is not? Will stencil get updated anyway? | ||
| 887 | u8 new_stencil = PerformStencilAction(stencil_test.action_depth_pass, old_stencil, stencil_test.replacement_value); | ||
| 888 | SetStencil(x >> 4, y >> 4, new_stencil); | ||
| 889 | } | ||
| 731 | } | 890 | } |
| 732 | 891 | ||
| 733 | auto dest = GetPixel(x >> 4, y >> 4); | 892 | auto dest = GetPixel(x >> 4, y >> 4); |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 5757ac75d..6587bcf27 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -4,10 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | #include "video_core/hwrasterizer_base.h" | 11 | #include "video_core/hwrasterizer_base.h" |
| 10 | 12 | ||
| 13 | class EmuWindow; | ||
| 14 | |||
| 11 | class RendererBase : NonCopyable { | 15 | class RendererBase : NonCopyable { |
| 12 | public: | 16 | public: |
| 13 | 17 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 518f79331..2db845da6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -2,10 +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 <cstring> | ||
| 6 | #include <memory> | ||
| 7 | |||
| 5 | #include "common/color.h" | 8 | #include "common/color.h" |
| 9 | #include "common/math_util.h" | ||
| 6 | 10 | ||
| 7 | #include "core/settings.h" | ||
| 8 | #include "core/hw/gpu.h" | 11 | #include "core/hw/gpu.h" |
| 12 | #include "core/memory.h" | ||
| 13 | #include "core/settings.h" | ||
| 9 | 14 | ||
| 10 | #include "video_core/pica.h" | 15 | #include "video_core/pica.h" |
| 11 | #include "video_core/utils.h" | 16 | #include "video_core/utils.h" |
| @@ -16,8 +21,6 @@ | |||
| 16 | 21 | ||
| 17 | #include "generated/gl_3_2_core.h" | 22 | #include "generated/gl_3_2_core.h" |
| 18 | 23 | ||
| 19 | #include <memory> | ||
| 20 | |||
| 21 | static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { | 24 | static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { |
| 22 | return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && | 25 | return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && |
| 23 | stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && | 26 | stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && |
| @@ -813,12 +816,16 @@ void RasterizerOpenGL::ReloadColorBuffer() { | |||
| 813 | } | 816 | } |
| 814 | 817 | ||
| 815 | void RasterizerOpenGL::ReloadDepthBuffer() { | 818 | void RasterizerOpenGL::ReloadDepthBuffer() { |
| 819 | PAddr depth_buffer_addr = Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress(); | ||
| 820 | |||
| 821 | if (depth_buffer_addr == 0) | ||
| 822 | return; | ||
| 823 | |||
| 816 | // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil | 824 | // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil |
| 817 | u8* depth_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress()); | 825 | u8* depth_buffer = Memory::GetPhysicalPointer(depth_buffer_addr); |
| 818 | 826 | ||
| 819 | if (depth_buffer == nullptr) { | 827 | if (depth_buffer == nullptr) |
| 820 | return; | 828 | return; |
| 821 | } | ||
| 822 | 829 | ||
| 823 | u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); | 830 | u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); |
| 824 | 831 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index d7d422b1f..ae7b26fc6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -4,7 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 7 | #include "video_core/hwrasterizer_base.h" | 11 | #include "video_core/hwrasterizer_base.h" |
| 12 | #include "video_core/vertex_shader.h" | ||
| 8 | 13 | ||
| 9 | #include "gl_state.h" | 14 | #include "gl_state.h" |
| 10 | #include "gl_rasterizer_cache.h" | 15 | #include "gl_rasterizer_cache.h" |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 2e4110a88..dc3ffdf22 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -31,12 +31,18 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text | |||
| 31 | state.texture_units[texture_unit].texture_2d = new_texture->texture.handle; | 31 | state.texture_units[texture_unit].texture_2d = new_texture->texture.handle; |
| 32 | state.Apply(); | 32 | state.Apply(); |
| 33 | 33 | ||
| 34 | // TODO: Need to choose filters that correspond to PICA once register is declared | 34 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(config.config.mag_filter)); |
| 35 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 35 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(config.config.min_filter)); |
| 36 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 37 | 36 | ||
| 38 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s)); | 37 | GLenum wrap_s = PicaToGL::WrapMode(config.config.wrap_s); |
| 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t)); | 38 | GLenum wrap_t = PicaToGL::WrapMode(config.config.wrap_t); |
| 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); | ||
| 40 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); | ||
| 41 | |||
| 42 | if (wrap_s == GL_CLAMP_TO_BORDER || wrap_t == GL_CLAMP_TO_BORDER) { | ||
| 43 | auto border_color = PicaToGL::ColorRGBA8((u8*)&config.config.border_color.r); | ||
| 44 | glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color.data()); | ||
| 45 | } | ||
| 40 | 46 | ||
| 41 | const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); | 47 | const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); |
| 42 | 48 | ||
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp deleted file mode 100644 index 8f4ae28a4..000000000 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ /dev/null | |||
| @@ -1,111 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 7 | |||
| 8 | // Textures | ||
| 9 | OGLTexture::OGLTexture() : handle(0) { | ||
| 10 | } | ||
| 11 | |||
| 12 | OGLTexture::~OGLTexture() { | ||
| 13 | Release(); | ||
| 14 | } | ||
| 15 | |||
| 16 | void OGLTexture::Create() { | ||
| 17 | if (handle != 0) { | ||
| 18 | return; | ||
| 19 | } | ||
| 20 | |||
| 21 | glGenTextures(1, &handle); | ||
| 22 | } | ||
| 23 | |||
| 24 | void OGLTexture::Release() { | ||
| 25 | glDeleteTextures(1, &handle); | ||
| 26 | handle = 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | // Shaders | ||
| 30 | OGLShader::OGLShader() : handle(0) { | ||
| 31 | } | ||
| 32 | |||
| 33 | OGLShader::~OGLShader() { | ||
| 34 | Release(); | ||
| 35 | } | ||
| 36 | |||
| 37 | void OGLShader::Create(const char* vert_shader, const char* frag_shader) { | ||
| 38 | if (handle != 0) { | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | |||
| 42 | handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); | ||
| 43 | } | ||
| 44 | |||
| 45 | void OGLShader::Release() { | ||
| 46 | glDeleteProgram(handle); | ||
| 47 | handle = 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | // Buffer objects | ||
| 51 | OGLBuffer::OGLBuffer() : handle(0) { | ||
| 52 | } | ||
| 53 | |||
| 54 | OGLBuffer::~OGLBuffer() { | ||
| 55 | Release(); | ||
| 56 | } | ||
| 57 | |||
| 58 | void OGLBuffer::Create() { | ||
| 59 | if (handle != 0) { | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | glGenBuffers(1, &handle); | ||
| 64 | } | ||
| 65 | |||
| 66 | void OGLBuffer::Release() { | ||
| 67 | glDeleteBuffers(1, &handle); | ||
| 68 | handle = 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | // Vertex array objects | ||
| 72 | OGLVertexArray::OGLVertexArray() : handle(0) { | ||
| 73 | } | ||
| 74 | |||
| 75 | OGLVertexArray::~OGLVertexArray() { | ||
| 76 | Release(); | ||
| 77 | } | ||
| 78 | |||
| 79 | void OGLVertexArray::Create() { | ||
| 80 | if (handle != 0) { | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | |||
| 84 | glGenVertexArrays(1, &handle); | ||
| 85 | } | ||
| 86 | |||
| 87 | void OGLVertexArray::Release() { | ||
| 88 | glDeleteVertexArrays(1, &handle); | ||
| 89 | handle = 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | // Framebuffers | ||
| 93 | OGLFramebuffer::OGLFramebuffer() : handle(0) { | ||
| 94 | } | ||
| 95 | |||
| 96 | OGLFramebuffer::~OGLFramebuffer() { | ||
| 97 | Release(); | ||
| 98 | } | ||
| 99 | |||
| 100 | void OGLFramebuffer::Create() { | ||
| 101 | if (handle != 0) { | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | glGenFramebuffers(1, &handle); | ||
| 106 | } | ||
| 107 | |||
| 108 | void OGLFramebuffer::Release() { | ||
| 109 | glDeleteFramebuffers(1, &handle); | ||
| 110 | handle = 0; | ||
| 111 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 975720d0a..6f9dc012d 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h | |||
| @@ -4,76 +4,124 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <utility> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | #include "generated/gl_3_2_core.h" | 11 | #include "video_core/renderer_opengl/generated/gl_3_2_core.h" |
| 12 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 10 | 13 | ||
| 11 | class OGLTexture : public NonCopyable { | 14 | class OGLTexture : private NonCopyable { |
| 12 | public: | 15 | public: |
| 13 | OGLTexture(); | 16 | OGLTexture() = default; |
| 14 | ~OGLTexture(); | 17 | OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); } |
| 18 | ~OGLTexture() { Release(); } | ||
| 19 | OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; } | ||
| 15 | 20 | ||
| 16 | /// Creates a new internal OpenGL resource and stores the handle | 21 | /// Creates a new internal OpenGL resource and stores the handle |
| 17 | void Create(); | 22 | void Create() { |
| 23 | if (handle != 0) return; | ||
| 24 | glGenTextures(1, &handle); | ||
| 25 | } | ||
| 18 | 26 | ||
| 19 | /// Deletes the internal OpenGL resource | 27 | /// Deletes the internal OpenGL resource |
| 20 | void Release(); | 28 | void Release() { |
| 29 | if (handle == 0) return; | ||
| 30 | glDeleteTextures(1, &handle); | ||
| 31 | handle = 0; | ||
| 32 | } | ||
| 21 | 33 | ||
| 22 | GLuint handle; | 34 | GLuint handle = 0; |
| 23 | }; | 35 | }; |
| 24 | 36 | ||
| 25 | class OGLShader : public NonCopyable { | 37 | class OGLShader : private NonCopyable { |
| 26 | public: | 38 | public: |
| 27 | OGLShader(); | 39 | OGLShader() = default; |
| 28 | ~OGLShader(); | 40 | OGLShader(OGLShader&& o) { std::swap(handle, o.handle); } |
| 41 | ~OGLShader() { Release(); } | ||
| 42 | OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; } | ||
| 29 | 43 | ||
| 30 | /// Creates a new internal OpenGL resource and stores the handle | 44 | /// Creates a new internal OpenGL resource and stores the handle |
| 31 | void Create(const char* vert_shader, const char* frag_shader); | 45 | void Create(const char* vert_shader, const char* frag_shader) { |
| 46 | if (handle != 0) return; | ||
| 47 | handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); | ||
| 48 | } | ||
| 32 | 49 | ||
| 33 | /// Deletes the internal OpenGL resource | 50 | /// Deletes the internal OpenGL resource |
| 34 | void Release(); | 51 | void Release() { |
| 52 | if (handle == 0) return; | ||
| 53 | glDeleteProgram(handle); | ||
| 54 | handle = 0; | ||
| 55 | } | ||
| 35 | 56 | ||
| 36 | GLuint handle; | 57 | GLuint handle = 0; |
| 37 | }; | 58 | }; |
| 38 | 59 | ||
| 39 | class OGLBuffer : public NonCopyable { | 60 | class OGLBuffer : private NonCopyable { |
| 40 | public: | 61 | public: |
| 41 | OGLBuffer(); | 62 | OGLBuffer() = default; |
| 42 | ~OGLBuffer(); | 63 | OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); } |
| 64 | ~OGLBuffer() { Release(); } | ||
| 65 | OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; } | ||
| 43 | 66 | ||
| 44 | /// Creates a new internal OpenGL resource and stores the handle | 67 | /// Creates a new internal OpenGL resource and stores the handle |
| 45 | void Create(); | 68 | void Create() { |
| 69 | if (handle != 0) return; | ||
| 70 | glGenBuffers(1, &handle); | ||
| 71 | } | ||
| 46 | 72 | ||
| 47 | /// Deletes the internal OpenGL resource | 73 | /// Deletes the internal OpenGL resource |
| 48 | void Release(); | 74 | void Release() { |
| 75 | if (handle == 0) return; | ||
| 76 | glDeleteBuffers(1, &handle); | ||
| 77 | handle = 0; | ||
| 78 | } | ||
| 49 | 79 | ||
| 50 | GLuint handle; | 80 | GLuint handle = 0; |
| 51 | }; | 81 | }; |
| 52 | 82 | ||
| 53 | class OGLVertexArray : public NonCopyable { | 83 | class OGLVertexArray : private NonCopyable { |
| 54 | public: | 84 | public: |
| 55 | OGLVertexArray(); | 85 | OGLVertexArray() = default; |
| 56 | ~OGLVertexArray(); | 86 | OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); } |
| 87 | ~OGLVertexArray() { Release(); } | ||
| 88 | OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; } | ||
| 57 | 89 | ||
| 58 | /// Creates a new internal OpenGL resource and stores the handle | 90 | /// Creates a new internal OpenGL resource and stores the handle |
| 59 | void Create(); | 91 | void Create() { |
| 92 | if (handle != 0) return; | ||
| 93 | glGenVertexArrays(1, &handle); | ||
| 94 | } | ||
| 60 | 95 | ||
| 61 | /// Deletes the internal OpenGL resource | 96 | /// Deletes the internal OpenGL resource |
| 62 | void Release(); | 97 | void Release() { |
| 98 | if (handle == 0) return; | ||
| 99 | glDeleteVertexArrays(1, &handle); | ||
| 100 | handle = 0; | ||
| 101 | } | ||
| 63 | 102 | ||
| 64 | GLuint handle; | 103 | GLuint handle = 0; |
| 65 | }; | 104 | }; |
| 66 | 105 | ||
| 67 | class OGLFramebuffer : public NonCopyable { | 106 | class OGLFramebuffer : private NonCopyable { |
| 68 | public: | 107 | public: |
| 69 | OGLFramebuffer(); | 108 | OGLFramebuffer() = default; |
| 70 | ~OGLFramebuffer(); | 109 | OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); } |
| 110 | ~OGLFramebuffer() { Release(); } | ||
| 111 | OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; } | ||
| 71 | 112 | ||
| 72 | /// Creates a new internal OpenGL resource and stores the handle | 113 | /// Creates a new internal OpenGL resource and stores the handle |
| 73 | void Create(); | 114 | void Create() { |
| 115 | if (handle != 0) return; | ||
| 116 | glGenFramebuffers(1, &handle); | ||
| 117 | } | ||
| 74 | 118 | ||
| 75 | /// Deletes the internal OpenGL resource | 119 | /// Deletes the internal OpenGL resource |
| 76 | void Release(); | 120 | void Release() { |
| 121 | if (handle == 0) return; | ||
| 122 | glDeleteFramebuffers(1, &handle); | ||
| 123 | handle = 0; | ||
| 124 | } | ||
| 77 | 125 | ||
| 78 | GLuint handle; | 126 | GLuint handle = 0; |
| 79 | }; | 127 | }; |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 3526e16d5..9efc15337 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -147,20 +147,17 @@ void OpenGLState::Apply() { | |||
| 147 | 147 | ||
| 148 | // Textures | 148 | // Textures |
| 149 | for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { | 149 | for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { |
| 150 | if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { | 150 | if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d || |
| 151 | texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) { | ||
| 152 | |||
| 151 | glActiveTexture(GL_TEXTURE0 + texture_index); | 153 | glActiveTexture(GL_TEXTURE0 + texture_index); |
| 152 | 154 | ||
| 153 | if (texture_units[texture_index].enabled_2d) { | 155 | if (texture_units[texture_index].enabled_2d) { |
| 154 | glEnable(GL_TEXTURE_2D); | 156 | glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d); |
| 155 | } else { | 157 | } else { |
| 156 | glDisable(GL_TEXTURE_2D); | 158 | glBindTexture(GL_TEXTURE_2D, 0); |
| 157 | } | 159 | } |
| 158 | } | 160 | } |
| 159 | |||
| 160 | if (texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) { | ||
| 161 | glActiveTexture(GL_TEXTURE0 + texture_index); | ||
| 162 | glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d); | ||
| 163 | } | ||
| 164 | } | 161 | } |
| 165 | 162 | ||
| 166 | // Framebuffer | 163 | // Framebuffer |
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index e566f9f7a..3b562da86 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h | |||
| @@ -12,10 +12,37 @@ | |||
| 12 | 12 | ||
| 13 | namespace PicaToGL { | 13 | namespace PicaToGL { |
| 14 | 14 | ||
| 15 | inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { | ||
| 16 | static const GLenum filter_mode_table[] = { | ||
| 17 | GL_NEAREST, // TextureFilter::Nearest | ||
| 18 | GL_LINEAR // TextureFilter::Linear | ||
| 19 | }; | ||
| 20 | |||
| 21 | // Range check table for input | ||
| 22 | if (mode >= ARRAY_SIZE(filter_mode_table)) { | ||
| 23 | LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode); | ||
| 24 | UNREACHABLE(); | ||
| 25 | |||
| 26 | return GL_LINEAR; | ||
| 27 | } | ||
| 28 | |||
| 29 | GLenum gl_mode = filter_mode_table[mode]; | ||
| 30 | |||
| 31 | // Check for dummy values indicating an unknown mode | ||
| 32 | if (gl_mode == 0) { | ||
| 33 | LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode); | ||
| 34 | UNIMPLEMENTED(); | ||
| 35 | |||
| 36 | return GL_LINEAR; | ||
| 37 | } | ||
| 38 | |||
| 39 | return gl_mode; | ||
| 40 | } | ||
| 41 | |||
| 15 | inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { | 42 | inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { |
| 16 | static const GLenum wrap_mode_table[] = { | 43 | static const GLenum wrap_mode_table[] = { |
| 17 | GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge | 44 | GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge |
| 18 | 0, // Unknown | 45 | GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder |
| 19 | GL_REPEAT, // WrapMode::Repeat | 46 | GL_REPEAT, // WrapMode::Repeat |
| 20 | GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat | 47 | GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat |
| 21 | }; | 48 | }; |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 3399ca123..96e12839a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -2,22 +2,27 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <cstddef> | ||
| 7 | #include <cstdlib> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/emu_window.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "common/profiler_reporting.h" | ||
| 13 | |||
| 5 | #include "core/hw/gpu.h" | 14 | #include "core/hw/gpu.h" |
| 6 | #include "core/hw/hw.h" | 15 | #include "core/hw/hw.h" |
| 7 | #include "core/hw/lcd.h" | 16 | #include "core/hw/lcd.h" |
| 8 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 9 | #include "core/settings.h" | 18 | #include "core/settings.h" |
| 10 | 19 | ||
| 11 | #include "common/emu_window.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/profiler_reporting.h" | ||
| 14 | |||
| 15 | #include "video_core/video_core.h" | 20 | #include "video_core/video_core.h" |
| 16 | #include "video_core/renderer_opengl/renderer_opengl.h" | 21 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 17 | #include "video_core/renderer_opengl/gl_shader_util.h" | 22 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 18 | #include "video_core/renderer_opengl/gl_shaders.h" | 23 | #include "video_core/renderer_opengl/gl_shaders.h" |
| 19 | 24 | ||
| 20 | #include <algorithm> | 25 | #include "video_core/debug_utils/debug_utils.h" |
| 21 | 26 | ||
| 22 | /** | 27 | /** |
| 23 | * Vertex structure that the drawn screen rectangles are composed of. | 28 | * Vertex structure that the drawn screen rectangles are composed of. |
| @@ -126,6 +131,10 @@ void RendererOpenGL::SwapBuffers() { | |||
| 126 | hw_rasterizer->Reset(); | 131 | hw_rasterizer->Reset(); |
| 127 | } | 132 | } |
| 128 | } | 133 | } |
| 134 | |||
| 135 | if (Pica::g_debug_context && Pica::g_debug_context->recorder) { | ||
| 136 | Pica::g_debug_context->recorder->FrameFinished(); | ||
| 137 | } | ||
| 129 | } | 138 | } |
| 130 | 139 | ||
| 131 | /** | 140 | /** |
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index 87006a832..960ae5779 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp | |||
| @@ -2,8 +2,7 @@ | |||
| 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 <stack> | 5 | #include <boost/container/static_vector.hpp> |
| 6 | |||
| 7 | #include <boost/range/algorithm.hpp> | 6 | #include <boost/range/algorithm.hpp> |
| 8 | 7 | ||
| 9 | #include <common/file_util.h> | 8 | #include <common/file_util.h> |
| @@ -27,7 +26,7 @@ namespace Pica { | |||
| 27 | namespace VertexShader { | 26 | namespace VertexShader { |
| 28 | 27 | ||
| 29 | struct VertexShaderState { | 28 | struct VertexShaderState { |
| 30 | const u32* program_counter; | 29 | u32 program_counter; |
| 31 | 30 | ||
| 32 | const float24* input_register_table[16]; | 31 | const float24* input_register_table[16]; |
| 33 | Math::Vec4<float24> output_registers[16]; | 32 | Math::Vec4<float24> output_registers[16]; |
| @@ -53,7 +52,7 @@ struct VertexShaderState { | |||
| 53 | }; | 52 | }; |
| 54 | 53 | ||
| 55 | // TODO: Is there a maximal size for this? | 54 | // TODO: Is there a maximal size for this? |
| 56 | std::stack<CallStackElement> call_stack; | 55 | boost::container::static_vector<CallStackElement, 16> call_stack; |
| 57 | 56 | ||
| 58 | struct { | 57 | struct { |
| 59 | u32 max_offset; // maximum program counter ever reached | 58 | u32 max_offset; // maximum program counter ever reached |
| @@ -71,15 +70,15 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 71 | 70 | ||
| 72 | while (true) { | 71 | while (true) { |
| 73 | if (!state.call_stack.empty()) { | 72 | if (!state.call_stack.empty()) { |
| 74 | auto& top = state.call_stack.top(); | 73 | auto& top = state.call_stack.back(); |
| 75 | if (state.program_counter - program_code.data() == top.final_address) { | 74 | if (state.program_counter == top.final_address) { |
| 76 | state.address_registers[2] += top.loop_increment; | 75 | state.address_registers[2] += top.loop_increment; |
| 77 | 76 | ||
| 78 | if (top.repeat_counter-- == 0) { | 77 | if (top.repeat_counter-- == 0) { |
| 79 | state.program_counter = &program_code[top.return_address]; | 78 | state.program_counter = top.return_address; |
| 80 | state.call_stack.pop(); | 79 | state.call_stack.pop_back(); |
| 81 | } else { | 80 | } else { |
| 82 | state.program_counter = &program_code[top.loop_address]; | 81 | state.program_counter = top.loop_address; |
| 83 | } | 82 | } |
| 84 | 83 | ||
| 85 | // TODO: Is "trying again" accurate to hardware? | 84 | // TODO: Is "trying again" accurate to hardware? |
| @@ -88,17 +87,16 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 88 | } | 87 | } |
| 89 | 88 | ||
| 90 | bool exit_loop = false; | 89 | bool exit_loop = false; |
| 91 | const Instruction& instr = *(const Instruction*)state.program_counter; | 90 | const Instruction instr = { program_code[state.program_counter] }; |
| 92 | const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; | 91 | const SwizzlePattern swizzle = { swizzle_data[instr.common.operand_desc_id] }; |
| 93 | 92 | ||
| 94 | static auto call = [&program_code](VertexShaderState& state, u32 offset, u32 num_instructions, | 93 | static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions, |
| 95 | u32 return_offset, u8 repeat_count, u8 loop_increment) { | 94 | u32 return_offset, u8 repeat_count, u8 loop_increment) { |
| 96 | state.program_counter = &program_code[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset | 95 | state.program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset |
| 97 | state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); | 96 | ASSERT(state.call_stack.size() < state.call_stack.capacity()); |
| 97 | state.call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); | ||
| 98 | }; | 98 | }; |
| 99 | u32 binary_offset = state.program_counter - program_code.data(); | 99 | state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + state.program_counter); |
| 100 | |||
| 101 | state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset); | ||
| 102 | 100 | ||
| 103 | auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { | 101 | auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { |
| 104 | switch (source_reg.GetRegisterType()) { | 102 | switch (source_reg.GetRegisterType()) { |
| @@ -221,7 +219,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 221 | for (int i = 0; i < num_components; ++i) | 219 | for (int i = 0; i < num_components; ++i) |
| 222 | dot = dot + src1[i] * src2[i]; | 220 | dot = dot + src1[i] * src2[i]; |
| 223 | 221 | ||
| 224 | for (int i = 0; i < num_components; ++i) { | 222 | for (int i = 0; i < 4; ++i) { |
| 225 | if (!swizzle.DestComponentEnabled(i)) | 223 | if (!swizzle.DestComponentEnabled(i)) |
| 226 | continue; | 224 | continue; |
| 227 | 225 | ||
| @@ -442,13 +440,13 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 442 | 440 | ||
| 443 | case OpCode::Id::JMPC: | 441 | case OpCode::Id::JMPC: |
| 444 | if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { | 442 | if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { |
| 445 | state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; | 443 | state.program_counter = instr.flow_control.dest_offset - 1; |
| 446 | } | 444 | } |
| 447 | break; | 445 | break; |
| 448 | 446 | ||
| 449 | case OpCode::Id::JMPU: | 447 | case OpCode::Id::JMPU: |
| 450 | if (uniforms.b[instr.flow_control.bool_uniform_id]) { | 448 | if (uniforms.b[instr.flow_control.bool_uniform_id]) { |
| 451 | state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; | 449 | state.program_counter = instr.flow_control.dest_offset - 1; |
| 452 | } | 450 | } |
| 453 | break; | 451 | break; |
| 454 | 452 | ||
| @@ -456,7 +454,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 456 | call(state, | 454 | call(state, |
| 457 | instr.flow_control.dest_offset, | 455 | instr.flow_control.dest_offset, |
| 458 | instr.flow_control.num_instructions, | 456 | instr.flow_control.num_instructions, |
| 459 | binary_offset + 1, 0, 0); | 457 | state.program_counter + 1, 0, 0); |
| 460 | break; | 458 | break; |
| 461 | 459 | ||
| 462 | case OpCode::Id::CALLU: | 460 | case OpCode::Id::CALLU: |
| @@ -464,7 +462,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 464 | call(state, | 462 | call(state, |
| 465 | instr.flow_control.dest_offset, | 463 | instr.flow_control.dest_offset, |
| 466 | instr.flow_control.num_instructions, | 464 | instr.flow_control.num_instructions, |
| 467 | binary_offset + 1, 0, 0); | 465 | state.program_counter + 1, 0, 0); |
| 468 | } | 466 | } |
| 469 | break; | 467 | break; |
| 470 | 468 | ||
| @@ -473,7 +471,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 473 | call(state, | 471 | call(state, |
| 474 | instr.flow_control.dest_offset, | 472 | instr.flow_control.dest_offset, |
| 475 | instr.flow_control.num_instructions, | 473 | instr.flow_control.num_instructions, |
| 476 | binary_offset + 1, 0, 0); | 474 | state.program_counter + 1, 0, 0); |
| 477 | } | 475 | } |
| 478 | break; | 476 | break; |
| 479 | 477 | ||
| @@ -483,8 +481,8 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 483 | case OpCode::Id::IFU: | 481 | case OpCode::Id::IFU: |
| 484 | if (uniforms.b[instr.flow_control.bool_uniform_id]) { | 482 | if (uniforms.b[instr.flow_control.bool_uniform_id]) { |
| 485 | call(state, | 483 | call(state, |
| 486 | binary_offset + 1, | 484 | state.program_counter + 1, |
| 487 | instr.flow_control.dest_offset - binary_offset - 1, | 485 | instr.flow_control.dest_offset - state.program_counter - 1, |
| 488 | instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); | 486 | instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); |
| 489 | } else { | 487 | } else { |
| 490 | call(state, | 488 | call(state, |
| @@ -501,8 +499,8 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 501 | 499 | ||
| 502 | if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { | 500 | if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { |
| 503 | call(state, | 501 | call(state, |
| 504 | binary_offset + 1, | 502 | state.program_counter + 1, |
| 505 | instr.flow_control.dest_offset - binary_offset - 1, | 503 | instr.flow_control.dest_offset - state.program_counter - 1, |
| 506 | instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); | 504 | instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); |
| 507 | } else { | 505 | } else { |
| 508 | call(state, | 506 | call(state, |
| @@ -519,8 +517,8 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 519 | state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y; | 517 | state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y; |
| 520 | 518 | ||
| 521 | call(state, | 519 | call(state, |
| 522 | binary_offset + 1, | 520 | state.program_counter + 1, |
| 523 | instr.flow_control.dest_offset - binary_offset + 1, | 521 | instr.flow_control.dest_offset - state.program_counter + 1, |
| 524 | instr.flow_control.dest_offset + 1, | 522 | instr.flow_control.dest_offset + 1, |
| 525 | uniforms.i[instr.flow_control.int_uniform_id].x, | 523 | uniforms.i[instr.flow_control.int_uniform_id].x, |
| 526 | uniforms.i[instr.flow_control.int_uniform_id].z); | 524 | uniforms.i[instr.flow_control.int_uniform_id].z); |
| @@ -546,20 +544,17 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 546 | 544 | ||
| 547 | static Common::Profiling::TimingCategory shader_category("Vertex Shader"); | 545 | static Common::Profiling::TimingCategory shader_category("Vertex Shader"); |
| 548 | 546 | ||
| 549 | OutputVertex RunShader(const InputVertex& input, int num_attributes) { | 547 | OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup) { |
| 550 | Common::Profiling::ScopeTimer timer(shader_category); | 548 | Common::Profiling::ScopeTimer timer(shader_category); |
| 551 | 549 | ||
| 552 | const auto& regs = g_state.regs; | ||
| 553 | const auto& vs = g_state.vs; | ||
| 554 | VertexShaderState state; | 550 | VertexShaderState state; |
| 555 | 551 | ||
| 556 | const u32* main = &vs.program_code[regs.vs_main_offset]; | 552 | state.program_counter = config.main_offset; |
| 557 | state.program_counter = (u32*)main; | ||
| 558 | state.debug.max_offset = 0; | 553 | state.debug.max_offset = 0; |
| 559 | state.debug.max_opdesc_id = 0; | 554 | state.debug.max_opdesc_id = 0; |
| 560 | 555 | ||
| 561 | // Setup input register table | 556 | // Setup input register table |
| 562 | const auto& attribute_register_map = regs.vs_input_register_map; | 557 | const auto& attribute_register_map = config.input_register_map; |
| 563 | float24 dummy_register; | 558 | float24 dummy_register; |
| 564 | boost::fill(state.input_register_table, &dummy_register); | 559 | boost::fill(state.input_register_table, &dummy_register); |
| 565 | 560 | ||
| @@ -584,16 +579,18 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) { | |||
| 584 | state.conditional_code[1] = false; | 579 | state.conditional_code[1] = false; |
| 585 | 580 | ||
| 586 | ProcessShaderCode(state); | 581 | ProcessShaderCode(state); |
| 587 | DebugUtils::DumpShader(vs.program_code.data(), state.debug.max_offset, vs.swizzle_data.data(), | 582 | #if PICA_DUMP_SHADERS |
| 588 | state.debug.max_opdesc_id, regs.vs_main_offset, | 583 | DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(), |
| 589 | regs.vs_output_attributes); | 584 | state.debug.max_opdesc_id, config.main_offset, |
| 585 | g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here | ||
| 586 | #endif | ||
| 590 | 587 | ||
| 591 | // Setup output data | 588 | // Setup output data |
| 592 | OutputVertex ret; | 589 | OutputVertex ret; |
| 593 | // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to | 590 | // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to |
| 594 | // figure out what those circumstances are and enable the remaining outputs then. | 591 | // figure out what those circumstances are and enable the remaining outputs then. |
| 595 | for (int i = 0; i < 7; ++i) { | 592 | for (int i = 0; i < 7; ++i) { |
| 596 | const auto& output_register_map = regs.vs_output_attributes[i]; | 593 | const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here |
| 597 | 594 | ||
| 598 | u32 semantics[4] = { | 595 | u32 semantics[4] = { |
| 599 | output_register_map.map_x, output_register_map.map_y, | 596 | output_register_map.map_x, output_register_map.map_y, |
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h index 7471a6de8..97f9250dd 100644 --- a/src/video_core/vertex_shader.h +++ b/src/video_core/vertex_shader.h | |||
| @@ -4,11 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <initializer_list> | 7 | #include <type_traits> |
| 8 | 8 | ||
| 9 | #include <common/common_types.h> | 9 | #include "common/vector_math.h" |
| 10 | 10 | ||
| 11 | #include "math.h" | ||
| 12 | #include "pica.h" | 11 | #include "pica.h" |
| 13 | 12 | ||
| 14 | namespace Pica { | 13 | namespace Pica { |
| @@ -66,7 +65,7 @@ struct OutputVertex { | |||
| 66 | static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | 65 | static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); |
| 67 | static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); | 66 | static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); |
| 68 | 67 | ||
| 69 | OutputVertex RunShader(const InputVertex& input, int num_attributes); | 68 | OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup); |
| 70 | 69 | ||
| 71 | } // namespace | 70 | } // namespace |
| 72 | 71 | ||
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 3f24df7bd..14b33c9dd 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -4,12 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/emu_window.h" | ||
| 8 | |||
| 9 | #include "renderer_base.h" | ||
| 10 | |||
| 11 | #include <atomic> | 7 | #include <atomic> |
| 12 | 8 | ||
| 9 | class EmuWindow; | ||
| 10 | class RendererBase; | ||
| 11 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 14 | // Video Core namespace | 13 | // Video Core namespace |
| 15 | 14 | ||