diff --git a/.travis.yml b/.travis.yml
index f5077ff7ec..99473a46ba 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,33 +4,70 @@ language: cpp
env:
- PPSSPP_BUILD_TYPE=Linux
+ CMAKE=TRUE
- PPSSPP_BUILD_TYPE=Android
+ - PPSSPP_BUILD_TYPE=Blackberry
+ CMAKE=TRUE
+ - PPSSPP_BUILD_TYPE=Symbian
compiler:
- - clang
- gcc
-before_install:
- - sudo add-apt-repository -y ppa:ubuntu-sdk-team/ppa
- - sudo apt-get update
- - sudo apt-get install cmake libsdl1.2-dev openjdk-7-jdk ant lib32z1-dev lib32stdc++6
- - git submodule update --init --recursive
- - if [ "$PPSSPP_BUILD_TYPE" == "Android" ]; then wget --timeout=30 http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2 -O ndk.tar.bz2 && tar -xf ndk.tar.bz2; fi
- - if [[ "$CXX" == *clang* ]]; then export NDK_TOOLCHAIN_VERSION=clang; fi
- - export ANDROID_HOME=$(pwd)/android-ndk-r9 NDK=$(pwd)/android-ndk-r9
+matrix:
+ include:
+ - compiler: clang
+ env: PPSSPP_BUILD_TYPE=Linux
+ CMAKE=TRUE
-before_script:
- - mkdir build-travis
- - cd build-travis
- - cmake -DHEADLESS=ON ..
- - cd ..
+before_install:
+ - git submodule update --init --recursive
+ - sudo apt-get install aria2 -qq
+ - download_extract() { aria2c -x 16 $1 -o $2 && tar -xf $2; }
+# Travis uses CMake 2.8.7. We require 2.8.8. Grab latest
+ - if [ "$CMAKE" == "TRUE" ]; then
+ sudo apt-get install lib32stdc++6 -qq &&
+ aria2c -x 16 http://www.cmake.org/files/v2.8/cmake-2.8.12.1-Linux-i386.sh &&
+ chmod a+x cmake-2.8.12.1-Linux-i386.sh &&
+ sudo ./cmake-2.8.12.1-Linux-i386.sh --skip-license --prefix=/usr;
+ fi
+
+install:
+# Linux Setup
+ - if [ "$PPSSPP_BUILD_TYPE" == "Linux" ]; then
+ sudo apt-get install libsdl1.2-dev -qq;
+# Android NDK
+ - elif [ "$PPSSPP_BUILD_TYPE" == "Android" ]; then
+ NDK_VER=android-ndk-r9b &&
+ sudo apt-get install ant -qq &&
+ download_extract http://dl.google.com/android/ndk/${NDK_VER}-linux-x86_64.tar.bz2 ${NDK_VER}-linux-x86_64.tar.bz2 &&
+ export ANDROID_HOME=$(pwd)/${NDK_VER} NDK=$(pwd)/${NDK_VER} &&
+ if [[ "$CXX" == *clang* ]]; then export NDK_TOOLCHAIN_VERSION=clang; fi;
+# Blackberry NDK: 10.2.0.1155
+ - elif [ "$PPSSPP_BUILD_TYPE" == "Blackberry" ]; then
+ download_extract https://googledrive.com/host/0B5UBD4wjtpZ-QVdzSElobzNTOU0 libs.tar.gz &&
+ download_extract https://googledrive.com/host/0B5UBD4wjtpZ-NV80UzFYMVRkSXM tools.tar.gz &&
+ export QNX_TARGET="$(pwd)/target_10_2_0_1155/qnx6" QNX_HOST="$(pwd)/host_10_2_0_15/linux/x86" && PATH="$QNX_HOST/usr/bin:$PATH";
+# Symbian NDK: Belle
+ - elif [ "$PPSSPP_BUILD_TYPE" == "Symbian" ]; then
+ sudo apt-get install lib32stdc++6 lib32bz2-1.0 -qq &&
+ download_extract https://googledrive.com/host/0B5UBD4wjtpZ-T0Iwa0F3b2JqREE ndk.tar.bz2 &&
+ sed -i "s!/SDKs!$(pwd)/SDKs!" SDKs/SymbianSR1Qt474/bin/qt.conf &&
+ cp ffmpeg/symbian/armv6/lib/* SDKs/SymbianSR1Qt474/epoc32/release/armv5/urel/ &&
+ export EPOCROOT=$(pwd)/SDKs/SymbianSR1Qt474 SBS_GCCE463BIN=$(pwd)/tools/gcce4/bin &&
+ PATH=$SBS_GCCE463BIN:$(pwd)/tools/sbs/bin:$EPOCROOT/epoc32/tools:$(pwd)/tools:$EPOCROOT/bin:$(pwd)/tools/sbs/linux-x86_64-libc2_15/bin:$PATH;
+ fi
script:
- - if [ "$PPSSPP_BUILD_TYPE" == "Linux" ]; then cd build-travis && make && cd ..; else cd android && ./ab.sh && cd ..; fi
- - if [ "$PPSSPP_BUILD_TYPE" == "Linux" ]; then ./test.py; fi
+# Compile PPSSPP
+ - if [ "$PPSSPP_BUILD_TYPE" == "Linux" ]; then
+ ./b.sh --headless;
+ - elif [ "$PPSSPP_BUILD_TYPE" == "Android" ]; then
+ pushd android && ./ab.sh && popd;
+ - elif [ "$PPSSPP_BUILD_TYPE" == "Blackberry" ]; then
+ ./b.sh --no-package;
+ - elif [ "$PPSSPP_BUILD_TYPE" == "Symbian" ]; then
+ pushd Qt && qmake -spec symbian-sbsv2 PPSSPPQt.pro && make release-gcce -j4 && make sis && popd;
+ fi
-# For now, Android clang seems to be failing to build.
-matrix:
- exclude:
- - compiler: clang
- env: PPSSPP_BUILD_TYPE=Android
+after_success:
+ - if [ "$PPSSPP_BUILD_TYPE" == "Linux" ]; then ./test.py; fi
diff --git a/Blackberry/bar-descriptor.xml b/Blackberry/bar-descriptor.xml
index 64123f1788..7abea9c015 100644
--- a/Blackberry/bar-descriptor.xml
+++ b/Blackberry/bar-descriptor.xml
@@ -3,9 +3,9 @@
com.Qtness.PPSSPP
PPSSPP
PPSSPPBlackberry
- 0.9.5
+ 0.9.6
1
- Playstation portable emulator.
+ Playstation Portable emulator.
Qtness
gYAAgGE4qaHzBnzEAu8JKe4G1OI
diff --git a/Blackberry/bb.toolchain.cmake b/Blackberry/bb.toolchain.cmake
new file mode 100644
index 0000000000..381e3cf544
--- /dev/null
+++ b/Blackberry/bb.toolchain.cmake
@@ -0,0 +1,33 @@
+# Standard settings
+set (CMAKE_SYSTEM_NAME QNX)
+set (CMAKE_SYSTEM_VERSION 1)
+set (CMAKE_PREFIX_PATH $ENV{QNX_TARGET}/usr)
+set (CMAKE_INCLUDE_PATH $ENV{QNX_TARGET}/usr/include)
+if (SIMULATOR)
+ set (CMAKE_SYSTEM_PROCESSOR x86)
+ set (CMAKE_LIBRARY_PATH $ENV{QNX_TARGET}/x86 $ENV{QNX_TARGET}/x86/usr)
+else()
+ set (CMAKE_SYSTEM_PROCESSOR armv7)
+ set (CMAKE_LIBRARY_PATH $ENV{QNX_TARGET}/armle-v7 $ENV{QNX_TARGET}/armle-v7/usr)
+endif()
+set (UNIX True)
+
+set (CMAKE_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_LIBRARY_PATH} CACHE string "Blackberry find search path root")
+set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+include (CMakeForceCompiler)
+CMAKE_FORCE_C_COMPILER (nto${CMAKE_SYSTEM_PROCESSOR}-gcc nto${CMAKE_SYSTEM_PROCESSOR}-gcc)
+CMAKE_FORCE_CXX_COMPILER (nto${CMAKE_SYSTEM_PROCESSOR}-g++ nto${CMAKE_SYSTEM_PROCESSOR}-g++)
+set (CMAKE_COMPILER_IS_GNUCXX True)
+execute_process( COMMAND nto${CMAKE_SYSTEM_PROCESSOR}-gcc --version
+OUTPUT_VARIABLE GCC_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE )
+string( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" GCC_VERSION "${GCC_VERSION}" )
+set (CMAKE_C_COMPILER_VERSION ${GCC_VERSION})
+set (CMAKE_CXX_COMPILER_VERSION ${GCC_VERSION})
+
+# Skip the platform compiler checks for cross compiling
+set (CMAKE_CROSSCOMPILING TRUE)
+set (CMAKE_C_COMPILER_WORKS TRUE)
+set (CMAKE_CXX_COMPILER_WORKS TRUE)
+
diff --git a/Blackberry/build.sh b/Blackberry/build.sh
deleted file mode 100755
index 89d2c98423..0000000000
--- a/Blackberry/build.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-BB_OS=`cat ${QNX_TARGET}/etc/qversion 2>/dev/null`
-if [ -z "$BB_OS" ]; then
- echo "Could not find your Blackberry NDK. Please source bbndk-env.sh"
- exit 1
-fi
-echo "Building for Blackberry ${BB_OS}"
-
-# Set up cmake with GCC 4.6.3 cross-compiler from PATH
-CC=ntoarmv7-gcc CXX=ntoarmv7-g++ cmake -DBLACKBERRY=${BB_OS} ..
-
-# Compile and create unsigned PPSSPP.bar with debugtoken
-DEBUG="-devMode -debugToken ${HOME}/debugtoken.bar"
-make -j4 && blackberry-nativepackager -package PPSSPP.bar bar-descriptor.xml $DEBUG
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e86315f086..b95eef2db0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,13 +10,17 @@ if(ANDROID)
endif()
if(BLACKBERRY)
- set(CMAKE_SYSTEM_NAME "QNX")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS")
endif()
if (IOS OR BLACKBERRY)
- set(ARM ON)
- set(USE_FFMPEG ON)
+ if (SIMULATOR)
+ set(X86 ON)
+ else()
+ set(ARM ON)
+ set(ARMEABI_V7A ON)
+ set(USE_FFMPEG ON)
+ endif()
endif()
if (MAEMO)
@@ -29,7 +33,7 @@ if(LOONGSON)
set(MIPS ON) # MIPS + x86 for now
endif()
-if(ARM)
+if(ARM OR SIMULATOR)
set(USING_GLES2 ON)
else() # Assume x86
set(X86 ON)
@@ -64,26 +68,28 @@ option(IOS "Set to ON if targeting an iOS device" ${IOS})
option(USING_GLES2 "Set to ON if target device uses OpenGL ES 2.0" ${USING_GLES2})
option(USING_QT_UI "Set to ON if you wish to use the Qt frontend wrapper" ${USING_QT_UI})
option(HEADLESS "Set to OFF to not generate the PPSSPPHeadless target" ${HEADLESS})
+option(SIMULATOR "Set to ON when targeting an x86 simulator of an ARM platform" ${SIMULATOR})
option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG})
-if(ANDROID)
- if(NOT ANDROID_ABI)
+if(ANDROID OR BLACKBERRY OR IOS)
+ if (NOT CMAKE_TOOLCHAIN_FILE)
+ if (ANDROID)
+ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/android/android.toolchain.cmake)
+ elseif(BLACKBERRY)
+ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/Blackberry/bb.toolchain.cmake)
+ elseif(IOS)
+ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/ios/ios.toolchain.cmake)
+ endif()
message(FATAL_ERROR "CMAKE_TOOLCHAIN_FILE was not set!\n"
- "Delete the CMakeCache.txt file and CMakeFiles directory."
- "Rerun ${CMAKE_COMMAND} with \"-DCMAKE_TOOLCHAIN_FILE"
- "=${CMAKE_SOURCE_DIR}/android/android.toolchain.cmake\"")
+ "Delete the CMakeCache.txt file and CMakeFiles directory.\n"
+ "Re-run ${CMAKE_COMMAND} with:\n"
+ "\"-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\"")
endif()
+endif()
+
+if(ANDROID)
set(CoreLibName ppsspp_jni)
set(CoreLinkType SHARED)
-elseif(IOS)
- if (NOT IOS_PLATFORM)
- message(FATAL_ERROR "CMAKE_TOOLCHAIN_FILE was not set!\n"
- "Delete the CMakeCache.txt file and CMakeFiles directory."
- "Rerun ${CMAKE_COMMAND} with \"-DCMAKE_TOOLCHAIN_FILE"
- "=${CMAKE_SOURCE_DIR}/ios/ios.toolchain.cmake\"")
- endif()
- set(CoreLibName Core)
- set(CoreLinkType STATIC)
else()
set(CoreLibName Core)
set(CoreLinkType STATIC)
@@ -149,7 +155,7 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -parallel -fopenmp")
endif()
if(NOT APPLE)
- if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel" AND NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_definitions(-Wno-psabi)
endif()
add_definitions(-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -D__BSD_VISIBLE=1)
@@ -160,7 +166,10 @@ if(NOT MSVC)
endif()
if(BLACKBERRY)
- add_definitions(-D_QNX_SOURCE -DARMV7 -O3 -mfpu=neon -mtune=cortex-a9)
+ add_definitions(-D_QNX_SOURCE)
+ if(ARM)
+ add_definitions(-DARMV7 -O3 -mfpu=neon -mcpu=cortex-a9)
+ endif()
endif()
if(X86 AND NOT MIPS)
@@ -259,8 +268,6 @@ add_library(Common STATIC
Common/KeyMap.h
Common/LogManager.cpp
Common/LogManager.h
- Common/MathUtil.cpp
- Common/MathUtil.h
Common/MemArena.cpp
Common/MemArena.h
Common/MemoryUtil.cpp
@@ -270,8 +277,6 @@ add_library(Common STATIC
Common/MsgHandler.h
Common/StringUtils.cpp
Common/StringUtils.h
- Common/Thread.cpp
- Common/Thread.h
Common/ThreadPools.cpp
Common/ThreadPools.h
Common/Timer.cpp
@@ -283,8 +288,175 @@ if(WIN32)
target_link_libraries(Common winmm)
endif()
-if(BLACKBERRY)
- set(LIBZIP z)
+if(NOT USING_GLES2)
+ include_directories(${OPENGL_INCLUDE_DIR})
+
+ add_definitions(-DGLEW_STATIC)
+ add_library(glew STATIC
+ native/ext/glew/GL/glew.h
+ native/ext/glew/GL/glxew.h
+ native/ext/glew/GL/wglew.h
+ native/ext/glew/glew.c)
+ target_link_libraries(glew ${OPENGL_LIBRARIES})
+ include_directories(native/ext/glew)
+ set(GLEW_LIBRARIES glew)
+endif()
+
+add_library(snappy STATIC
+ ext/snappy/snappy-c.cpp
+ ext/snappy/snappy-internal.h
+ ext/snappy/snappy-sinksource.h
+ ext/snappy/snappy-stubs-internal.h
+ ext/snappy/snappy-stubs-public.h
+ ext/snappy/snappy.cpp
+ ext/snappy/snappy.h
+)
+include_directories(ext/snappy)
+
+add_library(vjson STATIC
+ native/ext/vjson/json.cpp
+ native/ext/vjson/json.h
+ native/ext/vjson/block_allocator.cpp
+ native/ext/vjson/block_allocator.h
+)
+
+add_library(rg_etc1 STATIC
+ native/ext/rg_etc1/rg_etc1.cpp
+ native/ext/rg_etc1/rg_etc1.h)
+include_directories(native/ext/rg_etc1)
+
+add_library(stb_vorbis STATIC
+ native/ext/stb_vorbis/stb_vorbis.c
+ native/ext/stb_vorbis/stb_vorbis.h)
+include_directories(native/ext/stb_vorbis)
+
+if(USE_FFMPEG AND NOT DEFINED FFMPEG_BUILDDIR)
+ if(BLACKBERRY)
+ set(PLATFORM_ARCH "blackberry/armv7")
+ elseif(IOS)
+ set(PLATFORM_ARCH "ios/universal")
+ elseif(MACOSX)
+ set(PLATFORM_ARCH "macosx/x86_64")
+ elseif(LINUX)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(PLATFORM_ARCH "linux/x86_64")
+ else()
+ set(PLATFORM_ARCH "linux/x86")
+ endif()
+ endif()
+ # Using static libraries
+ if (DEFINED PLATFORM_ARCH)
+ include_directories(ffmpeg/${PLATFORM_ARCH}/include)
+ link_directories(ffmpeg/${PLATFORM_ARCH}/lib)
+ set(FFMPEG_LIBRARIES libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a)
+ else()
+ # Manual definition of system library locations by the user.
+ if (DEFINED FFMPEG_INCLUDE_PATH)
+ include_directories(ffmpeg ${FFMPEG_INCLUDE_PATH})
+ endif()
+ if (DEFINED AVFORMAT_PATH)
+ add_library(libavformat STATIC IMPORTED)
+ set_target_properties(libavformat PROPERTIES IMPORTED_LOCATION ${AVFORMAT_PATH})
+ SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libavformat)
+ endif()
+ if (DEFINED AVCODEC_PATH)
+ add_library(libavcodec STATIC IMPORTED)
+ set_target_properties(libavcodec PROPERTIES IMPORTED_LOCATION ${AVCODEC_PATH})
+ SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libavcodec)
+ endif()
+ if (DEFINED AVUTIL_PATH)
+ add_library(libavutil STATIC IMPORTED)
+ set_target_properties(libavutil PROPERTIES IMPORTED_LOCATION ${AVUTIL_PATH})
+ SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libavutil)
+ endif()
+ if (DEFINED SWRESAMPLE_PATH)
+ add_library(libswresample STATIC IMPORTED)
+ set_target_properties(libswresample PROPERTIES IMPORTED_LOCATION ${SWRESAMPLE_PATH})
+ SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libswresample)
+ endif()
+ if (DEFINED SWSCALE_PATH)
+ add_library(libswscale STATIC IMPORTED)
+ set_target_properties(libswscale PROPERTIES IMPORTED_LOCATION ${SWSCALE_PATH})
+ SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libswscale)
+ endif()
+ endif(DEFINED PLATFORM_ARCH)
+endif(USE_FFMPEG AND NOT DEFINED FFMPEG_BUILDDIR)
+
+if(USE_FFMPEG)
+ # Using shared libraries
+ if(DEFINED FFMPEG_BUILDDIR)
+ include_directories(ffmpeg ${FFMPEG_BUILDDIR})
+
+ add_library(libavformat STATIC IMPORTED)
+ set_target_properties(libavformat PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavformat/libavformat.a)
+ add_library(libavcodec STATIC IMPORTED)
+ set_target_properties(libavcodec PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavcodec/libavcodec.a)
+ add_library(libavutil STATIC IMPORTED)
+ set_target_properties(libavutil PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavutil/libavutil.a)
+ add_library(libswresample STATIC IMPORTED)
+ set_target_properties(libswresample PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libswresample/libswresample.a)
+ add_library(libswscale STATIC IMPORTED)
+ set_target_properties(libswscale PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libswscale/libswscale.a)
+
+ SET (FFMPEG_LIBRARIES
+ libavformat
+ libavcodec
+ libavutil
+ libswresample
+ libswscale
+ )
+ endif()
+
+ if(IOS OR BLACKBERRY)
+ set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} iconv)
+ endif()
+
+ if(APPLE)
+ set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} bz2 "-framework CoreVideo")
+ if (NOT IOS)
+ set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} "-framework VideoDecodeAcceleration")
+ endif()
+ endif(APPLE)
+
+ set(LinkCommon ${LinkCommon} ${FFMPEG_LIBRARIES})
+ add_definitions(-DUSE_FFMPEG)
+endif(USE_FFMPEG)
+
+# Modification to show where we are pulling the ffmpeg libraries from.
+if(USE_FFMPEG AND DEFINED FFMPEG_LIBRARIES)
+ target_link_libraries(Common ${FFMPEG_LIBRARIES})
+ message(STATUS "FFMPEG library locations:")
+ if(DEFINED PLATFORM_ARCH)
+ set(TEMP ${CMAKE_SOURCE_DIR}/ffmpeg/${PLATFORM_ARCH}/lib)
+ message(STATUS "libavcodec location: ${TEMP}/libavcodec.a")
+ message(STATUS "libavformat location: ${TEMP}/libavformat.a")
+ message(STATUS "libavutil location: ${TEMP}/libavutil.a")
+ message(STATUS "libswresample location: ${TEMP}/libswresample.a")
+ message(STATUS "libswscale location: ${TEMP}/libswscale.a")
+ else()
+ get_target_property(TEMP libavcodec IMPORTED_LOCATION)
+ message(STATUS "libavcodec location: ${TEMP}")
+ get_target_property(TEMP libavformat IMPORTED_LOCATION)
+ message(STATUS "libavformat location: ${TEMP}")
+ get_target_property(TEMP libavutil IMPORTED_LOCATION)
+ message(STATUS "libavutil location: ${TEMP}")
+ get_target_property(TEMP libswresample IMPORTED_LOCATION)
+ message(STATUS "libswresample location: ${TEMP}")
+ get_target_property(TEMP libswscale IMPORTED_LOCATION)
+ message(STATUS "libswscale location: ${TEMP}")
+ endif(DEFINED PLATFORM_ARCH)
+else()
+ message(STATUS "ERROR: No FFMPEG library locations")
+endif()
+
+if(USE_FFMPEG AND NOT DEFINED FFMPEG_LIBRARIES)
+ message(WARNING "FFMPEG_BUILDDIR variable or manual path definition is required to enable FFmpeg. Disabling it.")
+ unset(USE_FFMPEG)
+endif()
+
+find_package(ZLIB)
+if(ZLIB_FOUND)
+ include_directories(${ZLIB_INCLUDE_DIR})
else()
add_library(zlib STATIC
ext/zlib/adler32.c
@@ -316,111 +488,113 @@ else()
ext/zlib/zutil.h
)
include_directories(ext/zlib)
- set(LIBZIP zlib)
+ set(ZLIB_LIBRARY zlib)
endif()
-add_library(snappy STATIC
- ext/snappy/snappy-c.cpp
- ext/snappy/snappy-internal.h
- ext/snappy/snappy-sinksource.h
- ext/snappy/snappy-stubs-internal.h
- ext/snappy/snappy-stubs-public.h
- ext/snappy/snappy.cpp
- ext/snappy/snappy.h
+add_library(cityhash STATIC
+ native/ext/cityhash/city.cpp
+ native/ext/cityhash/city.h
+ native/ext/cityhash/citycrc.h
)
-include_directories(ext/snappy)
+include_directories(ext/cityhash)
-add_library(rg_etc1 STATIC
- native/ext/rg_etc1/rg_etc1.cpp
- native/ext/rg_etc1/rg_etc1.h)
-include_directories(native/ext/rg_etc1)
+add_library(libzip STATIC
+ native/ext/libzip/zip.h
+ native/ext/libzip/mkstemp.c
+ native/ext/libzip/zip_add.c
+ native/ext/libzip/zip_add_dir.c
+ native/ext/libzip/zip_close.c
+ native/ext/libzip/zip_delete.c
+ native/ext/libzip/zip_dirent.c
+ native/ext/libzip/zip_entry_free.c
+ native/ext/libzip/zip_entry_new.c
+ native/ext/libzip/zip_err_str.c
+ native/ext/libzip/zip_error.c
+ native/ext/libzip/zip_error_clear.c
+ native/ext/libzip/zip_error_get.c
+ native/ext/libzip/zip_error_get_sys_type.c
+ native/ext/libzip/zip_error_strerror.c
+ native/ext/libzip/zip_error_to_str.c
+ native/ext/libzip/zip_fclose.c
+ native/ext/libzip/zip_file_error_clear.c
+ native/ext/libzip/zip_file_error_get.c
+ native/ext/libzip/zip_file_get_offset.c
+ native/ext/libzip/zip_file_strerror.c
+ native/ext/libzip/zip_filerange_crc.c
+ native/ext/libzip/zip_fopen.c
+ native/ext/libzip/zip_fopen_index.c
+ native/ext/libzip/zip_fread.c
+ native/ext/libzip/zip_free.c
+ native/ext/libzip/zip_get_archive_comment.c
+ native/ext/libzip/zip_get_archive_flag.c
+ native/ext/libzip/zip_get_file_comment.c
+ native/ext/libzip/zip_get_name.c
+ native/ext/libzip/zip_get_num_files.c
+ native/ext/libzip/zip_memdup.c
+ native/ext/libzip/zip_name_locate.c
+ native/ext/libzip/zip_new.c
+ native/ext/libzip/zip_open.c
+ native/ext/libzip/zip_rename.c
+ native/ext/libzip/zip_replace.c
+ native/ext/libzip/zip_set_archive_comment.c
+ native/ext/libzip/zip_set_archive_flag.c
+ native/ext/libzip/zip_set_file_comment.c
+ native/ext/libzip/zip_set_name.c
+ native/ext/libzip/zip_source_buffer.c
+ native/ext/libzip/zip_source_file.c
+ native/ext/libzip/zip_source_filep.c
+ native/ext/libzip/zip_source_free.c
+ native/ext/libzip/zip_source_function.c
+ native/ext/libzip/zip_source_zip.c
+ native/ext/libzip/zip_stat.c
+ native/ext/libzip/zip_stat_index.c
+ native/ext/libzip/zip_stat_init.c
+ native/ext/libzip/zip_strerror.c
+ native/ext/libzip/zip_unchange.c
+ native/ext/libzip/zip_unchange_all.c
+ native/ext/libzip/zip_unchange_archive.c
+ native/ext/libzip/zip_unchange_data.c)
+target_link_libraries(libzip ${ZLIB_LIBRARY})
+include_directories(native/ext/libzip)
+set(LIBZIP_LIBRARY libzip)
-if(NOT USING_GLES2)
- include_directories(${OPENGL_INCLUDE_DIR})
-
- add_definitions(-DGLEW_STATIC)
- add_library(glew STATIC
- native/ext/glew/GL/glew.h
- native/ext/glew/GL/glxew.h
- native/ext/glew/GL/wglew.h
- native/ext/glew/glew.c)
- target_link_libraries(glew ${OPENGL_LIBRARIES})
- include_directories(native/ext/glew)
- set(GLEW_LIBRARIES glew)
+# FindPNG does a few things we don't want. So do it ourselves.
+# Fixed to libpng16, otherwise it can pick up earlier even if newer exists.
+find_path(PNG_PNG_INCLUDE_DIR NAMES "libpng16/png.h")
+find_library(PNG_LIBRARY NAMES png16 libpng16 )
+find_package(PackageHandleStandardArgs)
+find_package_handle_standard_args(PNG REQUIRED_VARS PNG_LIBRARY PNG_PNG_INCLUDE_DIR)
+if (PNG_FOUND)
+ include_directories(${PNG_PNG_INCLUDE_DIR})
+else()
+ add_library(png16 STATIC
+ native/ext/libpng16/pngconf.h
+ native/ext/libpng16/pngdebug.h
+ native/ext/libpng16/png.c
+ native/ext/libpng16/png.h
+ native/ext/libpng16/pngerror.c
+ native/ext/libpng16/pngget.c
+ native/ext/libpng16/pnginfo.h
+ native/ext/libpng16/pnglibconf.h
+ native/ext/libpng16/pngmem.c
+ native/ext/libpng16/pngpread.c
+ native/ext/libpng16/pngpriv.h
+ native/ext/libpng16/pngread.c
+ native/ext/libpng16/pngrio.c
+ native/ext/libpng16/pngrtran.c
+ native/ext/libpng16/pngrutil.c
+ native/ext/libpng16/pngset.c
+ native/ext/libpng16/pngstruct.h
+ native/ext/libpng16/pngtest.c
+ native/ext/libpng16/pngtrans.c
+ native/ext/libpng16/pngwio.c
+ native/ext/libpng16/pngwrite.c
+ native/ext/libpng16/pngwtran.c
+ native/ext/libpng16/pngwutil.c)
+ set(PNG_LIBRARY png16)
+ include_directories(native/ext)
endif()
-
-add_library(stb_image STATIC
- native/ext/stb_image/stb_image.c
- native/ext/stb_image/stb_image.h)
-include_directories(native/ext/stb_image)
-
-add_library(stb_vorbis STATIC
- native/ext/stb_vorbis/stb_vorbis.c
- native/ext/stb_vorbis/stb_vorbis.h)
-include_directories(native/ext/stb_vorbis)
-
-if(ANDROID)
- add_library(libzip STATIC
- native/ext/libzip/zip.h
- native/ext/libzip/mkstemp.c
- native/ext/libzip/zip_add.c
- native/ext/libzip/zip_add_dir.c
- native/ext/libzip/zip_close.c
- native/ext/libzip/zip_delete.c
- native/ext/libzip/zip_dirent.c
- native/ext/libzip/zip_entry_free.c
- native/ext/libzip/zip_entry_new.c
- native/ext/libzip/zip_err_str.c
- native/ext/libzip/zip_error.c
- native/ext/libzip/zip_error_clear.c
- native/ext/libzip/zip_error_get.c
- native/ext/libzip/zip_error_get_sys_type.c
- native/ext/libzip/zip_error_strerror.c
- native/ext/libzip/zip_error_to_str.c
- native/ext/libzip/zip_fclose.c
- native/ext/libzip/zip_file_error_clear.c
- native/ext/libzip/zip_file_error_get.c
- native/ext/libzip/zip_file_get_offset.c
- native/ext/libzip/zip_file_strerror.c
- native/ext/libzip/zip_filerange_crc.c
- native/ext/libzip/zip_fopen.c
- native/ext/libzip/zip_fopen_index.c
- native/ext/libzip/zip_fread.c
- native/ext/libzip/zip_free.c
- native/ext/libzip/zip_get_archive_comment.c
- native/ext/libzip/zip_get_archive_flag.c
- native/ext/libzip/zip_get_file_comment.c
- native/ext/libzip/zip_get_name.c
- native/ext/libzip/zip_get_num_files.c
- native/ext/libzip/zip_memdup.c
- native/ext/libzip/zip_name_locate.c
- native/ext/libzip/zip_new.c
- native/ext/libzip/zip_open.c
- native/ext/libzip/zip_rename.c
- native/ext/libzip/zip_replace.c
- native/ext/libzip/zip_set_archive_comment.c
- native/ext/libzip/zip_set_archive_flag.c
- native/ext/libzip/zip_set_file_comment.c
- native/ext/libzip/zip_set_name.c
- native/ext/libzip/zip_source_buffer.c
- native/ext/libzip/zip_source_file.c
- native/ext/libzip/zip_source_filep.c
- native/ext/libzip/zip_source_free.c
- native/ext/libzip/zip_source_function.c
- native/ext/libzip/zip_source_zip.c
- native/ext/libzip/zip_stat.c
- native/ext/libzip/zip_stat_index.c
- native/ext/libzip/zip_stat_init.c
- native/ext/libzip/zip_strerror.c
- native/ext/libzip/zip_unchange.c
- native/ext/libzip/zip_unchange_all.c
- native/ext/libzip/zip_unchange_archive.c
- native/ext/libzip/zip_unchange_data.c)
- target_link_libraries(libzip zlib)
- include_directories(native/ext/libzip)
- set(LIBZIP libzip zlib)
-endif()
-
+
set(nativeExtra)
set(nativeExtraLibs)
if(ANDROID)
@@ -468,7 +642,10 @@ elseif(SDL_FOUND)
set(TargetBin PPSSPPSDL)
# Require SDL
include_directories(${SDL_INCLUDE_DIR})
- set(nativeExtra ${nativeExtra} native/base/PCMain.cpp)
+ set(nativeExtra ${nativeExtra}
+ SDL/SDLJoystick.h
+ SDL/SDLJoystick.cpp
+ native/base/PCMain.cpp)
set(nativeExtraLibs ${nativeExtraLibs} ${SDL_LIBRARY})
if(APPLE)
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
@@ -517,6 +694,10 @@ add_library(native STATIC
native/base/timeutil.h
native/data/compression.cpp
native/data/compression.h
+ native/ext/vjson/json.cpp
+ native/ext/vjson/json.h
+ native/ext/vjson/block_allocator.cpp
+ native/ext/vjson/block_allocator.h
native/file/chunk_file.cpp
native/file/chunk_file.h
native/file/dialog.cpp
@@ -529,6 +710,8 @@ add_library(native STATIC
native/file/file_util.h
native/file/ini_file.cpp
native/file/ini_file.h
+ native/file/path.cpp
+ native/file/path.h
native/file/vfs.h
native/file/zip_read.cpp
native/file/zip_read.h
@@ -630,13 +813,15 @@ add_library(native STATIC
native/util/random/rng.h
native/util/text/utf8.h
native/util/text/utf8.cpp
+ native/util/text/parsers.h
+ native/util/text/parsers.cpp
native/util/const_map.h
native/ext/jpge/jpgd.cpp
native/ext/jpge/jpgd.h
native/ext/jpge/jpge.cpp
native/ext/jpge/jpge.h)
include_directories(native)
-target_link_libraries(native ${LIBZIP} rg_etc1 stb_image stb_vorbis snappy ${GLEW_LIBRARIES})
+target_link_libraries(native ${LIBZIP_LIBRARY} ${PNG_LIBRARY} rg_etc1 vjson stb_vorbis snappy ${GLEW_LIBRARIES})
if(ANDROID)
target_link_libraries(native log)
@@ -681,12 +866,15 @@ if(ARM)
Core/MIPS/ARM/ArmCompFPU.cpp
Core/MIPS/ARM/ArmCompLoadStore.cpp
Core/MIPS/ARM/ArmCompVFPU.cpp
+ Core/MIPS/ARM/ArmCompVFPUNEON.cpp
Core/MIPS/ARM/ArmJit.cpp
Core/MIPS/ARM/ArmJit.h
Core/MIPS/ARM/ArmRegCache.cpp
Core/MIPS/ARM/ArmRegCache.h
Core/MIPS/ARM/ArmRegCacheFPU.cpp
Core/MIPS/ARM/ArmRegCacheFPU.h
+ GPU/GLES/VertexDecoderArm.cpp
+ GPU/GLES/VertexDecoder.h
ext/disarm.cpp)
elseif(X86)
set(CoreExtra ${CoreExtra}
@@ -703,6 +891,8 @@ elseif(X86)
Core/MIPS/x86/RegCache.h
Core/MIPS/x86/RegCacheFPU.cpp
Core/MIPS/x86/RegCacheFPU.h
+ GPU/GLES/VertexDecoderX86.cpp
+ GPU/GLES/VertexDecoder.h
ext/disarm.cpp)
endif()
@@ -849,6 +1039,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceNet.h
Core/HLE/sceNetAdhoc.cpp
Core/HLE/sceNetAdhoc.h
+ Core/HLE/proAdhoc.h
+ Core/HLE/proAdhoc.cpp
Core/HLE/sceOpenPSID.cpp
Core/HLE/sceOpenPSID.h
Core/HLE/sceP3da.cpp
@@ -946,6 +1138,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/SaveState.h
Core/System.cpp
Core/System.h
+ Core/Util/GameManager.cpp
+ Core/Util/GameManager.h
Core/Util/BlockAllocator.cpp
Core/Util/BlockAllocator.h
Core/Util/PPGeDraw.cpp
@@ -955,7 +1149,7 @@ add_library(${CoreLibName} ${CoreLinkType}
$
Globals.h
git-version.cpp)
-target_link_libraries(${CoreLibName} Common native kirk xbrz xxhash
+target_link_libraries(${CoreLibName} Common native kirk cityhash xbrz xxhash
${CoreExtraLibs} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
setup_target_project(${CoreLibName} Core)
@@ -970,7 +1164,7 @@ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/git-version.cpp
PROPERTIES GENERATED TRUE)
add_dependencies(${CoreLibName} GitVersion)
-if(BLACKBERRY OR IOS OR ARMEABI_V7A)
+if(ARMEABI_V7A)
set(GPU_NEON GPU/Common/TextureDecoderNEON.cpp)
endif()
add_library(GPU OBJECT
@@ -1006,6 +1200,7 @@ add_library(GPU OBJECT
GPU/GLES/TextureScaler.h
GPU/GLES/TransformPipeline.cpp
GPU/GLES/TransformPipeline.h
+ GPU/GLES/SoftwareTransform.cpp
GPU/GLES/VertexDecoder.cpp
GPU/GLES/VertexDecoder.h
GPU/GLES/VertexShaderGenerator.cpp
@@ -1126,7 +1321,9 @@ set(NativeAppSource
UI/UIShader.cpp
UI/OnScreenDisplay.cpp
UI/ControlMappingScreen.cpp
+ UI/Store.cpp
UI/CwCheatScreen.cpp
+ UI/InstallZipScreen.cpp
UI/ui_atlas.cpp)
if(ANDROID AND ARM)
set(NativeAppSource ${NativeAppSource} android/jni/ArmEmitterTest.cpp)
@@ -1135,129 +1332,10 @@ set(NativeAssets
android/assets/ui_atlas.zim
assets/shaders
assets/ppge_atlas.zim
- assets/langregion.ini)
+ assets/langregion.ini
+ assets/unknown.png)
set(LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT} ${nativeExtraLibs})
-if(USE_FFMPEG AND NOT DEFINED FFMPEG_BUILDDIR)
- if(BLACKBERRY)
- set(PLATFORM_ARCH "blackberry/armv7")
- elseif(IOS)
- set(PLATFORM_ARCH "ios/universal")
- elseif(MACOSX)
- set(PLATFORM_ARCH "macosx/x86_64")
- elseif(LINUX)
- if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(PLATFORM_ARCH "linux/x86_64")
- else()
- set(PLATFORM_ARCH "linux/x86")
- endif()
- endif()
- # Using static libraries
- if (DEFINED PLATFORM_ARCH)
- include_directories(ffmpeg/${PLATFORM_ARCH}/include)
- link_directories(ffmpeg/${PLATFORM_ARCH}/lib)
- set(FFMPEG_LIBRARIES libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a)
- else()
- # Manual definition of system library locations by the user.
- if (DEFINED FFMPEG_INCLUDE_PATH)
- include_directories(ffmpeg ${FFMPEG_INCLUDE_PATH})
- endif()
- if (DEFINED AVFORMAT_PATH)
- add_library(libavformat STATIC IMPORTED)
- set_target_properties(libavformat PROPERTIES IMPORTED_LOCATION ${AVFORMAT_PATH})
- SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libavformat)
- endif()
- if (DEFINED AVCODEC_PATH)
- add_library(libavcodec STATIC IMPORTED)
- set_target_properties(libavcodec PROPERTIES IMPORTED_LOCATION ${AVCODEC_PATH})
- SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libavcodec)
- endif()
- if (DEFINED AVUTIL_PATH)
- add_library(libavutil STATIC IMPORTED)
- set_target_properties(libavutil PROPERTIES IMPORTED_LOCATION ${AVUTIL_PATH})
- SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libavutil)
- endif()
- if (DEFINED SWRESAMPLE_PATH)
- add_library(libswresample STATIC IMPORTED)
- set_target_properties(libswresample PROPERTIES IMPORTED_LOCATION ${SWRESAMPLE_PATH})
- SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libswresample)
- endif()
- if (DEFINED SWSCALE_PATH)
- add_library(libswscale STATIC IMPORTED)
- set_target_properties(libswscale PROPERTIES IMPORTED_LOCATION ${SWSCALE_PATH})
- SET (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} libswscale)
- endif()
- endif(DEFINED PLATFORM_ARCH)
-endif(USE_FFMPEG AND NOT DEFINED FFMPEG_BUILDDIR)
-
-if(USE_FFMPEG)
- # Using shared libraries
- if(DEFINED FFMPEG_BUILDDIR)
- include_directories(ffmpeg ${FFMPEG_BUILDDIR})
-
- add_library(libavformat STATIC IMPORTED)
- set_target_properties(libavformat PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavformat/libavformat.a)
- add_library(libavcodec STATIC IMPORTED)
- set_target_properties(libavcodec PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavcodec/libavcodec.a)
- add_library(libavutil STATIC IMPORTED)
- set_target_properties(libavutil PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavutil/libavutil.a)
- add_library(libswresample STATIC IMPORTED)
- set_target_properties(libswresample PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libswresample/libswresample.a)
- add_library(libswscale STATIC IMPORTED)
- set_target_properties(libswscale PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libswscale/libswscale.a)
-
- SET (FFMPEG_LIBRARIES
- libavformat
- libavcodec
- libavutil
- libswresample
- libswscale
- )
- endif()
-
- if(IOS OR BLACKBERRY)
- set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} iconv)
- endif()
-
- if(APPLE)
- set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} bz2 "-framework CoreVideo")
- if (NOT IOS)
- set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} "-framework VideoDecodeAcceleration")
- endif()
- endif(APPLE)
-
- set(LinkCommon ${LinkCommon} ${FFMPEG_LIBRARIES})
- add_definitions(-DUSE_FFMPEG)
-endif(USE_FFMPEG)
-
-# Modification to show where we are pulling the ffmpeg libraries from.
-if(USE_FFMPEG AND DEFINED FFMPEG_LIBRARIES)
- target_link_libraries(Common ${FFMPEG_LIBRARIES})
- message(STATUS "FFMPEG library locations:")
- if(DEFINED PLATFORM_ARCH)
- set(TEMP ${CMAKE_SOURCE_DIR}/ffmpeg/${PLATFORM_ARCH}/lib)
- message(STATUS "libavcodec location: ${TEMP}/libavcodec.a")
- message(STATUS "libavformat location: ${TEMP}/libavformat.a")
- message(STATUS "libavutil location: ${TEMP}/libavutil.a")
- message(STATUS "libswresample location: ${TEMP}/libswresample.a")
- message(STATUS "libswscale location: ${TEMP}/libswscale.a")
- else()
- get_target_property(TEMP libavcodec IMPORTED_LOCATION)
- message(STATUS "libavcodec location: ${TEMP}")
- get_target_property(TEMP libavformat IMPORTED_LOCATION)
- message(STATUS "libavformat location: ${TEMP}")
- get_target_property(TEMP libavutil IMPORTED_LOCATION)
- message(STATUS "libavutil location: ${TEMP}")
- get_target_property(TEMP libswresample IMPORTED_LOCATION)
- message(STATUS "libswresample location: ${TEMP}")
- get_target_property(TEMP libswscale IMPORTED_LOCATION)
- message(STATUS "libswscale location: ${TEMP}")
- endif(DEFINED PLATFORM_ARCH)
-endif()
-if(USE_FFMPEG AND NOT DEFINED FFMPEG_LIBRARIES)
- message(WARNING "FFMPEG_BUILDDIR variable or manual path definition is required to enable FFmpeg. Disabling it.")
- unset(USE_FFMPEG)
-endif()
if(HEADLESS)
add_executable(PPSSPPHeadless
@@ -1282,7 +1360,7 @@ endif()
# installs
file(INSTALL ${NativeAssets} DESTINATION assets)
-file(INSTALL flash0 lang DESTINATION .)
+file(INSTALL flash0 lang DESTINATION assets)
# Fix CMake some Xcode settings.
if(APPLE)
@@ -1297,8 +1375,11 @@ if(APPLE)
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -D_NDEBUG")
# These can be fast even for debug.
+ set_target_properties(cityhash PROPERTIES COMPILE_FLAGS "-O3")
set_target_properties(snappy PROPERTIES COMPILE_FLAGS "-O3")
- set_target_properties(zlib PROPERTIES COMPILE_FLAGS "-O3")
+ if(NOT ZLIB_FOUND)
+ set_target_properties(zlib PROPERTIES COMPILE_FLAGS "-O3")
+ endif()
endif()
if(APPLE AND NOT IOS)
@@ -1311,10 +1392,6 @@ if(IOS)
file(GLOB IOSAssets ios/assets/*.png)
file(INSTALL ${IOSAssets} DESTINATION assets)
- file(INSTALL assets/langregion.ini DESTINATION assets)
- file(INSTALL assets/shaders DESTINATION assets)
- file(INSTALL flash0 DESTINATION assets)
- file(INSTALL lang DESTINATION assets)
if (IOS_DEBUG)
file(INSTALL pspautotests DESTINATION assets)
endif()
diff --git a/Common/ArmCPUDetect.cpp b/Common/ArmCPUDetect.cpp
index 90f8cbac0f..e7cc4308fe 100644
--- a/Common/ArmCPUDetect.cpp
+++ b/Common/ArmCPUDetect.cpp
@@ -24,7 +24,7 @@
#endif
// Only Linux platforms have /proc/cpuinfo
-#if !defined(BLACKBERRY) && !defined(IOS) && !defined(__SYMBIAN32__)
+#if defined(__linux__)
const char procfile[] = "/proc/cpuinfo";
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
const char syscpupresentfile[] = "/sys/devices/system/cpu/present";
@@ -200,7 +200,7 @@ void CPUInfo::Detect()
vendor = VENDOR_ARM;
// Get the information about the CPU
-#if defined(__SYMBIAN32__) || defined(BLACKBERRY) || defined(IOS)
+#if !defined(__linux__)
bool isVFP3 = false;
bool isVFP4 = false;
#ifdef IOS
@@ -209,7 +209,7 @@ void CPUInfo::Detect()
#ifdef __ARM_ARCH_7S__
isVFP4 = true;
#endif
- strcpy(brand_string, "Apple");
+ strcpy(brand_string, "Apple A");
num_cores = 2;
#elif defined(BLACKBERRY)
isVFP3 = true;
@@ -220,10 +220,14 @@ void CPUInfo::Detect()
if (!strncmp(brand_string, "MSM", 3))
isVFP4 = true;
deviceinfo_free_details(&details);
-#elif defined(SYMBIAN)
+#elif defined(__SYMBIAN32__)
strcpy(brand_string, "Samsung ARMv6");
num_cores = 1;
+#else
+ strcpy(brand_string, "Unknown");
+ num_cores = 1;
#endif
+ strncpy(cpu_string, brand_string, sizeof(cpu_string));
// Hardcode this for now
bSwp = true;
bHalf = true;
@@ -240,7 +244,7 @@ void CPUInfo::Detect()
bIDIVt = isVFP4;
bFP = false;
bASIMD = false;
-#else
+#else // __linux__
strncpy(cpu_string, GetCPUString(), sizeof(cpu_string));
bSwp = CheckCPUFeature("swp");
bHalf = CheckCPUFeature("half");
@@ -255,46 +259,36 @@ void CPUInfo::Detect()
bVFPv4 = CheckCPUFeature("vfpv4");
bIDIVa = CheckCPUFeature("idiva");
bIDIVt = CheckCPUFeature("idivt");
- // Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait.
- if (GetCPUImplementer() == 0x51 && GetCPUPart() == 0x6F) // Krait(300) is 0x6F, Scorpion is 0x4D
+ // Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait (0x4D = Plus, 0x6F = Pro).
+ unsigned short CPUPart = GetCPUPart();
+ if (GetCPUImplementer() == 0x51 && (CPUPart == 0x4D || CPUPart == 0x6F))
bIDIVa = bIDIVt = true;
// These two require ARMv8 or higher
bFP = CheckCPUFeature("fp");
bASIMD = CheckCPUFeature("asimd");
num_cores = GetCoreCount();
#endif
-// On android, we build a separate library for ARMv7 so this is fine.
-// TODO: Check for ARMv7 on other platforms.
-#if defined(__ARM_ARCH_7A__)
- bArmV7 = true;
-#else
- bArmV7 = false;
-#endif
}
// Turn the cpu info into a string we can show
std::string CPUInfo::Summarize()
{
std::string sum;
-#if defined(BLACKBERRY) || defined(IOS) || defined(__SYMBIAN32__)
- sum = StringFromFormat("%i cores", num_cores);
-#else
if (num_cores == 1)
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
else
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
-#endif
if (bSwp) sum += ", SWP";
if (bHalf) sum += ", Half";
if (bThumb) sum += ", Thumb";
if (bFastMult) sum += ", FastMult";
- if (bVFP) sum += ", VFP";
if (bEDSP) sum += ", EDSP";
if (bThumbEE) sum += ", ThumbEE";
- if (bNEON) sum += ", NEON";
- if (bVFPv3) sum += ", VFPv3";
if (bTLS) sum += ", TLS";
+ if (bVFP) sum += ", VFP";
+ if (bVFPv3) sum += ", VFPv3";
if (bVFPv4) sum += ", VFPv4";
+ if (bNEON) sum += ", NEON";
if (bIDIVa) sum += ", IDIVa";
if (bIDIVt) sum += ", IDIVt";
diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp
index 9ea055887c..fc322b273c 100644
--- a/Common/ArmEmitter.cpp
+++ b/Common/ArmEmitter.cpp
@@ -18,6 +18,8 @@
#include "ArmEmitter.h"
#include "CPUDetect.h"
+#include "base/logging.h"
+
#include
#include
#include
@@ -36,6 +38,12 @@
#include
#endif
+// __FUNCTION__ is misused a lot below, it's no longer a string literal but a virtual
+// variable so this use fails in some compilers. Just define it away for now.
+#ifndef _MSC_VER
+#define __FUNCTION__ "(n/a)"
+#endif
+
namespace ArmGen
{
@@ -87,6 +95,10 @@ Operand2 AssumeMakeOperand2(u32 imm) {
Operand2 op2;
bool result = TryMakeOperand2(imm, op2);
_dbg_assert_msg_(JIT, result, "Could not make assumed Operand2.");
+ if (!result) {
+ // Make double sure that we get it logged.
+ ERROR_LOG(JIT, "Could not make assumed Operand2.");
+ }
return op2;
}
@@ -148,6 +160,11 @@ void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate)
void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
{
+ if (val == 0) {
+ if (rd != rs)
+ MOV(rd, rs);
+ return;
+ }
Operand2 op2;
bool negated;
if (TryMakeOperand2_AllowNegation(val, op2, &negated)) {
@@ -162,8 +179,8 @@ void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
// Decompose into two additions.
ADD(rd, rs, Operand2((u8)(val >> 8), 12)); // rotation right by 12*2 == rotation left by 8
ADD(rd, rd, Operand2((u8)(val), 0));
- } else if (((-(u32)(s32)val) & 0xFFFF0000) == 0) {
- val = -(u32)(s32)val;
+ } else if ((((u32)-(s32)val) & 0xFFFF0000) == 0) {
+ val = (u32)-(s32)val;
SUB(rd, rs, Operand2((u8)(val >> 8), 12));
SUB(rd, rd, Operand2((u8)(val), 0));
} else {
@@ -189,7 +206,7 @@ void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
} else {
int ops = 0;
for (int i = 0; i < 32; i += 2) {
- u8 bits = (val >> i) & 0xFF;
+ u8 bits = RotR(val, i) & 0xFF;
// If either low bit is not set, we need to use a BIC for them.
if ((bits & 3) != 3) {
++ops;
@@ -198,10 +215,16 @@ void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
}
// The worst case is 4 (e.g. 0x55555555.)
- if (ops <= 3 || !cpu_info.bArmV7) {
+#ifdef HAVE_ARMV7
+ if (ops > 3) {
+ MOVI2R(scratch, val);
+ AND(rd, rs, scratch);
+ } else
+#endif
+ {
bool first = true;
for (int i = 0; i < 32; i += 2) {
- u8 bits = (val >> i) & 0xFF;
+ u8 bits = RotR(val, i) & 0xFF;
if ((bits & 3) != 3) {
u8 rotation = i == 0 ? 0 : 16 - i / 2;
if (first) {
@@ -214,9 +237,6 @@ void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
i += 8 - 2;
}
}
- } else {
- MOVI2R(scratch, val);
- AND(rd, rs, scratch);
}
}
}
@@ -250,12 +270,17 @@ void ARMXEmitter::TSTI2R(ARMReg rs, u32 val, ARMReg scratch)
void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
{
Operand2 op2;
- if (TryMakeOperand2(val, op2)) {
+ if (val == 0) {
+ // Avoid the ALU, may improve pipeline.
+ if (rd != rs) {
+ MOV(rd, rs);
+ }
+ } else if (TryMakeOperand2(val, op2)) {
ORR(rd, rs, op2);
} else {
int ops = 0;
for (int i = 0; i < 32; i += 2) {
- u8 bits = (val >> i) & 0xFF;
+ u8 bits = RotR(val, i) & 0xFF;
// If either low bit is set, we need to use a ORR for them.
if ((bits & 3) != 0) {
++ops;
@@ -268,10 +293,15 @@ void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
if (TryMakeOperand2_AllowInverse(val, op2, &inversed) && ops >= 3) {
MVN(scratch, op2);
ORR(rd, rs, scratch);
- } else if (ops <= 3 || !cpu_info.bArmV7) {
+#ifdef HAVE_ARMV7
+ } else if (ops > 3) {
+ MOVI2R(scratch, val);
+ ORR(rd, rs, scratch);
+#endif
+ } else {
bool first = true;
for (int i = 0; i < 32; i += 2) {
- u8 bits = (val >> i) & 0xFF;
+ u8 bits = RotR(val, i) & 0xFF;
if ((bits & 3) != 0) {
u8 rotation = i == 0 ? 0 : 16 - i / 2;
if (first) {
@@ -284,9 +314,6 @@ void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
i += 8 - 2;
}
}
- } else {
- MOVI2R(scratch, val);
- ORR(rd, rs, scratch);
}
}
}
@@ -329,26 +356,48 @@ void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize)
Operand2 op2;
bool inverse;
- if (cpu_info.bArmV7 && !optimize)
+#ifdef HAVE_ARMV7
+ // Unused
+ if (!optimize)
{
// For backpatching on ARMv7
MOVW(reg, val & 0xFFFF);
MOVT(reg, val, true);
+ return;
}
- else if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) {
+#endif
+
+ if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) {
inverse ? MVN(reg, op2) : MOV(reg, op2);
} else {
- if (cpu_info.bArmV7)
- {
- // Use MOVW+MOVT for ARMv7+
- MOVW(reg, val & 0xFFFF);
- if(val & 0xFFFF0000)
- MOVT(reg, val, true);
- } else if (!TrySetValue_TwoOp(reg,val)) {
+#ifdef HAVE_ARMV7
+ // Use MOVW+MOVT for ARMv7+
+ MOVW(reg, val & 0xFFFF);
+ if(val & 0xFFFF0000)
+ MOVT(reg, val, true);
+#else
+ if (!TrySetValue_TwoOp(reg,val)) {
+ bool first = true;
+ for (int i = 0; i < 32; i += 2) {
+ u8 bits = RotR(val, i) & 0xFF;
+ if ((bits & 3) != 0) {
+ u8 rotation = i == 0 ? 0 : 16 - i / 2;
+ if (first) {
+ MOV(reg, Operand2(bits, rotation));
+ first = false;
+ } else {
+ ORR(reg, reg, Operand2(bits, rotation));
+ }
+ // Well, we took care of these other bits while we were at it.
+ i += 8 - 2;
+ }
+ }
// Use literal pool for ARMv6.
- AddNewLit(val);
- LDR(reg, _PC); // To be backpatched later
+ // Disabled for now as it is crashing since Vertex Decoder JIT
+// AddNewLit(val);
+// LDR(reg, _PC); // To be backpatched later
}
+#endif
}
}
@@ -702,12 +751,24 @@ void ARMXEmitter::LSL (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedData
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, true, dest, src, op2);}
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);}
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);}
-void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(2, false, dest, src, op2);}
-void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(2, true, dest, src, op2);}
+void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) {
+ _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "LSR must have a non-zero shift (use LSL.)");
+ WriteShiftedDataOp(2, false, dest, src, op2);
+}
+void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, Operand2 op2) {
+ _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "LSRS must have a non-zero shift (use LSLS.)");
+ WriteShiftedDataOp(2, true, dest, src, op2);
+}
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, false, dest, src, op2);}
void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, true, dest, src, op2);}
-void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, false, dest, src, op2);}
-void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, true, dest, src, op2);}
+void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) {
+ _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "ASR must have a non-zero shift (use LSL.)");
+ WriteShiftedDataOp(4, false, dest, src, op2);
+}
+void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) {
+ _assert_msg_(JIT, op2.GetType() != TYPE_IMM || op2.Imm5() != 0, "ASRS must have a non-zero shift (use LSLS.)");
+ WriteShiftedDataOp(4, true, dest, src, op2);
+}
void ARMXEmitter::ASR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, false, dest, src, op2);}
void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, true, dest, src, op2);}
@@ -754,6 +815,17 @@ void ARMXEmitter::CLZ(ARMReg rd, ARMReg rm)
Write32(condition | (0x16F << 16) | (rd << 12) | (0xF1 << 4) | rm);
}
+void ARMXEmitter::PLD(ARMReg rn, int offset, bool forWrite) {
+ _dbg_assert_msg_(JIT, offset < 0x3ff && offset > -0x3ff, "PLD: Max 12 bits of offset allowed");
+
+ bool U = offset >= 0;
+ if (offset < 0) offset = -offset;
+ bool R = !forWrite;
+ // Conditions not allowed
+ Write32((0xF5 << 24) | (U << 23) | (R << 22) | (1 << 20) | ((int)rn << 16) | (0xF << 12) | offset);
+}
+
+
void ARMXEmitter::BFI(ARMReg rd, ARMReg rn, u8 lsb, u8 width)
{
u32 msb = (lsb + width - 1);
@@ -998,21 +1070,6 @@ void ARMXEmitter::LDMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack,
#undef VA_TO_REGLIST
-ARMReg ARMXEmitter::SubBase(ARMReg Reg)
-{
- if (Reg >= S0)
- {
- if (Reg >= D0)
- {
- if (Reg >= Q0)
- return (ARMReg)((Reg - Q0) * 2); // Always gets encoded as a double register
- return (ARMReg)(Reg - D0);
- }
- return (ARMReg)(Reg - S0);
- }
- return Reg;
-}
-
// NEON Specific
void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
@@ -1061,15 +1118,14 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
| ((Vm & 0x10) << 2) | (Vm & 0xF));
}
-// Double/single, Neon
extern const VFPEnc VFPOps[16][2] = {
- {{0xE0, 0xA0}, {0x20, 0xD1}}, // 0: VMLA
+ {{0xE0, 0xA0}, { -1, -1}}, // 0: VMLA
{{0xE1, 0xA4}, { -1, -1}}, // 1: VNMLA
- {{0xE0, 0xA4}, {0x22, 0xD1}}, // 2: VMLS
+ {{0xE0, 0xA4}, { -1, -1}}, // 2: VMLS
{{0xE1, 0xA0}, { -1, -1}}, // 3: VNMLS
- {{0xE3, 0xA0}, {0x20, 0xD0}}, // 4: VADD
- {{0xE3, 0xA4}, {0x22, 0xD0}}, // 5: VSUB
- {{0xE2, 0xA0}, {0x30, 0xD1}}, // 6: VMUL
+ {{0xE3, 0xA0}, { -1, -1}}, // 4: VADD
+ {{0xE3, 0xA4}, { -1, -1}}, // 5: VSUB
+ {{0xE2, 0xA0}, { -1, -1}}, // 6: VMUL
{{0xE2, 0xA4}, { -1, -1}}, // 7: VNMUL
{{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 8: VABS(Vn(0x0) used for encoding)
{{0xE8, 0xA0}, { -1, -1}}, // 9: VDIV
@@ -1098,7 +1154,7 @@ const char *VFPOpNames[16] = {
"VABSi",
};
-u32 ARMXEmitter::EncodeVd(ARMReg Vd)
+u32 EncodeVd(ARMReg Vd)
{
bool quad_reg = Vd >= Q0;
bool double_reg = Vd >= D0;
@@ -1107,27 +1163,29 @@ u32 ARMXEmitter::EncodeVd(ARMReg Vd)
if (quad_reg)
return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 12);
- else
+ else {
if (double_reg)
return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 12);
else
return ((Reg & 0x1) << 22) | ((Reg & 0x1E) << 11);
+ }
}
-u32 ARMXEmitter::EncodeVn(ARMReg Vn)
+u32 EncodeVn(ARMReg Vn)
{
bool quad_reg = Vn >= Q0;
bool double_reg = Vn >= D0;
-
+
ARMReg Reg = SubBase(Vn);
if (quad_reg)
return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3);
- else
+ else {
if (double_reg)
return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3);
else
return ((Reg & 0x1E) << 15) | ((Reg & 0x1) << 7);
+ }
}
-u32 ARMXEmitter::EncodeVm(ARMReg Vm)
+u32 EncodeVm(ARMReg Vm)
{
bool quad_reg = Vm >= Q0;
bool double_reg = Vm >= D0;
@@ -1135,12 +1193,62 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm)
ARMReg Reg = SubBase(Vm);
if (quad_reg)
- return ((Reg & 0x10) << 2) | (Reg & 0xF);
- else
+ return ((Reg & 0x10) << 1) | (Reg & 0xF);
+ else {
if (double_reg)
- return ((Reg & 0x10) << 2) | (Reg & 0xF);
+ return ((Reg & 0x10) << 1) | (Reg & 0xF);
else
return ((Reg & 0x1) << 5) | (Reg >> 1);
+ }
+}
+
+u32 encodedSize(u32 value)
+{
+ if (value & I_8)
+ return 0;
+ else if (value & I_16)
+ return 1;
+ else if ((value & I_32) || (value & F_32))
+ return 2;
+ else if (value & I_64)
+ return 3;
+ else
+ _dbg_assert_msg_(JIT, false, "Passed invalid size to integer NEON instruction");
+ return 0;
+}
+
+ARMReg SubBase(ARMReg Reg)
+{
+ if (Reg >= S0)
+ {
+ if (Reg >= D0)
+ {
+ if (Reg >= Q0)
+ return (ARMReg)((Reg - Q0) * 2); // Always gets encoded as a double register
+ return (ARMReg)(Reg - D0);
+ }
+ return (ARMReg)(Reg - S0);
+ }
+ return Reg;
+}
+
+ARMReg DScalar(ARMReg dreg, int subScalar) {
+ int dr = (int)(SubBase(dreg)) & 0xF;
+ int scalar = ((subScalar << 4) | dr);
+ ARMReg ret = (ARMReg)(D0 + scalar);
+ // ILOG("Scalar: %i D0: %i AR: %i", scalar, (int)D0, (int)ret);
+ return ret;
+}
+
+// Convert to a DScalar
+ARMReg QScalar(ARMReg qreg, int subScalar) {
+ int dr = (int)(SubBase(qreg)) & 0xF;
+ if (subScalar & 2) {
+ dr++;
+ }
+ int scalar = (((subScalar & 1) << 4) | dr);
+ ARMReg ret = (ARMReg)(D0 + scalar);
+ return ret;
}
void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm)
@@ -1386,6 +1494,1068 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags)
}
}
+void ARMXEmitter::VABA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | EncodeVn(Vn) \
+ | (encodedSize(Size) << 20) | EncodeVd(Vd) | (0x71 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= D0 && Vn < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \
+ | (encodedSize(Size) << 20) | EncodeVd(Vd) | (0x50 << 4) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VABD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD << 8) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | EncodeVn(Vn) \
+ | (encodedSize(Size) << 20) | EncodeVd(Vd) | (0x70 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= D0 && Vn < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | EncodeVn(Vn) \
+ | (encodedSize(Size) << 20) | EncodeVd(Vd) | (0x70 << 4) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VABS(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB1 << 16) | (encodedSize(Size) << 18) | EncodeVd(Vd) \
+ | ((Size & F_32 ? 1 : 0) << 10) | (0x30 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VACGE(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ // Only Float
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) \
+ | (0xD1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VACGT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ // Only Float
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) \
+ | (0xD1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VACLE(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ VACGE(Vd, Vm, Vn);
+}
+
+void ARMXEmitter::VACLT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ VACGT(Vd, Vn, Vm);
+}
+
+void ARMXEmitter::VADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) \
+ | (0x8 << 8) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \
+ | EncodeVd(Vd) | (0x80 << 4) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VADDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= D0 && Vn < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \
+ | EncodeVd(Vd) | EncodeVm(Vm));
+}
+void ARMXEmitter::VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) \
+ | EncodeVd(Vd) | (1 << 8) | EncodeVm(Vm));
+}
+void ARMXEmitter::VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ // _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ // _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (1 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ // _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (3 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ // _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ // _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (1 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ if (Size & F_32)
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xE0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF3 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) \
+ | (0x81 << 4) | (register_quad << 6) | EncodeVm(Vm));
+
+}
+void ARMXEmitter::VCEQ(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 16) \
+ | EncodeVd(Vd) | ((Size & F_32 ? 1 : 0) << 10) | (0x10 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ if (Size & F_32)
+ Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xE0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) \
+ | (0x31 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCGE(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 16) \
+ | EncodeVd(Vd) | ((Size & F_32 ? 1 : 0) << 10) | (0x8 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ if (Size & F_32)
+ Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xE0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) \
+ | (0x30 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCGT(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \
+ | EncodeVd(Vd) | ((Size & F_32 ? 1 : 0) << 10) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ VCGE(Size, Vd, Vm, Vn);
+}
+void ARMXEmitter::VCLE(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \
+ | EncodeVd(Vd) | ((Size & F_32 ? 1 : 0) << 10) | (3 << 7) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCLS(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \
+ | EncodeVd(Vd) | (1 << 10) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ VCGT(Size, Vd, Vm, Vn);
+}
+void ARMXEmitter::VCLT(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) | (1 << 16) \
+ | EncodeVd(Vd) | ((Size & F_32 ? 1 : 0) << 10) | (0x20 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCLZ(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \
+ | EncodeVd(Vd) | (0x48 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VCNT(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, Size & I_8, "Can only use I_8 with " __FUNCTION__);
+
+ bool register_quad = Vd >= Q0;
+ Write32((0xF3 << 24) | (0xD << 20) | (encodedSize(Size) << 18) \
+ | EncodeVd(Vd) | (0x90 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Vm, u8 index)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ u32 imm4 = 0;
+ if (Size & I_8)
+ imm4 = (index << 1) | 1;
+ else if (Size & I_16)
+ imm4 = (index << 2) | 2;
+ else if (Size & (I_32 | F_32))
+ imm4 = (index << 3) | 4;
+ Write32((0xF3 << 24) | (0xB << 20) | (imm4 << 16) \
+ | EncodeVd(Vd) | (0xC << 8) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VDUP(u32 Size, ARMReg Vd, ARMReg Rt)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Rt < D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Vd = SubBase(Vd);
+ u8 sizeEncoded = 0;
+ if (Size & I_8)
+ sizeEncoded = 2;
+ else if (Size & I_16)
+ sizeEncoded = 1;
+ else if (Size & I_32)
+ sizeEncoded = 0;
+
+ Write32((0xEE << 24) | (0x8 << 20) | ((sizeEncoded & 2) << 21) | (register_quad << 21) \
+ | ((Vd & 0xF) << 16) | (Rt << 12) | (0xD1 << 4) | ((Vd & 0x10) << 3) | (1 << 4));
+}
+void ARMXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VEXT(ARMReg Vd, ARMReg Vn, ARMReg Vm, u8 index)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (0xB << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (index & 0xF) \
+ | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VFMA(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, cpu_info.bVFPv4, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xC1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VFMS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, cpu_info.bVFPv4, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xC1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 23) | (encodedSize(Size) << 20) \
+ | EncodeVn(Vn) | EncodeVd(Vd) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 23) | (encodedSize(Size) << 20) \
+ | EncodeVn(Vn) | EncodeVd(Vd) | (1 << 9) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 23) | (encodedSize(Size) << 20) \
+ | EncodeVn(Vn) | EncodeVd(Vd) | (0x60 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF2 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 23) | (encodedSize(Size) << 20) \
+ | EncodeVn(Vn) | EncodeVd(Vd) | (0x61 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x90 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMLS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF2 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | (1 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x90 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \
+ | EncodeVn(Vn) | EncodeVd(Vd) | (0x80 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vn >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm < Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float.");
+
+ Write32((0xF2 << 24) | ((Size & I_UNSIGNED ? 1 : 0) << 24) | (encodedSize(Size) << 20) \
+ | EncodeVn(Vn) | EncodeVd(Vd) | (0xA0 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | ((Size & I_POLYNOMIAL) ? (1 << 24) : 0) | (encodedSize(Size) << 20) | \
+ EncodeVn(Vn) | EncodeVd(Vd) | (0x91 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xC0 << 4) | ((Size & I_POLYNOMIAL) ? 1 << 9 : 0) | EncodeVm(Vm));
+}
+void ARMXEmitter::VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ // No idea if the Non-Q case here works. Not really that interested.
+ if (Size & F_32)
+ Write32((0xF2 << 24) | (register_quad << 24) | (1 << 23) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x14 << 4) | EncodeVm(Vm));
+ else
+ _dbg_assert_msg_(JIT, false, "VMLA_scalar only supports float atm");
+ //else
+ // Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x90 << 4) | (1 << 6) | EncodeVm(Vm));
+ // Unsigned support missing
+}
+void ARMXEmitter::VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ int VmEnc = EncodeVm(Vm);
+ // No idea if the Non-Q case here works. Not really that interested.
+ if (Size & F_32) // Q flag
+ Write32((0xF2 << 24) | (register_quad << 24) | (1 << 23) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x94 << 4) | VmEnc);
+ else
+ _dbg_assert_msg_(JIT, false, "VMUL_scalar only supports float atm");
+
+ // Write32((0xF2 << 24) | ((Size & I_POLYNOMIAL) ? (1 << 24) : 0) | (1 << 23) | (encodedSize(Size) << 20) |
+ // EncodeVn(Vn) | EncodeVd(Vd) | (0x84 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ // Unsigned support missing
+}
+
+void ARMXEmitter::VNEG(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 16) | \
+ EncodeVd(Vd) | ((Size & F_32) ? 1 << 10 : 0) | (0xE << 6) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (3 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (2 << 20) | EncodeVn(Vn) | EncodeVd(Vd) | (0x11 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VPADAL(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | EncodeVd(Vd) | \
+ (0x60 << 4) | ((Size & I_UNSIGNED) ? 1 << 7 : 0) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ if (Size & F_32)
+ Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xD0 << 4) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xB1 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VPADDL(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | EncodeVd(Vd) | \
+ (0x20 << 4) | (Size & I_UNSIGNED ? 1 << 7 : 0) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ if (Size & F_32)
+ Write32((0xF3 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xA0 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ if (Size & F_32)
+ Write32((0xF3 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF0 << 4) | EncodeVm(Vm));
+ else
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xA1 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQABS(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | EncodeVd(Vd) | \
+ (0x70 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x90 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xB0 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xB0 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF2 << 24) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xD0 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQNEG(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | EncodeVd(Vd) | \
+ (0x78 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF3 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xB0 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x51 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x41 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x21 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x40 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRECPE(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (0xB << 16) | EncodeVd(Vd) | \
+ (0x40 << 4) | (Size & F_32 ? 1 << 8 : 0) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | EncodeVn(Vn) | EncodeVd(Vd) | (0xF1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x10 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x50 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+ Vd = SubBase(Vd);
+ Vm = SubBase(Vm);
+
+ Write32((0xF3 << 24) | (0xB << 20) | ((Vd & 0x10) << 18) | (0xB << 16)
+ | ((Vd & 0xF) << 12) | (9 << 7) | (Size & F_32 ? (1 << 8) : 0) | (register_quad << 6)
+ | ((Vm & 0x10) << 1) | (Vm & 0xF));
+}
+void ARMXEmitter::VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xF1 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ Write32((0xF3 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x60 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, !(Size & F_32), __FUNCTION__ " doesn't support float");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x40 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ if (Size & F_32)
+ Write32((0xF2 << 24) | (1 << 21) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0xD0 << 4) | (register_quad << 6) | EncodeVm(Vm));
+ else
+ Write32((0xF3 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x80 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ Write32((0xF2 << 24) | (1 << 23) | ((encodedSize(Size) - 1) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x60 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x20 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ Write32((0xF2 << 24) | (Size & I_UNSIGNED ? 1 << 24 : 0) | (1 << 23) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x30 << 4) | EncodeVm(Vm));
+}
+void ARMXEmitter::VSWP(ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (1 << 17) | EncodeVd(Vd) | \
+ (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VTRN(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 17) | EncodeVd(Vd) | \
+ (1 << 7) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF2 << 24) | (encodedSize(Size) << 20) | EncodeVn(Vn) | EncodeVd(Vd) | \
+ (0x81 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VUZP(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 17) | EncodeVd(Vd) | \
+ (0x10 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+void ARMXEmitter::VZIP(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= D0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3 << 24) | (0xB << 20) | (encodedSize(Size) << 18) | (1 << 17) | EncodeVd(Vd) | \
+ (0x18 << 4) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VMOVL(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vd >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vm >= D0 && Vm <= D31, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+ _dbg_assert_msg_(JIT, (Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VMOVL");
+
+ bool unsign = (Size & I_UNSIGNED) != 0;
+ int imm3 = 0;
+ if (Size & I_8) imm3 = 1;
+ if (Size & I_16) imm3 = 2;
+ if (Size & I_32) imm3 = 4;
+
+ Write32((0xF2 << 24) | (unsign << 24) | (1 << 23) | (imm3 << 19) | EncodeVd(Vd) | \
+ (0xA1 << 4) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VMOVN(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, Vm >= Q0, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, Vd >= D0 && Vd <= D31, "Pass invalid register to " __FUNCTION__);
+ _dbg_assert_msg_(JIT, cpu_info.bNEON, "Can't use " __FUNCTION__ " when CPU doesn't support it");
+
+ bool register_quad = Vd >= Q0;
+
+ Write32((0xF3B << 20) | (encodedSize(Size) << 18) | (1 << 17) | EncodeVd(Vd) | (1 << 9) | EncodeVm(Vm));
+}
+
+void ARMXEmitter::VCVT(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ _dbg_assert_msg_(JIT, (Size & (I_UNSIGNED | I_SIGNED)) != 0, "Must specify I_SIGNED or I_UNSIGNED in VCVT NEON");
+
+ bool register_quad = Vd >= Q0;
+ bool toInteger = (Size & I_32) != 0;
+ bool isUnsigned = (Size & I_UNSIGNED) != 0;
+ int op = (toInteger << 1) | (int)isUnsigned;
+
+ Write32((0xF3 << 24) | (0xBB << 16) | EncodeVd(Vd) | (0x3 << 9) | (op << 7) | (register_quad << 6) | EncodeVm(Vm));
+}
+
+static int RegCountToType(int nRegs, NEONAlignment align) {
+ switch (nRegs) {
+ case 1:
+ _dbg_assert_msg_(JIT, !((int)align & 1), "align & 1 must be == 0");
+ return 7;
+ case 2:
+ _dbg_assert_msg_(JIT, !((int)align & 3), "align & 3 must be == 0");
+ return 10;
+ case 3:
+ _dbg_assert_msg_(JIT, !((int)align & 1), "align & 1 must be == 0");
+ return 6;
+ case 4:
+ return 4;
+ default:
+ _dbg_assert_msg_(JIT, false, "Invalid number of registers passed to vector load/store");
+ return 0;
+ }
+}
+
+void ARMXEmitter::WriteVLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm)
+{
+ u32 spacing = RegCountToType(regCount, align); // Only support loading to 1 reg
+ // Gets encoded as a double register
+ Vd = SubBase(Vd);
+
+ Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (load << 21) | (Rn << 16)
+ | ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
+ | (align << 4) | Rm);
+}
+
+void ARMXEmitter::VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) {
+ WriteVLDST1(true, Size, Vd, Rn, regCount, align, Rm);
+}
+
+void ARMXEmitter::VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm) {
+ WriteVLDST1(false, Size, Vd, Rn, regCount, align, Rm);
+}
+
+void ARMXEmitter::WriteVLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm)
+{
+ bool register_quad = Vd >= Q0;
+
+ Vd = SubBase(Vd);
+ // Support quad lanes by converting to D lanes
+ if (register_quad && lane > 1) {
+ Vd = (ARMReg)((int)Vd + 1);
+ lane -= 2;
+ }
+ int encSize = encodedSize(Size);
+ int index_align = 0;
+ switch (encSize) {
+ case 0: index_align = lane << 1; break;
+ case 1: index_align = lane << 2; if (aligned) index_align |= 1; break;
+ case 2: index_align = lane << 3; if (aligned) index_align |= 3; break;
+ default:
+ break;
+ }
+
+ Write32((0xF4 << 24) | (1 << 23) | ((Vd & 0x10) << 18) | (load << 21) | (Rn << 16)
+ | ((Vd & 0xF) << 12) | (encSize << 10)
+ | (index_align << 4) | Rm);
+}
+
+void ARMXEmitter::VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) {
+ WriteVLDST1_lane(true, Size, Vd, Rn, lane, aligned, Rm);
+}
+
+void ARMXEmitter::VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm) {
+ WriteVLDST1_lane(false, Size, Vd, Rn, lane, aligned, Rm);
+}
+
+void ARMXEmitter::VLD1_all_lanes(u32 Size, ARMReg Vd, ARMReg Rn, bool aligned, ARMReg Rm) {
+ bool register_quad = Vd >= Q0;
+
+ Vd = SubBase(Vd);
+
+ int T = register_quad; // two D registers
+
+ Write32((0xF4 << 24) | (1 << 23) | ((Vd & 0x10) << 18) | (1 << 21) | (Rn << 16)
+ | ((Vd & 0xF) << 12) | (0xC << 8) | (encodedSize(Size) << 6)
+ | (T << 5) | (aligned << 4) | Rm);
+}
+
+/*
+void ARMXEmitter::VLD2(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm)
+{
+ u32 spacing = 0x8; // Single spaced registers
+ // Gets encoded as a double register
+ Vd = SubBase(Vd);
+
+ Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (1 << 21) | (Rn << 16)
+ | ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
+ | (align << 4) | Rm);
+}
+*/
+
+void ARMXEmitter::VREVX(u32 size, u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ bool register_quad = Vd >= Q0;
+ Vd = SubBase(Vd);
+ Vm = SubBase(Vm);
+
+ Write32((0xF3 << 24) | (1 << 23) | ((Vd & 0x10) << 18) | (0x3 << 20)
+ | (encodedSize(Size) << 18) | ((Vd & 0xF) << 12) | (size << 7)
+ | (register_quad << 6) | ((Vm & 0x10) << 1) | (Vm & 0xF));
+}
+
+void ARMXEmitter::VREV64(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ VREVX(0, Size, Vd, Vm);
+}
+
+void ARMXEmitter::VREV32(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ VREVX(1, Size, Vd, Vm);
+}
+
+void ARMXEmitter::VREV16(u32 Size, ARMReg Vd, ARMReg Vm)
+{
+ VREVX(2, Size, Vd, Vm);
+}
+
// UNTESTED
// See page A8-878 in ARMv7-A Architecture Reference Manual
diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h
index 868c5bcdb3..117b5ef28b 100644
--- a/Common/ArmEmitter.h
+++ b/Common/ArmEmitter.h
@@ -70,6 +70,9 @@ enum ARMReg
// ASIMD Quad-Word registers
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
+
+ // for NEON VLD/VST instructions
+ REG_UPDATE = R13,
INVALID_REG = 0xFFFFFFFF
};
@@ -346,9 +349,44 @@ struct LiteralPool
typedef const u8* JumpTarget;
+// XXX: Stop polluting the global namespace
+const u32 I_8 = (1 << 0);
+const u32 I_16 = (1 << 1);
+const u32 I_32 = (1 << 2);
+const u32 I_64 = (1 << 3);
+const u32 I_SIGNED = (1 << 4);
+const u32 I_UNSIGNED = (1 << 5);
+const u32 F_32 = (1 << 6);
+const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL
+
+u32 EncodeVd(ARMReg Vd);
+u32 EncodeVn(ARMReg Vn);
+u32 EncodeVm(ARMReg Vm);
+
+u32 encodedSize(u32 value);
+
+// Subtracts the base from the register to give us the real one
+ARMReg SubBase(ARMReg Reg);
+
+// See A.7.1 in the ARMv7-A
+// VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed
+ARMReg DScalar(ARMReg dreg, int subScalar);
+ARMReg QScalar(ARMReg qreg, int subScalar);
+
+enum NEONAlignment {
+ ALIGN_NONE = 0,
+ ALIGN_64 = 1,
+ ALIGN_128 = 2,
+ ALIGN_256 = 3
+};
+
+
+class NEONXEmitter;
+
class ARMXEmitter
{
friend struct OpArg; // for Write8 etc
+ friend class NEONXEmitter;
private:
u8 *code, *startcode;
u8 *lastCacheFlushEnd;
@@ -361,9 +399,6 @@ private:
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
- u32 EncodeVd(ARMReg Vd);
- u32 EncodeVn(ARMReg Vn);
- u32 EncodeVm(ARMReg Vm);
void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
@@ -371,6 +406,9 @@ private:
// New Ops
void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false);
+ void WriteVLDST1(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align, ARMReg Rm);
+ void WriteVLDST1_lane(bool load, u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm);
+
protected:
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
@@ -449,7 +487,6 @@ public:
void ADDS(ARMReg dest, ARMReg src, Operand2 op2);
void ADC (ARMReg dest, ARMReg src, Operand2 op2);
void ADCS(ARMReg dest, ARMReg src, Operand2 op2);
-
void LSL (ARMReg dest, ARMReg src, Operand2 op2);
void LSL (ARMReg dest, ARMReg src, ARMReg op2);
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
@@ -505,6 +542,7 @@ public:
void BFI(ARMReg rd, ARMReg rn, u8 lsb, u8 width);
void UBFX(ARMReg dest, ARMReg op2, u8 lsb, u8 width);
void CLZ(ARMReg rd, ARMReg rm);
+ void PLD(ARMReg rd, int offset, bool forWrite = false);
// Using just MSR here messes with our defines on the PPC side of stuff (when this code was in dolphin...)
// Just need to put an underscore here, bit annoying.
@@ -543,12 +581,10 @@ public:
// is deprecating conditional execution of ASIMD instructions.
// ASIMD instructions don't even have a conditional encoding.
- // Subtracts the base from the register to give us the real one
- ARMReg SubBase(ARMReg Reg);
// NEON Only
- void VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
- void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
- void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VABD(IntegerSize size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VADD(IntegerSize size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSUB(IntegerSize size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
// VFP Only
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
@@ -582,6 +618,163 @@ public:
void VCVTF32F16(ARMReg Dest, ARMReg Src);
void VCVTF16F32(ARMReg Dest, ARMReg Src);
+ void VABA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VABAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VABD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VABDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VABS(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VACGE(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VACGT(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VACLE(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VACLT(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VADDL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VADDW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VAND(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VBIC(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VBIF(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VBIT(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VBSL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VCEQ(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VCEQ(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCGE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VCGE(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCGT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VCGT(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCLE(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VCLE(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCLS(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCLT(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VCLT(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCLZ(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VCNT(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VDUP(u32 Size, ARMReg Vd, ARMReg Vm, u8 index);
+ void VDUP(u32 Size, ARMReg Vd, ARMReg Rt);
+ void VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VEXT(ARMReg Vd, ARMReg Vn, ARMReg Vm, u8 index);
+ void VFMA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VFMS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VHSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+
+ // Three registers
+ void VMLA(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMLS(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMUL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMLAL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMLSL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMULL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQRDMULH(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+
+ // Two registers and a scalar
+ // These two are super useful for matrix multiplication
+ void VMUL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMLA_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+
+ // TODO:
+ /*
+ void VMLS_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMLAL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMLSL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VMULL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMLAL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMLSL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMULH_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQDMULL_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQRDMULH_scalar(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ */
+
+ void VNEG(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VORN(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VPADAL(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VPADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VPADDL(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VPMAX(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VPMIN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQABS(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VQADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQNEG(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VQRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VQSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VRADDHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VRECPE(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VRECPS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VRHADD(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VRSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VRSQRTE(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VRSQRTS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VRSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSHL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSUB(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSUBHN(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSUBL(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSUBW(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VSWP(ARMReg Vd, ARMReg Vm);
+ void VTRN(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VTST(u32 Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
+ void VUZP(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VZIP(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VREVX(u32 size, u32 Size, ARMReg Vd, ARMReg Vm);
+ void VREV64(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VREV32(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VREV16(u32 Size, ARMReg Vd, ARMReg Vm);
+
+
+ // Widening and narrowing moves
+ void VMOVL(u32 Size, ARMReg Vd, ARMReg Vm);
+ void VMOVN(u32 Size, ARMReg Vd, ARMReg Vm);
+
+ // Vector VCVT
+ void VCVT(u32 DestSize, ARMReg Dest, ARMReg Src);
+
+
+ // Notes:
+ // Rm == _PC is interpreted as no offset, otherwise, effective address is sum of Rn and Rm
+ // Rm == R13 is interpreted as VLD1, .... [Rn]! Added a REG_UPDATE pseudo register.
+
+ // Load/store multiple registers full of elements (a register is a D register)
+ // Specifying alignment when it can be guaranteed is documented to improve load/store performance.
+ // For example, when loading a set of four 64-bit registers that we know is 32-byte aligned, we should specify ALIGN_256.
+ void VLD1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+ void VST1(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+
+ // Load/store single lanes of D registers
+ void VLD1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm = _PC);
+ void VST1_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, bool aligned, ARMReg Rm = _PC);
+
+ // Load one value into all lanes of a D or a Q register (either supported, all formats should work).
+ void VLD1_all_lanes(u32 Size, ARMReg Vd, ARMReg Rn, bool aligned, ARMReg Rm = _PC);
+
+ /*
+ // Deinterleave two loads... or something. TODO
+ void VLD2(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+ void VST2(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+
+ void VLD2_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
+ void VST2_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
+
+ void VLD3(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+ void VST3(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+
+ void VLD3_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
+ void VST3_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
+
+ void VLD4(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+ void VST4(u32 Size, ARMReg Vd, ARMReg Rn, int regCount, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
+
+ void VLD4_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
+ void VST4_lane(u32 Size, ARMReg Vd, ARMReg Rn, int lane, ARMReg Rm = _PC);
+ */
+
void VMRS_APSR();
void VMRS(ARMReg Rt);
void VMSR(ARMReg Rt);
@@ -592,13 +785,16 @@ public:
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
void MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate = false);
+ // Load pointers without casting
+ template void MOVP2R(ARMReg reg, T *val) {
+ MOVI2R(reg, (u32)(intptr_t)(void *)val);
+ }
+
void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
void CMPI2R(ARMReg rs, u32 val, ARMReg scratch);
void TSTI2R(ARMReg rs, u32 val, ARMReg scratch);
void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
-
-
}; // class ARMXEmitter
@@ -635,14 +831,16 @@ public:
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace()
{
-#ifndef __SYMBIAN32__
+#ifdef __SYMBIAN32__
+ ResetExecutableMemory(region);
+#else
FreeMemoryPages(region, region_size);
#endif
region = NULL;
region_size = 0;
}
- bool IsInSpace(u8 *ptr)
+ bool IsInSpace(const u8 *ptr) const
{
return ptr >= region && ptr < region + region_size;
}
@@ -672,7 +870,7 @@ public:
return region;
}
- size_t GetOffset(u8 *ptr) {
+ size_t GetOffset(const u8 *ptr) const {
return ptr - region;
}
};
diff --git a/Common/Atomic_GCC.h b/Common/Atomic_GCC.h
index 2ee4622da1..5024b759bc 100644
--- a/Common/Atomic_GCC.h
+++ b/Common/Atomic_GCC.h
@@ -21,7 +21,7 @@
#ifdef BLACKBERRY
#include
#elif defined(__SYMBIAN32__)
-#include
+#include
#endif
#include "Common.h"
@@ -63,12 +63,16 @@ inline u32 AtomicLoad(volatile u32& src) {
return src; // 32-bit reads are always atomic.
}
inline u32 AtomicLoadAcquire(volatile u32& src) {
+#ifdef __SYMBIAN32__
+ return __e32_atomic_load_acq32(&src);
+#else
//keep the compiler from caching any memory references
u32 result = src; // 32-bit reads are always atomic.
//__sync_synchronize(); // TODO: May not be necessary.
// Compiler instruction only. x86 loads always have acquire semantics.
__asm__ __volatile__ ( "":::"memory" );
return result;
+#endif
}
inline void AtomicOr(volatile u32& target, u32 value) {
@@ -82,57 +86,12 @@ inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
#ifdef BLACKBERRY
atomic_set(&dest, value);
#elif defined(__SYMBIAN32__)
- g_atomic_int_set(&dest, value);
+ __e32_atomic_store_rel32(&dest, value);
#else
- __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics.
+ __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function has acquire semantics.
#endif
}
}
-// Old code kept here for reference in case we need the parts with __asm__ __volatile__.
-#if 0
-LONG SyncInterlockedIncrement(LONG *Dest)
-{
-#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
- return __sync_add_and_fetch(Dest, 1);
-#else
- register int result;
- __asm__ __volatile__("lock; xadd %0,%1"
- : "=r" (result), "=m" (*Dest)
- : "0" (1), "m" (*Dest)
- : "memory");
- return result;
-#endif
-}
-
-LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
-{
-#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
- return __sync_add_and_fetch(Dest, Val);
-#else
- register int result;
- __asm__ __volatile__("lock; xadd %0,%1"
- : "=r" (result), "=m" (*Dest)
- : "0" (Val), "m" (*Dest)
- : "memory");
- return result;
-#endif
-}
-
-LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
-{
-#if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
- return __sync_lock_test_and_set(Dest, Val);
-#else
- register int result;
- __asm__ __volatile__("lock; xchg %0,%1"
- : "=r" (result), "=m" (*Dest)
- : "0" (Val), "m" (*Dest)
- : "memory");
- return result;
-#endif
-}
-#endif
-
#endif
diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp
index 19e557f9ea..a7aa7fc09e 100644
--- a/Common/CPUDetect.cpp
+++ b/Common/CPUDetect.cpp
@@ -36,7 +36,7 @@
#undef _interlockedbittestandreset64
#else
-#if !defined(_M_GENERIC) && !defined(MIPS)
+#ifdef _M_SSE
#include
#endif
@@ -45,8 +45,7 @@
#include
#elif !defined(MIPS)
-void __cpuidex(int regs[4], int cpuid_leaf, int ecxval)
-{
+void __cpuidex(int regs[4], int cpuid_leaf, int ecxval) {
#ifdef ANDROID
// Use the /dev/cpu/%i/cpuid interface
int f = open("/dev/cpu/0/cpuid", O_RDONLY);
@@ -90,8 +89,7 @@ CPUInfo::CPUInfo() {
}
// Detects the various cpu features
-void CPUInfo::Detect()
-{
+void CPUInfo::Detect() {
memset(this, 0, sizeof(*this));
#ifdef _M_IX86
Mode64bit = false;
@@ -154,7 +152,11 @@ void CPUInfo::Detect()
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
- if ((cpu_id[2] >> 28) & 1) bAVX = true;
+ if ((cpu_id[2] >> 28) & 1) {
+ bAVX = true;
+ if ((cpu_id[2] >> 12) & 1)
+ bFMA = true;
+ }
if ((cpu_id[2] >> 25) & 1) bAES = true;
}
if (max_ex_fn >= 0x80000004) {
@@ -231,6 +233,7 @@ std::string CPUInfo::Summarize()
if (bSSE4_2) sum += ", SSE4.2";
if (HTT) sum += ", HTT";
if (bAVX) sum += ", AVX";
+ if (bAVX) sum += ", FMA";
if (bAES) sum += ", AES";
if (bLongMode) sum += ", 64-bit support";
return sum;
diff --git a/Common/CPUDetect.h b/Common/CPUDetect.h
index 4ca4712bb6..04c615b412 100644
--- a/Common/CPUDetect.h
+++ b/Common/CPUDetect.h
@@ -19,26 +19,29 @@
#ifndef _CPUDETECT_H_
#define _CPUDETECT_H_
+// Every architecture has its own define. This needs to be added to.
+#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__)
+#define HAVE_ARMV7 1
+#endif
+
#include
-enum CPUVendor
-{
+enum CPUVendor {
VENDOR_INTEL = 0,
VENDOR_AMD = 1,
VENDOR_ARM = 2,
VENDOR_OTHER = 3,
};
-struct CPUInfo
-{
+struct CPUInfo {
CPUVendor vendor;
-
+
char cpu_string[0x21];
char brand_string[0x41];
bool OS64bit;
bool CPU64bit;
bool Mode64bit;
-
+
bool HTT;
int num_cores;
int logical_cpu_count;
@@ -53,10 +56,11 @@ struct CPUInfo
bool bLZCNT;
bool bSSE4A;
bool bAVX;
+ bool bFMA;
bool bAES;
bool bLAHFSAHF64;
bool bLongMode;
-
+
// ARM specific CPUInfo
bool bSwp;
bool bHalf;
@@ -71,7 +75,6 @@ struct CPUInfo
bool bVFPv4;
bool bIDIVa;
bool bIDIVt;
- bool bArmV7; // enable MOVT, MOVW etc
// ARMv8 specific
bool bFP;
@@ -79,7 +82,7 @@ struct CPUInfo
// Call Detect()
explicit CPUInfo();
-
+
// Turn the cpu info into a string we can show
std::string Summarize();
diff --git a/Common/Common.h b/Common/Common.h
index df4b22acba..8604128025 100644
--- a/Common/Common.h
+++ b/Common/Common.h
@@ -146,6 +146,8 @@ private:
# define _M_SSE 0x301
# elif defined __SSE3__
# define _M_SSE 0x300
+# elif defined __SSE2__
+# define _M_SSE 0x200
# endif
#elif ((_MSC_VER >= 1500) || __INTEL_COMPILER) // Visual Studio 2008
# define _M_SSE 0x402
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 447c5861ec..be412443ea 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -183,16 +183,13 @@
-
-
-
@@ -216,7 +213,6 @@
-
@@ -228,7 +224,6 @@
Create
-
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 62a187b5f0..c91b201d5a 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -16,14 +16,11 @@
-
-
-
@@ -47,13 +44,11 @@
-
-
diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp
index 24f151ba92..2ae97a644a 100644
--- a/Common/FileUtil.cpp
+++ b/Common/FileUtil.cpp
@@ -37,7 +37,10 @@
#include
#include
#include
-#endif
+#if !defined(IOS)
+#include
+#endif // !defined(IOS)
+#endif // __APPLE__
#include "util/text/utf8.h"
@@ -254,11 +257,11 @@ bool CreateDir(const std::string &path)
bool CreateFullPath(const std::string &fullPath)
{
int panicCounter = 100;
- INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
+ DEBUG_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
if (File::Exists(fullPath))
{
- INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
+ DEBUG_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
return true;
}
@@ -641,21 +644,50 @@ bool SetCurrentDir(const std::string &directory)
return __chdir(directory.c_str()) == 0;
}
-#ifdef _WIN32
-std::wstring &GetExeDirectory()
+const std::string &GetExeDirectory()
{
- static std::wstring DolphinPath;
- if (DolphinPath.empty())
+ static std::string ExePath;
+
+ if (ExePath.empty())
{
- wchar_t Dolphin_exe_Path[2048];
- GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
- DolphinPath = Dolphin_exe_Path;
- DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
- }
- return DolphinPath;
-}
+#ifdef _WIN32
+ TCHAR program_path[4096] = {0};
+ GetModuleFileName(NULL, program_path, ARRAY_SIZE(program_path) - 1);
+ program_path[ARRAY_SIZE(program_path) - 1] = '\0';
+ TCHAR *last_slash = _tcsrchr(program_path, '\\');
+ if (last_slash != NULL)
+ *(last_slash + 1) = '\0';
+#ifdef UNICODE
+ ExePath = ConvertWStringToUTF8(program_path);
+#else
+ ExePath = program_path;
#endif
+#elif (defined(__APPLE__) && !defined(IOS)) || defined(__linux__)
+ char program_path[4096];
+ uint32_t program_path_size = sizeof(program_path) - 1;
+
+#if defined(__linux__)
+ if (readlink("/proc/self/exe", program_path, 4095) > 0)
+#elif defined(__APPLE__) && !defined(IOS)
+ if (_NSGetExecutablePath(program_path, &program_path_size) == 0)
+#else
+#error Unmatched ifdef.
+#endif
+ {
+ program_path[sizeof(program_path) - 1] = '\0';
+ char *last_slash = strrchr(program_path, '/');
+ if (last_slash != NULL)
+ *(last_slash + 1) = '\0';
+ ExePath = program_path;
+ }
+#endif
+ }
+
+ return ExePath;
+}
+
+
IOFile::IOFile()
: m_file(NULL), m_good(true)
{}
diff --git a/Common/FileUtil.h b/Common/FileUtil.h
index 79f46f7188..a7727eed40 100644
--- a/Common/FileUtil.h
+++ b/Common/FileUtil.h
@@ -102,9 +102,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path);
// Set the current directory to given directory
bool SetCurrentDir(const std::string &directory);
-#ifdef _WIN32
-std::wstring &GetExeDirectory();
-#endif
+const std::string &GetExeDirectory();
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
diff --git a/Common/KeyMap.cpp b/Common/KeyMap.cpp
index 4f94900a83..9be86d1072 100644
--- a/Common/KeyMap.cpp
+++ b/Common/KeyMap.cpp
@@ -67,6 +67,7 @@ static const DefMappingStruct defaultQwertyKeyboardKeyMap[] = {
{VIRTKEY_UNTHROTTLE , NKCODE_TAB},
{VIRTKEY_SPEED_TOGGLE, NKCODE_GRAVE},
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
+ {VIRTKEY_REWIND , NKCODE_DEL},
};
static const DefMappingStruct defaultAzertyKeyboardKeyMap[] = {
@@ -95,6 +96,7 @@ static const DefMappingStruct defaultAzertyKeyboardKeyMap[] = {
{VIRTKEY_UNTHROTTLE , NKCODE_TAB},
{VIRTKEY_SPEED_TOGGLE, NKCODE_GRAVE},
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
+ {VIRTKEY_REWIND , NKCODE_DEL},
};
static const DefMappingStruct defaultQwertzKeyboardKeyMap[] = {
@@ -123,6 +125,7 @@ static const DefMappingStruct defaultQwertzKeyboardKeyMap[] = {
{VIRTKEY_UNTHROTTLE , NKCODE_TAB},
{VIRTKEY_SPEED_TOGGLE, NKCODE_GRAVE},
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
+ {VIRTKEY_REWIND , NKCODE_DEL},
};
static const DefMappingStruct default360KeyMap[] = {
@@ -190,6 +193,7 @@ static const DefMappingStruct defaultBlackberryQWERTYKeyMap[] = {
{VIRTKEY_UNTHROTTLE , NKCODE_TAB},
{VIRTKEY_SPEED_TOGGLE, NKCODE_GRAVE},
{VIRTKEY_PAUSE , NKCODE_ESCAPE},
+ {VIRTKEY_REWIND , NKCODE_DEL},
};
static const DefMappingStruct defaultPadMap[] = {
@@ -279,17 +283,17 @@ void UpdateConfirmCancelKeys() {
int confirmKey = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE;
int cancelKey = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS;
- for(auto i = g_controllerMap[confirmKey].begin(); i != g_controllerMap[confirmKey].end(); ++i) {
+ for (auto i = g_controllerMap[confirmKey].begin(); i != g_controllerMap[confirmKey].end(); ++i) {
confirmKeys.push_back((keycode_t)i->keyCode);
}
- for(auto i = g_controllerMap[cancelKey].begin(); i != g_controllerMap[cancelKey].end(); ++i) {
+ for (auto i = g_controllerMap[cancelKey].begin(); i != g_controllerMap[cancelKey].end(); ++i) {
cancelKeys.push_back((keycode_t)i->keyCode);
}
// Push several hard-coded keys before submitting to native.
- const keycode_t hardcodedConfirmKeys[] = {
- NKCODE_SPACE,
+ const keycode_t hardcodedConfirmKeys[] = {
+ NKCODE_SPACE,
NKCODE_ENTER,
};
@@ -299,9 +303,9 @@ void UpdateConfirmCancelKeys() {
confirmKeys.push_back(hardcodedConfirmKeys[i]);
}
- const keycode_t hardcodedCancelKeys[] = {
- NKCODE_ESCAPE,
- NKCODE_BACK,
+ const keycode_t hardcodedCancelKeys[] = {
+ NKCODE_ESCAPE,
+ NKCODE_BACK,
};
for (size_t i = 0; i < ARRAY_SIZE(hardcodedCancelKeys); i++) {
@@ -329,7 +333,6 @@ void SetDefaultKeyMap(DefaultMaps dmap, bool replace) {
bool qwertz = false;
#ifdef _WIN32
HKL localeId = GetKeyboardLayout(0);
-
// TODO: Is this list complete enough?
switch ((int)localeId & 0xFFFF) {
case 0x407:
@@ -360,7 +363,8 @@ void SetDefaultKeyMap(DefaultMaps dmap, bool replace) {
SetDefaultKeyMap(DEVICE_ID_PAD_0, defaultShieldKeyMap, ARRAY_SIZE(defaultShieldKeyMap), replace);
break;
case DEFAULT_MAPPING_BLACKBERRY_QWERTY:
- SetDefaultKeyMap(DEVICE_ID_PAD_0, defaultBlackberryQWERTYKeyMap, ARRAY_SIZE(defaultBlackberryQWERTYKeyMap), replace);
+ SetDefaultKeyMap(DEVICE_ID_KEYBOARD, defaultBlackberryQWERTYKeyMap, ARRAY_SIZE(defaultBlackberryQWERTYKeyMap), replace);
+ replace = false;
case DEFAULT_MAPPING_PAD:
SetDefaultKeyMap(DEVICE_ID_PAD_0, defaultPadMap, ARRAY_SIZE(defaultPadMap), replace);
break;
@@ -426,7 +430,7 @@ const KeyMap_IntStrPair key_names[] = {
{NKCODE_F10, "F10"},
{NKCODE_F11, "F11"},
{NKCODE_F12, "F12"},
-
+
{NKCODE_GRAVE, "`"},
{NKCODE_SLASH, "/"},
{NKCODE_BACKSLASH, "\\"},
@@ -453,7 +457,8 @@ const KeyMap_IntStrPair key_names[] = {
{NKCODE_ALT_RIGHT, "RAlt"},
{NKCODE_SPACE, "Space"},
{NKCODE_WINDOW, "Windows"},
- {NKCODE_DEL, "Del"},
+ {NKCODE_DEL, "Backspace"},
+ {NKCODE_FORWARD_DEL, "Delete"},
{NKCODE_MOVE_HOME, "Home"},
{NKCODE_MOVE_END, "End"},
{NKCODE_ESCAPE, "Esc"},
@@ -601,6 +606,11 @@ const KeyMap_IntStrPair psp_button_names[] = {
{VIRTKEY_UNTHROTTLE, "Unthrottle"},
{VIRTKEY_SPEED_TOGGLE, "SpeedToggle"},
{VIRTKEY_PAUSE, "Pause"},
+#ifndef USING_GLES2
+ {VIRTKEY_REWIND, "Rewind"},
+#endif
+ {VIRTKEY_SAVE_STATE, "Save State"},
+ {VIRTKEY_LOAD_STATE, "Load State"},
{VIRTKEY_AXIS_RIGHT_Y_MAX, "RightAn.Up"},
{VIRTKEY_AXIS_RIGHT_Y_MIN, "RightAn.Down"},
@@ -671,27 +681,20 @@ KeyDef AxisDef(int deviceId, int axisId, int direction) {
return KeyDef(deviceId, TranslateKeyCodeFromAxis(axisId, direction));
}
-static bool FindKeyMapping(int deviceId, int key, int *psp_button) {
+static bool FindKeyMapping(int deviceId, int key, std::vector *psp_button) {
// Brute force, let's optimize later
for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) {
for (auto iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) {
if (*iter2 == KeyDef(deviceId, key)) {
- *psp_button = iter->first;
- return true;
+ psp_button->push_back(iter->first);
}
}
}
- return false;
+ return psp_button->size() > 0;
}
-int KeyToPspButton(int deviceId, int key) {
- int search_start_layer = 0;
- int psp_button;
-
- if (FindKeyMapping(deviceId, key, &psp_button))
- return psp_button;
-
- return KEYMAP_ERROR_UNKNOWN_KEY;
+bool KeyToPspButton(int deviceId, int key, std::vector *pspKeys) {
+ return FindKeyMapping(deviceId, key, pspKeys);
}
// TODO: vector output
@@ -708,9 +711,9 @@ bool KeyFromPspButton(int btn, std::vector *keys) {
return false;
}
-int AxisToPspButton(int deviceId, int axisId, int direction) {
+bool AxisToPspButton(int deviceId, int axisId, int direction, std::vector *pspKeys) {
int key = TranslateKeyCodeFromAxis(axisId, direction);
- return KeyToPspButton(deviceId, key);
+ return KeyToPspButton(deviceId, key, pspKeys);
}
bool AxisFromPspButton(int btn, int *deviceId, int *axisId, int *direction) {
diff --git a/Common/KeyMap.h b/Common/KeyMap.h
index 604a861e2f..9d69ffedd9 100644
--- a/Common/KeyMap.h
+++ b/Common/KeyMap.h
@@ -40,6 +40,9 @@ enum {
VIRTKEY_AXIS_RIGHT_Y_MIN = 0x10009,
VIRTKEY_AXIS_RIGHT_X_MAX = 0x1000a,
VIRTKEY_AXIS_RIGHT_Y_MAX = 0x1000b,
+ VIRTKEY_REWIND = 0x1000c,
+ VIRTKEY_SAVE_STATE = 0x1000d,
+ VIRTKEY_LOAD_STATE = 0x1000e,
VIRTKEY_LAST,
VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST
};
@@ -95,9 +98,9 @@ typedef std::map> KeyMapping;
// KeyMap
// A translation layer for key assignment. Provides
// integration with Core's config state.
-//
+//
// Does not handle input state managment.
-//
+//
// Platform ports should map their platform's keys to KeyMap's keys (NKCODE_*).
//
// Then have KeyMap transform those into psp buttons.
@@ -113,7 +116,7 @@ namespace KeyMap {
std::string name;
};
- // Use if you need to display the textual name
+ // Use if you need to display the textual name
std::string GetKeyName(int keyCode);
std::string GetKeyOrAxisName(int keyCode);
std::string GetAxisName(int axisId);
@@ -124,10 +127,7 @@ namespace KeyMap {
// Use if to translate KeyMap Keys to PSP
// buttons. You should have already translated
// your platform's keys to KeyMap keys.
- //
- // Returns KEYMAP_ERROR_UNKNOWN_KEY
- // for any unmapped key
- int KeyToPspButton(int deviceId, int key);
+ bool KeyToPspButton(int deviceId, int key, std::vector *pspKeys);
bool KeyFromPspButton(int btn, std::vector *keys);
int TranslateKeyCodeToAxis(int keyCode, int &direction);
@@ -141,7 +141,7 @@ namespace KeyMap {
// Direction is negative or positive.
void SetAxisMapping(int btn, int deviceId, int axisId, int direction, bool replace);
- int AxisToPspButton(int deviceId, int axisId, int direction);
+ bool AxisToPspButton(int deviceId, int axisId, int direction, std::vector *pspKeys);
bool AxisFromPspButton(int btn, int *deviceId, int *axisId, int *direction);
std::string NamePspButtonFromAxis(int deviceId, int axisId, int direction);
diff --git a/Common/LogManager.h b/Common/LogManager.h
index 38ea882062..d7ded3de8e 100644
--- a/Common/LogManager.h
+++ b/Common/LogManager.h
@@ -19,11 +19,11 @@
#include "Log.h"
#include "StringUtils.h"
-#include "Thread.h"
#include "FileUtil.h"
#include "file/ini_file.h"
#include
+#include "StdMutex.h"
#define MAX_MESSAGES 8000
#define MAX_MSGLEN 1024
diff --git a/Common/MathUtil.cpp b/Common/MathUtil.cpp
deleted file mode 100644
index 1e4ef5aac3..0000000000
--- a/Common/MathUtil.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "MathUtil.h"
-
-int GetPow2(int x)
-{
- int ret = 0;
- int val = 1;
- while(x > val)
- {
- ret++;
- val *= 2;
- }
- return ret;
-}
-
diff --git a/Common/MathUtil.h b/Common/MathUtil.h
deleted file mode 100644
index 3ae49b39e1..0000000000
--- a/Common/MathUtil.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _MATH_UTIL_H_
-#define _MATH_UTIL_H_
-
-int GetPow2(int x);
-
-#endif // _MATH_UTIL_H_
diff --git a/Common/MemArena.cpp b/Common/MemArena.cpp
index 327c974c07..f228c6274a 100644
--- a/Common/MemArena.cpp
+++ b/Common/MemArena.cpp
@@ -175,6 +175,12 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
return ptr;
#else
void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |
+// Do not sync memory to underlying file. Linux has this by default.
+#ifdef BLACKBERRY
+ MAP_NOSYNCFILE |
+#elif defined(__FreeBSD__)
+ MAP_NOSYNC |
+#endif
((base == 0) ? 0 : MAP_FIXED), fd, offset);
if (retval == MAP_FAILED)
@@ -216,7 +222,6 @@ u8* MemArena::Find4GBBase()
#else // 32 bit
#ifdef _WIN32
- // The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE);
if (base) {
VirtualFree(base, 0, MEM_RELEASE);
@@ -244,8 +249,6 @@ u8* MemArena::Find4GBBase()
// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
// continue;
-
-
static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
// OK, we know where to find free space. Now grab it!
// We just mimic the popular BAT setup.
@@ -265,6 +268,8 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32
for (i = 0; i < num_views; i++)
{
const MemoryView &view = views[i];
+ if (view.size == 0)
+ continue;
SKIP(flags, view.flags);
if (view.flags & MV_MIRROR_PREVIOUS) {
position = last_position;
@@ -305,6 +310,8 @@ bail:
// Argh! ERROR! Free what we grabbed so far so we can try again.
for (int j = 0; j <= i; j++)
{
+ if (views[i].size == 0)
+ continue;
SKIP(flags, views[i].flags);
if (views[j].out_ptr_low && *views[j].out_ptr_low)
{
@@ -334,6 +341,8 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
for (int i = 0; i < num_views; i++)
{
+ if (views[i].size == 0)
+ continue;
SKIP(flags, views[i].flags);
if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0)
total_mem += roundup(views[i].size);
@@ -384,6 +393,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
u8 *base = MemArena::Find4GBBase();
if (!Memory_TryBase(base, views, num_views, flags, arena))
{
+ ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base.");
PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
return 0;
}
@@ -399,6 +409,8 @@ void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemAr
{
for (int i = 0; i < num_views; i++)
{
+ if (views[i].size == 0)
+ continue;
SKIP(flags, views[i].flags);
if (views[i].out_ptr_low && *views[i].out_ptr_low)
arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
diff --git a/Common/MemArena.h b/Common/MemArena.h
index 79165ad8b4..20093770b7 100644
--- a/Common/MemArena.h
+++ b/Common/MemArena.h
@@ -60,6 +60,8 @@ enum {
// MV_FAKE_VMEM = 2,
// MV_WII_ONLY = 4,
MV_IS_PRIMARY_RAM = 0x100,
+ MV_IS_EXTRA1_RAM = 0x200,
+ MV_IS_EXTRA2_RAM = 0x400,
};
struct MemoryView
diff --git a/Common/MemoryUtil.cpp b/Common/MemoryUtil.cpp
index a263e21eda..0ac3f07aad 100644
--- a/Common/MemoryUtil.cpp
+++ b/Common/MemoryUtil.cpp
@@ -45,10 +45,17 @@
#ifdef __SYMBIAN32__
#include
-#define SYMBIAN_CODECHUNK_SIZE 1024*1024*20;
+#define CODECHUNK_SIZE 1024*1024*20
static RChunk* g_code_chunk = NULL;
static RHeap* g_code_heap = NULL;
-static void* g_next_ptr = NULL;
+static u8* g_next_ptr = NULL;
+static u8* g_orig_ptr = NULL;
+
+void ResetExecutableMemory(void* ptr)
+{
+ // Just reset the ptr to the base
+ g_next_ptr = g_orig_ptr;
+}
#endif
// This is purposely not a full wrapper for virtualalloc/mmap, but it
@@ -63,14 +70,13 @@ void* AllocateExecutableMemory(size_t size, bool low)
//memory chunk for all the executable code for the JIT
if( g_code_chunk == NULL && g_code_heap == NULL)
{
- TInt minsize = SYMBIAN_CODECHUNK_SIZE;
- TInt maxsize = SYMBIAN_CODECHUNK_SIZE + 3*GetPageSize(); //some offsets
g_code_chunk = new RChunk();
- g_code_chunk->CreateLocalCode(minsize, maxsize);
- g_code_heap = UserHeap::ChunkHeap(*g_code_chunk, minsize, 1, maxsize);
- g_next_ptr = (void*) g_code_heap->Alloc( minsize );
+ g_code_chunk->CreateLocalCode(CODECHUNK_SIZE, CODECHUNK_SIZE + 3*GetPageSize());
+ g_code_heap = UserHeap::ChunkHeap(*g_code_chunk, CODECHUNK_SIZE, 1, CODECHUNK_SIZE + 3*GetPageSize());
+ g_next_ptr = reinterpret_cast(g_code_heap->AllocZ(CODECHUNK_SIZE));
+ g_orig_ptr = g_next_ptr;
}
- void* ptr = g_next_ptr;
+ void* ptr = (void*)g_next_ptr;
g_next_ptr += size;
#else
static char *map_hint = 0;
@@ -123,7 +129,7 @@ void* AllocateMemoryPages(size_t size)
#ifdef _WIN32
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
#elif defined(__SYMBIAN32__)
- void* ptr = new u8[size];
+ void* ptr = malloc(size);
#else
void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
#endif
@@ -173,7 +179,7 @@ void FreeMemoryPages(void* ptr, size_t size)
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
ptr = NULL; // Is this our responsibility?
#elif defined(__SYMBIAN32__)
- delete [] ptr;
+ free(ptr);
#else
munmap(ptr, size);
#endif
diff --git a/Common/MemoryUtil.h b/Common/MemoryUtil.h
index 2ae8fea943..67b968a6a4 100644
--- a/Common/MemoryUtil.h
+++ b/Common/MemoryUtil.h
@@ -30,6 +30,9 @@ void* AllocateAlignedMemory(size_t size,size_t alignment);
void FreeAlignedMemory(void* ptr);
void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
+#ifdef __SYMBIAN32__
+void ResetExecutableMemory(void* ptr);
+#endif
inline int GetPageSize() { return 4096; }
diff --git a/Common/StdConditionVariable.h b/Common/StdConditionVariable.h
deleted file mode 100644
index b6ffd5d424..0000000000
--- a/Common/StdConditionVariable.h
+++ /dev/null
@@ -1,153 +0,0 @@
-
-#ifndef CONDITION_VARIABLE_H_
-#define CONDITION_VARIABLE_H_
-
-#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
-#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
-
-#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
-// GCC 4.4 provides
-#include
-#else
-
-// partial std::condition_variable implementation for win32/pthread
-
-#include "StdMutex.h"
-
-#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
-#define USE_RVALUE_REFERENCES
-#endif
-
-#if defined(_WIN32) && defined(_M_X64)
-#define USE_CONDITION_VARIABLES
-#elif defined(_WIN32)
-#define USE_EVENTS
-#endif
-
-namespace std
-{
-
-class condition_variable
-{
-#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
- typedef CONDITION_VARIABLE native_type;
-#elif defined(_WIN32)
- typedef HANDLE native_type;
-#else
- typedef pthread_cond_t native_type;
-#endif
-
-public:
-
-#ifdef USE_EVENTS
- typedef native_type native_handle_type;
-#else
- typedef native_type* native_handle_type;
-#endif
-
- condition_variable()
- {
-#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
- InitializeConditionVariable(&m_handle);
-#elif defined(_WIN32)
- m_handle = CreateEvent(NULL, false, false, NULL);
-#else
- pthread_cond_init(&m_handle, NULL);
-#endif
- }
-
- ~condition_variable()
- {
-#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES)
- CloseHandle(m_handle);
-#elif !defined(_WIN32)
- pthread_cond_destroy(&m_handle);
-#endif
- }
-
- condition_variable(const condition_variable&) /*= delete*/;
- condition_variable& operator=(const condition_variable&) /*= delete*/;
-
- void notify_one()
- {
-#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
- WakeConditionVariable(&m_handle);
-#elif defined(_WIN32)
- SetEvent(m_handle);
-#else
- pthread_cond_signal(&m_handle);
-#endif
- }
-
- void notify_all()
- {
-#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
- WakeAllConditionVariable(&m_handle);
-#elif defined(_WIN32)
- // TODO: broken
- SetEvent(m_handle);
-#else
- pthread_cond_broadcast(&m_handle);
-#endif
- }
-
- void wait(unique_lock& lock)
- {
-#ifdef _WIN32
- #ifdef USE_SRWLOCKS
- SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0);
- #elif defined(USE_CONDITION_VARIABLES)
- SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE);
- #else
- // TODO: broken, the unlock and wait need to be atomic
- lock.unlock();
- WaitForSingleObject(m_handle, INFINITE);
- lock.lock();
- #endif
-#else
- pthread_cond_wait(&m_handle, lock.mutex()->native_handle());
-#endif
- }
-
- template
- void wait(unique_lock& lock, Predicate pred)
- {
- while (!pred())
- wait(lock);
- }
-
- //template
- //cv_status wait_until(unique_lock& lock,
- // const chrono::time_point& abs_time);
-
- //template
- // bool wait_until(unique_lock& lock,
- // const chrono::time_point& abs_time,
- // Predicate pred);
-
- //template
- //cv_status wait_for(unique_lock& lock,
- // const chrono::duration& rel_time);
-
- //template
- // bool wait_for(unique_lock& lock,
- // const chrono::duration& rel_time,
- // Predicate pred);
-
- native_handle_type native_handle()
- {
-#ifdef USE_EVENTS
- return m_handle;
-#else
- return &m_handle;
-#endif
- }
-
-private:
- native_type m_handle;
-};
-
-}
-
-#endif
-#endif
diff --git a/Common/Thread.cpp b/Common/Thread.cpp
deleted file mode 100644
index 2ca3ec08f8..0000000000
--- a/Common/Thread.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "Thread.h"
-#include "Common.h"
-
-#ifdef __APPLE__
-#include
-#elif defined(ANDROID)
-#include
-#elif defined BSD4_4
-#include
-#endif
-
-#ifdef BLACKBERRY
-#include
-#endif
-
-#ifdef USE_BEGINTHREADEX
-#include
-#endif
-
-namespace Common
-{
-
-int CurrentThreadId()
-{
-#ifdef _WIN32
- return GetCurrentThreadId();
-#elif defined __APPLE__
- return mach_thread_self();
-#else
- return pthread_self();
-#endif
-}
-
-#ifdef _WIN32
-
-bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
-{
- return SetThreadAffinityMask(thread, mask) != 0;
-}
-
-bool SetCurrentThreadAffinity(u32 mask)
-{
- return SetThreadAffinityMask(GetCurrentThread(), mask) != 0;
-}
-
-// Supporting functions
-void SleepCurrentThread(int ms)
-{
- Sleep(ms);
-}
-
-void SwitchCurrentThread()
-{
- SwitchToThread();
-}
-
-// Sets the debugger-visible name of the current thread.
-// Uses undocumented (actually, it is now documented) trick.
-// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
-
-// This is implemented much nicer in upcoming msvc++, see:
-// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
-void SetCurrentThreadName(const char* szThreadName)
-{
- static const DWORD MS_VC_EXCEPTION = 0x406D1388;
-
- #pragma pack(push,8)
- struct THREADNAME_INFO
- {
- DWORD dwType; // must be 0x1000
- LPCSTR szName; // pointer to name (in user addr space)
- DWORD dwThreadID; // thread ID (-1=caller thread)
- DWORD dwFlags; // reserved for future use, must be zero
- } info;
- #pragma pack(pop)
-
- info.dwType = 0x1000;
- info.szName = szThreadName;
- info.dwThreadID = -1; //dwThreadID;
- info.dwFlags = 0;
-
- __try
- {
- RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
- }
- __except(EXCEPTION_CONTINUE_EXECUTION)
- {}
-}
-
-void EnableCrashingOnCrashes()
-{
- typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
- typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
- const DWORD EXCEPTION_SWALLOWING = 0x1;
-
- HMODULE kernel32 = LoadLibraryA("kernel32.dll");
- tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32,
- "GetProcessUserModeExceptionPolicy");
- tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32,
- "SetProcessUserModeExceptionPolicy");
- if (pGetPolicy && pSetPolicy)
- {
- DWORD dwFlags;
- if (pGetPolicy(&dwFlags))
- {
- // Turn off the filter
- pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
- }
- }
-}
-
-
-#else // !WIN32, so must be POSIX threads
-
-bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
-{
-#ifdef __APPLE__
- return thread_policy_set(pthread_mach_thread_np(thread),
- THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1) == 0;
-#elif defined(ANDROID) || defined(BLACKBERRY)
- return false;
-#elif (defined __linux__ || defined BSD4_4)
- cpu_set_t cpu_set;
- CPU_ZERO(&cpu_set);
-
- for (int i = 0; i != sizeof(mask) * 8; ++i) {
- if ((mask >> i) & 1)
- CPU_SET(i, &cpu_set);
- }
-
- return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set) == 0;
-#endif
-
- return false;
-}
-
-bool SetCurrentThreadAffinity(u32 mask)
-{
-#ifdef BLACKBERRY
- return ThreadCtl(_NTO_TCTL_RUNMASK, &mask) != -1;
-#elif defined(ANDROID)
- return syscall(__NR_sched_setaffinity, gettid(), sizeof(mask), &mask) == 0;
-#else
- return SetThreadAffinity(pthread_self(), mask);
-#endif
-}
-
-static pthread_key_t threadname_key;
-static pthread_once_t threadname_key_once = PTHREAD_ONCE_INIT;
-
-void SleepCurrentThread(int ms)
-{
- usleep(1000 * ms);
-}
-
-void SwitchCurrentThread()
-{
- usleep(1000 * 1);
-}
-
-static void FreeThreadName(void* threadname)
-{
- free(threadname);
-}
-
-static void ThreadnameKeyAlloc()
-{
- pthread_key_create(&threadname_key, FreeThreadName);
-}
-
-void SetCurrentThreadName(const char* szThreadName)
-{
-#ifdef BLACKBERRY
- pthread_setname_np(pthread_self(), szThreadName);
-#else
- pthread_once(&threadname_key_once, ThreadnameKeyAlloc);
-
- void* threadname;
- if ((threadname = pthread_getspecific(threadname_key)) != NULL)
- free(threadname);
-
- pthread_setspecific(threadname_key, strdup(szThreadName));
-#endif
-
- INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName);
-}
-
-void EnableCrashingOnCrashes()
-{
-
-}
-
-#endif
-
-} // namespace Common
diff --git a/Common/Thread.h b/Common/Thread.h
deleted file mode 100644
index 0726bef34c..0000000000
--- a/Common/Thread.h
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#ifndef _THREAD_H_
-#define _THREAD_H_
-
-#include "thread/thread.h"
-#include "StdConditionVariable.h"
-
-// Don't include common.h here as it will break LogManager
-#include "CommonTypes.h"
-#include
-#include
-
-// This may not be defined outside _WIN32
-#ifndef _WIN32
-#ifndef INFINITE
-#define INFINITE 0xffffffff
-#endif
-
-// Assume !ARM && !MIPS = x86
-#if !defined(ARM) && !defined(MIPS)
-#include
-#endif
-
-//for gettimeofday and struct time(spec|val)
-#include
-#include
-#endif
-
-namespace Common
-{
-
-int CurrentThreadId();
-
-// In Windows 7 SP1 or later, stops Windows from swallowing crashes in WndProcs and other callbacks.
-void EnableCrashingOnCrashes();
-
-bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
-bool SetCurrentThreadAffinity(u32 mask);
-
-class Event
-{
-public:
- Event()
- : is_set(false)
- {};
-
- void Set()
- {
- std::lock_guard lk(m_mutex);
- if (!is_set)
- {
- is_set = true;
- m_condvar.notify_one();
- }
- }
-
- void Wait()
- {
- std::unique_lock lk(m_mutex);
- m_condvar.wait(lk, IsSet(this));
- is_set = false;
- }
-
- void Reset()
- {
- std::unique_lock lk(m_mutex);
- // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration
- is_set = false;
- }
-
-private:
- class IsSet
- {
- public:
- IsSet(const Event* ev)
- : m_event(ev)
- {}
-
- bool operator()()
- {
- return m_event->is_set;
- }
-
- private:
- const Event* const m_event;
- };
-
- volatile bool is_set;
- std::condition_variable m_condvar;
- std::mutex m_mutex;
-};
-
-// TODO: doesn't work on windows with (count > 2)
-class Barrier
-{
-public:
- Barrier(size_t count)
- : m_count(count), m_waiting(0)
- {}
-
- // block until "count" threads call Sync()
- bool Sync()
- {
- std::unique_lock lk(m_mutex);
-
- // TODO: broken when next round of Sync()s
- // is entered before all waiting threads return from the notify_all
-
- if (m_count == ++m_waiting)
- {
- m_waiting = 0;
- m_condvar.notify_all();
- return true;
- }
- else
- {
- m_condvar.wait(lk, IsDoneWating(this));
- return false;
- }
- }
-
-private:
- class IsDoneWating
- {
- public:
- IsDoneWating(const Barrier* bar)
- : m_bar(bar)
- {}
-
- bool operator()()
- {
- return (0 == m_bar->m_waiting);
- }
-
- private:
- const Barrier* const m_bar;
- };
-
- std::condition_variable m_condvar;
- std::mutex m_mutex;
- const size_t m_count;
- volatile size_t m_waiting;
-};
-
-void SleepCurrentThread(int ms);
-void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
-
-// Use this function during a spin-wait to make the current thread
-// relax while another thread is working. This may be more efficient
-// than using events because event functions use kernel calls.
-inline void YieldCPU()
-{
- std::this_thread::yield();
-}
-
-void SetCurrentThreadName(const char *name);
-
-} // namespace Common
-
-#endif // _THREAD_H_
diff --git a/Common/ppcEmitter.h b/Common/ppcEmitter.h
index 45156d09e3..64866b0df1 100644
--- a/Common/ppcEmitter.h
+++ b/Common/ppcEmitter.h
@@ -463,7 +463,7 @@ namespace PpcGen
region_size = 0;
}
- bool IsInSpace(u8 *ptr)
+ bool IsInSpace(const u8 *ptr) const
{
return ptr >= region && ptr < region + region_size;
}
@@ -493,7 +493,7 @@ namespace PpcGen
return region;
}
- size_t GetOffset(u8 *ptr) {
+ size_t GetOffset(const u8 *ptr) const {
return ptr - region;
}
};
diff --git a/Common/x64Emitter.cpp b/Common/x64Emitter.cpp
index 9abc3eff2c..a4e6db829b 100644
--- a/Common/x64Emitter.cpp
+++ b/Common/x64Emitter.cpp
@@ -1371,6 +1371,12 @@ void XEmitter::PSLLQ(X64Reg reg, int shift) {
Write8(shift);
}
+void XEmitter::PSLLDQ(X64Reg reg, int shift) {
+ WriteSSEOp(64, 0x73, true, (X64Reg)7, R(reg));
+ Write8(shift);
+}
+
+
// WARNING not REX compatible
void XEmitter::PSRAW(X64Reg reg, int shift) {
if (reg > 7)
diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h
index ba7c8d0fa1..182a1992d4 100644
--- a/Common/x64Emitter.h
+++ b/Common/x64Emitter.h
@@ -126,7 +126,6 @@ enum
class XEmitter;
-// RIP addressing does not benefit from micro op fusion on Core arch
struct OpArg
{
OpArg() {} // dummy op arg, used for storage
@@ -658,6 +657,8 @@ public:
void PSLLD(X64Reg reg, int shift);
void PSLLQ(X64Reg reg, int shift);
+ void PSLLDQ(X64Reg reg, int shift);
+
void PSRAW(X64Reg reg, int shift);
void PSRAD(X64Reg reg, int shift);
@@ -755,7 +756,7 @@ public:
region_size = 0;
}
- bool IsInSpace(u8 *ptr)
+ bool IsInSpace(const u8 *ptr) const
{
return ptr >= region && ptr < region + region_size;
}
@@ -781,7 +782,7 @@ public:
return region;
}
- size_t GetOffset(u8 *ptr) {
+ size_t GetOffset(const u8 *ptr) const {
return ptr - region;
}
};
diff --git a/Core/Config.cpp b/Core/Config.cpp
index 93be94916b..9661e942c6 100644
--- a/Core/Config.cpp
+++ b/Core/Config.cpp
@@ -17,20 +17,31 @@
#include "base/display.h"
#include "base/NativeApp.h"
+#include "ext/vjson/json.h"
+#include "file/ini_file.h"
+#include "i18n/i18n.h"
+#include "gfx_es2/gpu_features.h"
+#include "net/http_client.h"
+#include "util/text/parsers.h"
+
+#include "Common/CPUDetect.h"
#include "Common/KeyMap.h"
#include "Common/FileUtil.h"
#include "Common/StringUtils.h"
#include "Config.h"
-#include "file/ini_file.h"
-#include "i18n/i18n.h"
-#include "gfx_es2/gpu_features.h"
#include "HLE/sceUtility.h"
-#include "Common/CPUDetect.h"
+
+#ifndef USING_QT_UI
+extern const char *PPSSPP_GIT_VERSION;
+#endif
+
+// TODO: Find a better place for this.
+http::Downloader g_DownloadManager;
Config g_Config;
#ifdef IOS
-extern bool isJailed;
+extern bool iosCanUseJit;
#endif
Config::Config() { }
@@ -52,12 +63,16 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
IniFile::Section *general = iniFile.GetOrCreateSection("General");
general->Get("FirstRun", &bFirstRun, true);
+ general->Get("RunCount", &iRunCount, 0);
+ iRunCount++;
general->Get("Enable Logging", &bEnableLogging, true);
general->Get("AutoRun", &bAutoRun, true);
general->Get("Browse", &bBrowse, false);
general->Get("IgnoreBadMemAccess", &bIgnoreBadMemAccess, true);
general->Get("CurrentDirectory", ¤tDirectory, "");
general->Get("ShowDebuggerOnLoad", &bShowDebuggerOnLoad, false);
+ general->Get("HomebrewStore", &bHomebrewStore, false);
+ general->Get("CheckForNewVersion", &bCheckForNewVersion, true);
if (!File::Exists(currentDirectory))
currentDirectory = "";
@@ -79,13 +94,13 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
general->Get("RewindFlipFrequency", &iRewindFlipFrequency, 0);
general->Get("GridView1", &bGridView1, true);
general->Get("GridView2", &bGridView2, true);
- general->Get("GridView3", &bGridView3, true);
+ general->Get("GridView3", &bGridView3, false);
// "default" means let emulator decide, "" means disable.
general->Get("ReportingHost", &sReportHost, "default");
general->Get("Recent", recentIsos);
general->Get("AutoSaveSymbolMap", &bAutoSaveSymbolMap, false);
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
general->Get("TopMost", &bTopMost);
general->Get("WindowX", &iWindowX, -1); // -1 tells us to center the window.
general->Get("WindowY", &iWindowY, -1);
@@ -118,19 +133,15 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
#ifdef IOS
- cpu->Get("Jit", &bJit, !isJailed);
+ cpu->Get("Jit", &bJit, iosCanUseJit);
#else
cpu->Get("Jit", &bJit, true);
#endif
cpu->Get("SeparateCPUThread", &bSeparateCPUThread, false);
cpu->Get("AtomicAudioLocks", &bAtomicAudioLocks, false);
-#ifdef __SYMBIAN32__
- cpu->Get("SeparateIOThread", &bSeparateIOThread, false);
-#else
cpu->Get("SeparateIOThread", &bSeparateIOThread, true);
-#endif
- cpu->Get("FastMemory", &bFastMemory, false);
+ cpu->Get("FastMemoryAccess", &bFastMemory, true);
cpu->Get("CPUSpeed", &iLockedCPUSpeed, 0);
IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics");
@@ -144,12 +155,13 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
graphics->Get("RenderingMode", &iRenderingMode, renderingModeDefault);
graphics->Get("SoftwareRendering", &bSoftwareRendering, false);
graphics->Get("HardwareTransform", &bHardwareTransform, true);
+ graphics->Get("SoftwareSkinning", &bSoftwareSkinning, true);
graphics->Get("TextureFiltering", &iTexFiltering, 1);
- // Auto on Windows, 1x elsewhere. Maybe change to 2x on large screens?
-#ifdef _WIN32
+ // Auto on Windows, 2x on large screens, 1x elsewhere.
+#if defined(_WIN32) && !defined(USING_QT_UI)
graphics->Get("InternalResolution", &iInternalResolution, 0);
#else
- graphics->Get("InternalResolution", &iInternalResolution, 1);
+ graphics->Get("InternalResolution", &iInternalResolution, pixel_xres >= 1024 ? 2 : 1);
#endif
graphics->Get("FrameSkip", &iFrameSkip, 0);
@@ -169,25 +181,38 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
iAnisotropyLevel = 4;
}
graphics->Get("VertexCache", &bVertexCache, true);
- graphics->Get("VertexDecoderJit", &bVertexDecoderJit, true);
+#ifdef IOS
+ graphics->Get("VertexDecJit", &bVertexDecoderJit, iosCanUseJit);
+#else
+ graphics->Get("VertexDecJit", &bVertexDecoderJit, true);
+#endif
#ifdef _WIN32
graphics->Get("FullScreen", &bFullScreen, false);
#endif
+ bool partialStretchDefault = false;
#ifdef BLACKBERRY
- graphics->Get("PartialStretch", &bPartialStretch, pixel_xres == pixel_yres);
+ partialStretchDefault = pixel_xres < 1.3 * pixel_yres;
#endif
+ graphics->Get("PartialStretch", &bPartialStretch, partialStretchDefault);
graphics->Get("StretchToDisplay", &bStretchToDisplay, false);
graphics->Get("TrueColor", &bTrueColor, true);
- graphics->Get("MipMap", &bMipMap, true);
+
+ graphics->Get("MipMap", &bMipMap, false);
+
graphics->Get("TexScalingLevel", &iTexScalingLevel, 1);
graphics->Get("TexScalingType", &iTexScalingType, 0);
graphics->Get("TexDeposterize", &bTexDeposterize, false);
graphics->Get("VSyncInterval", &bVSync, false);
graphics->Get("DisableStencilTest", &bDisableStencilTest, false);
graphics->Get("AlwaysDepthWrite", &bAlwaysDepthWrite, false);
+// Has been in use on Symbian since v0.7. Preferred option.
+#ifdef __SYMBIAN32__
+ graphics->Get("TimerHack", &bTimerHack, true);
+#else
+ graphics->Get("TimerHack", &bTimerHack, false);
+#endif
graphics->Get("LowQualitySplineBezier", &bLowQualitySplineBezier, false);
- graphics->Get("WipeFramebufferAlpha", &bWipeFramebufferAlpha, false);
graphics->Get("PostShader", &sPostShaderName, "Off");
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
@@ -233,29 +258,47 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
control->Get("TiltInputType", &iTiltInputType, 0);
#endif
+ control->Get("DisableDpadDiagonals", &bDisableDpadDiagonals, false);
+ control->Get("TouchButtonStyle", &iTouchButtonStyle, 1);
control->Get("TouchButtonOpacity", &iTouchButtonOpacity, 65);
- control->Get("ButtonScale", &fButtonScale, 1.15);
//set these to -1 if not initialized. initializing these
//requires pixel coordinates which is not known right now.
//will be initialized in GamepadEmu::CreatePadLayout
- control->Get("ActionButtonSpacing", &iActionButtonSpacing, -1);
+ float defaultScale = 1.15f;
+ control->Get("ActionButtonSpacing2", &fActionButtonSpacing, 1.0f);
control->Get("ActionButtonCenterX", &fActionButtonCenterX, -1.0);
control->Get("ActionButtonCenterY", &fActionButtonCenterY, -1.0);
- control->Get("DPadRadius", &iDpadRadius, -1);
+ control->Get("ActionButtonScale", &fActionButtonScale, defaultScale);
control->Get("DPadX", &fDpadX, -1.0);
control->Get("DPadY", &fDpadY, -1.0);
- control->Get("StartKeyX", &fStartKeyX, -1.0);
- control->Get("StartKeyY", &fStartKeyY, -1.0);
- control->Get("SelectKeyX", &fSelectKeyX, -1.0);
- control->Get("SelectKeyY", &fSelectKeyY, -1.0);
- control->Get("UnthrottleKeyX", &fUnthrottleKeyX, -1.0);
- control->Get("UnthrottleKeyY", &fUnthrottleKeyY, -1.0);
- control->Get("LKeyX", &fLKeyX, -1.0);
- control->Get("LKeyY", &fLKeyY, -1.0);
- control->Get("RKeyX", &fRKeyX, -1.0);
- control->Get("RKeyY", &fRKeyY, -1.0);
- control->Get("AnalogStickX", &fAnalogStickX, -1.0);
- control->Get("AnalogStickY", &fAnalogStickY, -1.0);
+
+ // Check for an old dpad setting
+ float f;
+ control->Get("DPadRadius", &f, 0.0f);
+ if (f > 0.0f) {
+ ResetControlLayout();
+ } else {
+ control->Get("DPadScale", &fDpadScale, defaultScale);
+ control->Get("DPadSpacing", &fDpadSpacing, 1.0f);
+ control->Get("StartKeyX", &fStartKeyX, -1.0);
+ control->Get("StartKeyY", &fStartKeyY, -1.0);
+ control->Get("StartKeyScale", &fStartKeyScale, defaultScale);
+ control->Get("SelectKeyX", &fSelectKeyX, -1.0);
+ control->Get("SelectKeyY", &fSelectKeyY, -1.0);
+ control->Get("SelectKeyScale", &fSelectKeyScale, defaultScale);
+ control->Get("UnthrottleKeyX", &fUnthrottleKeyX, -1.0);
+ control->Get("UnthrottleKeyY", &fUnthrottleKeyY, -1.0);
+ control->Get("UnthrottleKeyScale", &fUnthrottleKeyScale, defaultScale);
+ control->Get("LKeyX", &fLKeyX, -1.0);
+ control->Get("LKeyY", &fLKeyY, -1.0);
+ control->Get("LKeyScale", &fLKeyScale, defaultScale);
+ control->Get("RKeyX", &fRKeyX, -1.0);
+ control->Get("RKeyY", &fRKeyY, -1.0);
+ control->Get("RKeyScale", &fRKeyScale, defaultScale);
+ control->Get("AnalogStickX", &fAnalogStickX, -1.0);
+ control->Get("AnalogStickY", &fAnalogStickY, -1.0);
+ control->Get("AnalogStickScale", &fAnalogStickScale, defaultScale);
+ }
// MIGRATION: For users who had the old static touch layout, aren't I nice?
if (fDpadX > 1.0 || fDpadY > 1.0) // Likely the rest are too!
@@ -277,9 +320,20 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
fAnalogStickX /= dp_xres;
fAnalogStickY /= dp_yres;
}
-
+
+ IniFile::Section *network = iniFile.GetOrCreateSection("Network");
+ network->Get("EnableWlan", &bEnableWlan, false);
+
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
+ pspConfig->Get("PSPModel", &iPSPModel, PSP_MODEL_SLIM);
+ pspConfig->Get("PSPFirmwareVersion", &iFirmwareVersion, PSP_DEFAULT_FIRMWARE);
+#if !defined(_M_X64) && !defined(_WIN32) && !defined(__SYMBIAN32__)
+ // 32-bit mmap cannot map more than 32MB contiguous
+ iPSPModel = PSP_MODEL_FAT;
+#endif
pspConfig->Get("NickName", &sNickName, "PPSSPP");
+ pspConfig->Get("proAdhocServer", &proAdhocServer, "localhost");
+ pspConfig->Get("MacAddress", &localMacAddress, "01:02:03:04:05:06");
pspConfig->Get("Language", &iLanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH);
pspConfig->Get("TimeFormat", &iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR);
pspConfig->Get("DateFormat", &iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD);
@@ -288,7 +342,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
pspConfig->Get("ButtonPreference", &iButtonPreference, PSP_SYSTEMPARAM_BUTTON_CROSS);
pspConfig->Get("LockParentalLevel", &iLockParentalLevel, 0);
pspConfig->Get("WlanAdhocChannel", &iWlanAdhocChannel, PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC);
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
pspConfig->Get("BypassOSKWithKeyboard", &bBypassOSKWithKeyboard, false);
#endif
pspConfig->Get("WlanPowerSave", &bWlanPowerSave, PSP_SYSTEMPARAM_WLAN_POWERSAVE_OFF);
@@ -311,6 +365,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
debugConfig->Get("ShowBottomTabTitles",&bShowBottomTabTitles,true);
debugConfig->Get("ShowDeveloperMenu", &bShowDeveloperMenu, false);
debugConfig->Get("SkipDeadbeefFilling", &bSkipDeadbeefFilling, false);
+ debugConfig->Get("FuncHashMap", &bFuncHashMap, false);
IniFile::Section *speedhacks = iniFile.GetOrCreateSection("SpeedHacks");
speedhacks->Get("PrescaleUV", &bPrescaleUV, false);
@@ -319,6 +374,25 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
IniFile::Section *jitConfig = iniFile.GetOrCreateSection("JIT");
jitConfig->Get("DiscardRegsOnJRRA", &bDiscardRegsOnJRRA, false);
+ IniFile::Section *upgrade = iniFile.GetOrCreateSection("Upgrade");
+ upgrade->Get("UpgradeMessage", &upgradeMessage, "");
+ upgrade->Get("UpgradeVersion", &upgradeVersion, "");
+ upgrade->Get("DismissedVersion", &dismissedVersion, "");
+
+ if (dismissedVersion == upgradeVersion) {
+ upgradeMessage = "";
+ }
+
+ // Check for new version on every 5 runs.
+ // Sometimes the download may not be finished when the main screen shows (if the user dismisses the
+ // splash screen quickly), but then we'll just show the notification next time instead, we store the
+ // upgrade number in the ini.
+ if (iRunCount % 10 == 0 && bCheckForNewVersion) {
+ std::shared_ptr dl = g_DownloadManager.StartDownloadWithCallback(
+ "http://www.ppsspp.org/version.json", "", &DownloadCompletedCallback);
+ dl->SetHidden(true);
+ }
+
INFO_LOG(LOADER, "Loading controller config: %s", controllerIniFilename_.c_str());
bSaveSettings = true;
@@ -343,10 +417,11 @@ void Config::Save() {
}
IniFile::Section *general = iniFile.GetOrCreateSection("General");
-
+
// Need to do this somewhere...
bFirstRun = false;
general->Set("FirstRun", bFirstRun);
+ general->Set("RunCount", iRunCount);
general->Set("Enable Logging", bEnableLogging);
general->Set("AutoRun", bAutoRun);
general->Set("Browse", bBrowse);
@@ -355,7 +430,7 @@ void Config::Save() {
general->Set("ShowDebuggerOnLoad", bShowDebuggerOnLoad);
general->Set("ReportingHost", sReportHost);
general->Set("AutoSaveSymbolMap", bAutoSaveSymbolMap);
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
general->Set("TopMost", bTopMost);
general->Set("WindowX", iWindowX);
general->Set("WindowY", iWindowY);
@@ -373,10 +448,11 @@ void Config::Save() {
general->Set("GridView1", bGridView1);
general->Set("GridView2", bGridView2);
general->Set("GridView3", bGridView3);
-
+ general->Set("CheckForNewVersion", bCheckForNewVersion);
+
IniFile::Section *recent = iniFile.GetOrCreateSection("Recent");
recent->Set("MaxRecent", iMaxRecent);
-
+
for (int i = 0; i < iMaxRecent; i++) {
char keyName[64];
sprintf(keyName,"FileName%d",i);
@@ -384,15 +460,15 @@ void Config::Save() {
recent->Set(keyName, recentIsos[i]);
} else {
recent->Delete(keyName); // delete the nonexisting FileName
- }
+ }
}
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
cpu->Set("Jit", bJit);
cpu->Set("SeparateCPUThread", bSeparateCPUThread);
- cpu->Set("AtomicAudioLocks", bAtomicAudioLocks);
+ cpu->Set("AtomicAudioLocks", bAtomicAudioLocks);
cpu->Set("SeparateIOThread", bSeparateIOThread);
- cpu->Set("FastMemory", bFastMemory);
+ cpu->Set("FastMemoryAccess", bFastMemory);
cpu->Set("CPUSpeed", iLockedCPUSpeed);
IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics");
@@ -400,6 +476,7 @@ void Config::Save() {
graphics->Set("RenderingMode", iRenderingMode);
graphics->Set("SoftwareRendering", bSoftwareRendering);
graphics->Set("HardwareTransform", bHardwareTransform);
+ graphics->Set("SoftwareSkinning", bSoftwareSkinning);
graphics->Set("TextureFiltering", iTexFiltering);
graphics->Set("InternalResolution", iInternalResolution);
graphics->Set("FrameSkip", iFrameSkip);
@@ -408,13 +485,10 @@ void Config::Save() {
graphics->Set("ForceMaxEmulatedFPS", iForceMaxEmulatedFPS);
graphics->Set("AnisotropyLevel", iAnisotropyLevel);
graphics->Set("VertexCache", bVertexCache);
- graphics->Set("VertexDecoderJit", bVertexDecoderJit);
#ifdef _WIN32
graphics->Set("FullScreen", bFullScreen);
-#endif
-#ifdef BLACKBERRY
- graphics->Set("PartialStretch", bPartialStretch);
#endif
+ graphics->Set("PartialStretch", bPartialStretch);
graphics->Set("StretchToDisplay", bStretchToDisplay);
graphics->Set("TrueColor", bTrueColor);
graphics->Set("MipMap", bMipMap);
@@ -424,6 +498,7 @@ void Config::Save() {
graphics->Set("VSyncInterval", bVSync);
graphics->Set("DisableStencilTest", bDisableStencilTest);
graphics->Set("AlwaysDepthWrite", bAlwaysDepthWrite);
+ graphics->Set("TimerHack", bTimerHack);
graphics->Set("LowQualitySplineBezier", bLowQualitySplineBezier);
graphics->Set("PostShader", sPostShaderName);
@@ -448,7 +523,6 @@ void Config::Save() {
control->Set("ShowTouchUnthrottle", bShowTouchUnthrottle);
control->Set("ShowTouchDpad", bShowTouchDpad);
- // control->Set("KeyMapping",iMappingMap);
#ifdef USING_GLES2
control->Set("TiltBaseX", fTiltBaseX);
control->Set("TiltBaseY", fTiltBaseY);
@@ -459,30 +533,46 @@ void Config::Save() {
control->Set("DeadzoneRadius", fDeadzoneRadius);
control->Set("TiltInputType", iTiltInputType);
#endif
+ control->Set("DisableDpadDiagonals", bDisableDpadDiagonals);
+ control->Set("TouchButtonStyle", iTouchButtonStyle);
control->Set("TouchButtonOpacity", iTouchButtonOpacity);
- control->Set("ButtonScale", fButtonScale);
- control->Set("ActionButtonSpacing", iActionButtonSpacing);
+ control->Set("ActionButtonScale", fActionButtonScale);
+ control->Set("ActionButtonSpacing2", fActionButtonSpacing);
control->Set("ActionButtonCenterX", fActionButtonCenterX);
control->Set("ActionButtonCenterY", fActionButtonCenterY);
- control->Set("DPadRadius", iDpadRadius);
control->Set("DPadX", fDpadX);
control->Set("DPadY", fDpadY);
+ control->Set("DPadScale", fDpadScale);
+ control->Set("DPadSpacing", fDpadSpacing);
control->Set("StartKeyX", fStartKeyX);
control->Set("StartKeyY", fStartKeyY);
+ control->Set("StartKeyScale", fStartKeyScale);
control->Set("SelectKeyX", fSelectKeyX);
control->Set("SelectKeyY", fSelectKeyY);
+ control->Set("SelectKeyScale", fSelectKeyScale);
control->Set("UnthrottleKeyX", fUnthrottleKeyX);
control->Set("UnthrottleKeyY", fUnthrottleKeyY);
+ control->Set("UnthrottleKeyScale", fUnthrottleKeyScale);
control->Set("LKeyX", fLKeyX);
control->Set("LKeyY", fLKeyY);
+ control->Set("LKeyScale", fLKeyScale);
control->Set("RKeyX", fRKeyX);
control->Set("RKeyY", fRKeyY);
+ control->Set("RKeyScale", fRKeyScale);
control->Set("AnalogStickX", fAnalogStickX);
control->Set("AnalogStickY", fAnalogStickY);
+ control->Set("AnalogStickScale", fAnalogStickScale);
+ control->Delete("DPadRadius");
+ IniFile::Section *network = iniFile.GetOrCreateSection("Network");
+ network->Set("EnableWlan", bEnableWlan);
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
+ pspConfig->Set("PSPModel", iPSPModel);
+ pspConfig->Set("PSPFirmwareVersion", iFirmwareVersion);
pspConfig->Set("NickName", sNickName.c_str());
+ pspConfig->Set("proAdhocServer", proAdhocServer.c_str());
+ pspConfig->Set("MacAddress", localMacAddress.c_str());
pspConfig->Set("Language", iLanguage);
pspConfig->Set("TimeFormat", iTimeFormat);
pspConfig->Set("DateFormat", iDateFormat);
@@ -493,7 +583,7 @@ void Config::Save() {
pspConfig->Set("WlanAdhocChannel", iWlanAdhocChannel);
pspConfig->Set("WlanPowerSave", bWlanPowerSave);
pspConfig->Set("EncryptSave", bEncryptSave);
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
pspConfig->Set("BypassOSKWithKeyboard", bBypassOSKWithKeyboard);
#endif
@@ -514,11 +604,18 @@ void Config::Save() {
debugConfig->Set("ShowBottomTabTitles",bShowBottomTabTitles);
debugConfig->Set("ShowDeveloperMenu", bShowDeveloperMenu);
debugConfig->Set("SkipDeadbeefFilling", bSkipDeadbeefFilling);
+ debugConfig->Set("FuncHashMap", bFuncHashMap);
IniFile::Section *speedhacks = iniFile.GetOrCreateSection("SpeedHacks");
speedhacks->Set("PrescaleUV", bPrescaleUV);
speedhacks->Set("DisableAlphaTest", bDisableAlphaTest);
+ // Save upgrade check state
+ IniFile::Section *upgrade = iniFile.GetOrCreateSection("Upgrade");
+ upgrade->Set("UpgradeMessage", upgradeMessage);
+ upgrade->Set("UpgradeVersion", upgradeVersion);
+ upgrade->Set("DismissedVersion", dismissedVersion);
+
if (!iniFile.Save(iniFilename_.c_str())) {
ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str());
return;
@@ -542,9 +639,67 @@ void Config::Save() {
}
}
+// Use for debugging the version check without messing with the server
+#if 0
+#define PPSSPP_GIT_VERSION "v0.0.1-gaaaaaaaaa"
+#endif
+
+void Config::DownloadCompletedCallback(http::Download &download) {
+ if (download.ResultCode() != 200) {
+ ERROR_LOG(LOADER, "Failed to download version.json");
+ return;
+ }
+ std::string data;
+ download.buffer().TakeAll(&data);
+ if (data.empty()) {
+ ERROR_LOG(LOADER, "Version check: Empty data from server!");
+ return;
+ }
+
+ JsonReader reader(data.c_str(), data.size());
+ const json_value *root = reader.root();
+ std::string version = root->getString("version", "");
+
+ const char *gitVer = PPSSPP_GIT_VERSION;
+ Version installed(gitVer);
+ Version upgrade(version);
+ Version dismissed(g_Config.dismissedVersion);
+
+ if (!installed.IsValid()) {
+ ERROR_LOG(LOADER, "Version check: Local version string invalid. Build problems? %s", PPSSPP_GIT_VERSION);
+ return;
+ }
+ if (!upgrade.IsValid()) {
+ ERROR_LOG(LOADER, "Version check: Invalid server version: %s", version.c_str());
+ return;
+ }
+
+ if (installed >= upgrade) {
+ INFO_LOG(LOADER, "Version check: Already up to date, erasing any upgrade message");
+ g_Config.upgradeMessage = "";
+ g_Config.upgradeVersion = upgrade.ToString();
+ g_Config.dismissedVersion = "";
+ return;
+ }
+
+ if (installed < upgrade && dismissed != upgrade) {
+ g_Config.upgradeMessage = "New version of PPSSPP available!";
+ g_Config.upgradeVersion = upgrade.ToString();
+ g_Config.dismissedVersion = "";
+ }
+}
+
+void Config::DismissUpgrade() {
+ g_Config.dismissedVersion = g_Config.upgradeVersion;
+}
+
void Config::AddRecent(const std::string &file) {
- for (auto str = recentIsos.begin(); str != recentIsos.end(); str++) {
- if (*str == file) {
+ for (auto str = recentIsos.begin(); str != recentIsos.end(); ++str) {
+#ifdef _WIN32
+ if (!strcmpIgnore((*str).c_str(), file.c_str(), "\\", "/")) {
+#else
+ if (!strcmp((*str).c_str(), file.c_str())) {
+#endif
recentIsos.erase(str);
recentIsos.insert(recentIsos.begin(), file);
if ((int)recentIsos.size() > iMaxRecent)
@@ -560,15 +715,15 @@ void Config::AddRecent(const std::string &file) {
void Config::CleanRecent() {
std::vector cleanedRecent;
for (size_t i = 0; i < recentIsos.size(); i++) {
- if (File::Exists(recentIsos[i])){
+ if (File::Exists(recentIsos[i])) {
// clean the redundant recent games' list.
- if (cleanedRecent.size()==0){ // add first one
- cleanedRecent.push_back(recentIsos[i]);
+ if (cleanedRecent.size()==0) { // add first one
+ cleanedRecent.push_back(recentIsos[i]);
}
- for (size_t j=0; j recentIsos;
std::string sLanguageIni;
+
// GFX
bool bSoftwareRendering;
bool bHardwareTransform; // only used in the GLES backend
+ bool bSoftwareSkinning; // may speed up some games
+
int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering 2 = Read Framebuffer to memory (CPU) 3 = Read Framebuffer to memory (GPU)
int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG)
-#ifdef BLACKBERRY
bool bPartialStretch;
-#endif
bool bStretchToDisplay;
bool bVSync;
int iFrameSkip;
@@ -99,8 +115,8 @@ public:
bool bReloadCheats;
bool bDisableStencilTest;
bool bAlwaysDepthWrite;
+ bool bTimerHack;
bool bLowQualitySplineBezier;
- bool bWipeFramebufferAlpha; // this was meant to be CopyStencilToAlpha but not done yet.
std::string sPostShaderName; // Off for off.
// Sound
@@ -135,26 +151,42 @@ public:
bool bGridView2;
bool bGridView3;
+ // Disable diagonals
+ bool bDisableDpadDiagonals;
+ // Control Style
+ int iTouchButtonStyle;
// Control Positions
int iTouchButtonOpacity;
- float fButtonScale;
//space between PSP buttons
- int iActionButtonSpacing;
//the PSP button's center (triangle, circle, square, cross)
float fActionButtonCenterX, fActionButtonCenterY;
+ float fActionButtonScale;
+ float fActionButtonSpacing;
//radius of the D-pad (PSP cross)
- int iDpadRadius;
+ // int iDpadRadius;
//the D-pad (PSP cross) position
float fDpadX, fDpadY;
+ float fDpadScale;
+ float fDpadSpacing;
//the start key position
float fStartKeyX, fStartKeyY;
- //the select key position;
+ float fStartKeyScale;
+ //the select key position;
float fSelectKeyX, fSelectKeyY;
+ float fSelectKeyScale;
+
float fUnthrottleKeyX, fUnthrottleKeyY;
+ float fUnthrottleKeyScale;
+
float fLKeyX, fLKeyY;
+ float fLKeyScale;
+
float fRKeyX, fRKeyY;
+ float fRKeyScale;
+
//position of the analog stick
float fAnalogStickX, fAnalogStickY;
+ float fAnalogStickScale;
// Controls Visibility
bool bShowTouchControls;
@@ -170,10 +202,10 @@ public:
bool bShowTouchLTrigger;
bool bShowTouchRTrigger;
-
+
bool bShowTouchAnalogStick;
bool bShowTouchDpad;
-
+
bool bHapticFeedback;
// GLES backend-specific hacks. Not saved to the ini file, do not add checkboxes. Will be made into
@@ -193,6 +225,8 @@ public:
// SystemParam
std::string sNickName;
+ std::string proAdhocServer;
+ std::string localMacAddress;
int iLanguage;
int iTimeFormat;
int iDateFormat;
@@ -201,10 +235,16 @@ public:
int iButtonPreference;
int iLockParentalLevel;
bool bEncryptSave;
+
+ // Networking
+ bool bEnableWlan;
int iWlanAdhocChannel;
bool bWlanPowerSave;
+
+ int iPSPModel;
+ int iFirmwareVersion;
// TODO: Make this work with your platform, too!
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
bool bBypassOSKWithKeyboard;
#endif
@@ -226,6 +266,7 @@ public:
bool bShowDeveloperMenu;
// Double edged sword: much easier debugging, but not accurate.
bool bSkipDeadbeefFilling;
+ bool bFuncHashMap;
std::string currentDirectory;
std::string externalDirectory;
@@ -233,6 +274,11 @@ public:
std::string flash0Directory;
std::string internalDataDirectory;
+ // Data for upgrade prompt
+ std::string upgradeMessage; // The actual message from the server is currently not used, need a translation mechanism. So this just acts as a flag.
+ std::string upgradeVersion;
+ std::string dismissedVersion;
+
void Load(const char *iniFileName = "ppsspp.ini", const char *controllerIniFilename = "controls.ini");
void Save();
void RestoreDefaults();
@@ -247,6 +293,11 @@ public:
void AddRecent(const std::string &file);
void CleanRecent();
+ static void DownloadCompletedCallback(http::Download &download);
+ void DismissUpgrade();
+
+ void ResetControlLayout();
+
private:
std::string iniFilename_;
std::string controllerIniFilename_;
@@ -254,4 +305,7 @@ private:
std::string defaultPath_;
};
+// TODO: Find a better place for this.
+extern http::Downloader g_DownloadManager;
extern Config g_Config;
+
diff --git a/Core/Core.cpp b/Core/Core.cpp
index 53db613311..f4064c4f75 100644
--- a/Core/Core.cpp
+++ b/Core/Core.cpp
@@ -145,7 +145,7 @@ void Core_RunLoop() {
while (globalUIState != UISTATE_INGAME && globalUIState != UISTATE_EXIT) {
time_update();
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
double startTime = time_now_d();
UpdateRunLoop();
@@ -164,7 +164,7 @@ void Core_RunLoop() {
while (!coreState && globalUIState == UISTATE_INGAME) {
time_update();
UpdateRunLoop();
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(USING_QT_UI)
if (!Core_IsStepping()) {
GL_SwapBuffers();
}
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 66ebeb938a..3fd32fd53d 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -171,6 +171,7 @@
+
@@ -194,6 +195,7 @@
+
@@ -390,6 +392,7 @@
+
@@ -423,6 +426,7 @@
+
@@ -449,6 +453,7 @@
+
@@ -518,6 +523,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -575,6 +586,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 7e8ba76570..715e6ec4f0 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -496,6 +496,15 @@
Dialog
+
+ Debugger
+
+
+ HLE\Libraries
+
+
+ Util
+
@@ -915,6 +924,18 @@
MIPS\JitCommon
+
+ MIPS\ARM
+
+
+ Debugger
+
+
+ HLE\Libraries
+
+
+ Util
+
@@ -922,4 +943,4 @@
-
\ No newline at end of file
+
diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h
index 2cf0112055..27acc60e36 100644
--- a/Core/CoreParameter.h
+++ b/Core/CoreParameter.h
@@ -33,7 +33,7 @@ enum GPUCore {
// PSP_CoreParameter()
struct CoreParameter {
- CoreParameter() : collectEmuLog(0), unthrottle(false), fpsLimit(0), updateRecent(true) {}
+ CoreParameter() : collectEmuLog(0), unthrottle(false), fpsLimit(0), updateRecent(true), freezeNext(false), frozen(false) {}
CPUCore cpuCore;
GPUCore gpuCore;
bool enableSound; // there aren't multiple sound cores.
@@ -64,4 +64,8 @@ struct CoreParameter {
int fpsLimit;
bool updateRecent;
+
+ // Freeze-frame. For nvidia perfhud profiling. Developers only.
+ bool freezeNext;
+ bool frozen;
};
diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp
index b9867e9908..1d81b248dd 100644
--- a/Core/CoreTiming.cpp
+++ b/Core/CoreTiming.cpp
@@ -24,8 +24,10 @@
#include "Atomics.h"
#include "CoreTiming.h"
#include "Core.h"
+#include "Config.h"
#include "HLE/sceKernelThread.h"
#include "../Common/ChunkFile.h"
+#include "HLE/sceDisplay.h"
int CPU_HZ = 222000000;
@@ -100,14 +102,29 @@ int GetClockFrequencyMHz()
return CPU_HZ / 1000000;
}
+u64 GetGlobalTimeUsScaled()
+{
+ s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
+ int freq = GetClockFrequencyMHz();
+ if (g_Config.bTimerHack) {
+ float vps;
+ __DisplayGetVPS(&vps);
+ if (vps > 4.0f)
+ freq *= (vps / 60.0f);
+ }
+ s64 usSinceLast = ticksSinceLast / freq;
+ return lastGlobalTimeUs + usSinceLast;
+
+}
+
u64 GetGlobalTimeUs()
{
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
- s64 usSinceLast = ticksSinceLast / GetClockFrequencyMHz();
+ int freq = GetClockFrequencyMHz();
+ s64 usSinceLast = ticksSinceLast / freq;
return lastGlobalTimeUs + usSinceLast;
}
-
Event* GetNewEvent()
{
if(!eventPool)
diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h
index 8c53987e3a..03a10f2e05 100644
--- a/Core/CoreTiming.h
+++ b/Core/CoreTiming.h
@@ -80,6 +80,7 @@ namespace CoreTiming
u64 GetTicks();
u64 GetIdleTicks();
u64 GetGlobalTimeUs();
+ u64 GetGlobalTimeUsScaled();
// Returns the event_type identifier.
int RegisterEvent(const char *name, TimedCallback callback);
diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp
index 4d82886c99..2c4ada35f3 100644
--- a/Core/CwCheat.cpp
+++ b/Core/CwCheat.cpp
@@ -114,7 +114,10 @@ void CWCheatEngine::CreateCodeList() { //Creates code list to be used in functio
continue; //Line indicates Disc ID, not needed for cheats
}
if (initialCodesList[i].substr(0,2) == "_G") {
- continue; //Line indicates game Title, also not needed for cheats.
+ continue; //Line indicates game Title, also not needed for cheats
+ }
+ if (initialCodesList[i].substr(0,2) == "//") {
+ continue; //Line indicates comment, also not needed for cheats.
}
if (initialCodesList[i].substr(0,3) == "_C1") {
cheatEnabled = true;
@@ -231,7 +234,7 @@ std::vector CWCheatEngine::GetCodesList() { //Reads the entire chea
}
for (int i = 0; !list.eof(); i ++) {
getline(list, line, '\n');
- if (line.length() > 3 && line.substr(0,1) == "_"){
+ if (line.length() > 3 && (line.substr(0,1) == "_"||line.substr(0,2) == "//")){
codesList.push_back(line);
}
}
diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp
index 48826a095c..fa416b8c3e 100644
--- a/Core/Debugger/Breakpoints.cpp
+++ b/Core/Debugger/Breakpoints.cpp
@@ -324,13 +324,24 @@ const std::vector CBreakPoints::GetBreakpoints()
void CBreakPoints::Update(u32 addr)
{
- if (MIPSComp::jit && Core_IsInactive())
+ if (MIPSComp::jit)
{
+ bool resume = false;
+ if (Core_IsStepping() == false)
+ {
+ Core_EnableStepping(true);
+ Core_WaitInactive();
+ resume = true;
+ }
+
// In case this is a delay slot, clear the previous instruction too.
if (addr != 0)
MIPSComp::jit->ClearCacheAt(addr - 4, 8);
else
MIPSComp::jit->ClearCache();
+
+ if (resume)
+ Core_EnableStepping(false);
}
// Redraw in order to show the breakpoint.
diff --git a/Core/Debugger/DebugInterface.h b/Core/Debugger/DebugInterface.h
index 7a000d4df9..12605c86b5 100644
--- a/Core/Debugger/DebugInterface.h
+++ b/Core/Debugger/DebugInterface.h
@@ -41,8 +41,6 @@ public:
virtual void runToBreakpoint() {}
virtual int getColor(unsigned int address){return 0xFFFFFFFF;}
virtual const char *getDescription(unsigned int address) {return "";}
- virtual const char *findSymbolForAddress(unsigned int address) { return NULL; };
- virtual bool getSymbolValue(char* symbol, u32& dest) { return false; };
virtual bool initExpression(const char* exp, PostfixExpression& dest) { return false; };
virtual bool parseExpression(PostfixExpression& exp, u32& dest) { return false; };
diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp
new file mode 100644
index 0000000000..ac72137c12
--- /dev/null
+++ b/Core/Debugger/DisassemblyManager.cpp
@@ -0,0 +1,1004 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "DisassemblyManager.h"
+#include "DebugInterface.h"
+#include "Core/Debugger/SymbolMap.h"
+#include "Core/MIPS/MIPSCodeUtils.h"
+#include "Core/MIPS/MIPSTables.h"
+#include "Common/Common.h"
+#include "ext/xxhash.h"
+
+#include
+
+std::map DisassemblyManager::entries;
+DebugInterface* DisassemblyManager::cpu;
+int DisassemblyManager::maxParamChars = 29;
+
+bool isInInterval(u32 start, u32 size, u32 value)
+{
+ return start <= value && value <= (start+size-1);
+}
+
+
+static u32 computeHash(u32 address, u32 size)
+{
+ return XXH32(Memory::GetPointer(address),size,0xBACD7814);
+}
+
+
+void parseDisasm(const char* disasm, char* opcode, char* arguments, bool insertSymbols)
+{
+ // copy opcode
+ while (*disasm != 0 && *disasm != '\t')
+ {
+ *opcode++ = *disasm++;
+ }
+ *opcode = 0;
+
+ if (*disasm++ == 0)
+ {
+ *arguments = 0;
+ return;
+ }
+
+ const char* jumpAddress = strstr(disasm,"->$");
+ const char* jumpRegister = strstr(disasm,"->");
+ while (*disasm != 0)
+ {
+ // parse symbol
+ if (disasm == jumpAddress)
+ {
+ u32 branchTarget;
+ sscanf(disasm+3,"%08x",&branchTarget);
+
+ const char* addressSymbol = symbolMap.GetLabelName(branchTarget);
+ if (addressSymbol != NULL && insertSymbols)
+ {
+ arguments += sprintf(arguments,"%s",addressSymbol);
+ } else {
+ arguments += sprintf(arguments,"0x%08X",branchTarget);
+ }
+
+ disasm += 3+8;
+ continue;
+ }
+
+ if (disasm == jumpRegister)
+ disasm += 2;
+
+ if (*disasm == ' ')
+ {
+ disasm++;
+ continue;
+ }
+ *arguments++ = *disasm++;
+ }
+
+ *arguments = 0;
+}
+
+std::map::iterator findDisassemblyEntry(std::map& entries, u32 address, bool exact)
+{
+ if (exact)
+ return entries.find(address);
+
+ if (entries.size() == 0)
+ return entries.end();
+
+ // find first elem that's >= address
+ auto it = entries.lower_bound(address);
+ if (it != entries.end())
+ {
+ // it may be an exact match
+ if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))
+ return it;
+
+ // otherwise it may point to the next
+ if (it != entries.begin())
+ {
+ it--;
+ if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))
+ return it;
+ }
+ }
+
+ // check last entry manually
+ auto rit = entries.rbegin();
+ if (isInInterval(rit->second->getLineAddress(0),rit->second->getTotalSize(),address))
+ {
+ return (++rit).base();
+ }
+
+ // no match otherwise
+ return entries.end();
+}
+
+void DisassemblyManager::analyze(u32 address, u32 size = 1024)
+{
+ u32 end = address+size;
+
+ address &= ~3;
+ u32 start = address;
+
+ while (address < end && start <= address)
+ {
+ if (!PSP_IsInited())
+ return;
+
+ auto it = findDisassemblyEntry(entries,address,false);
+ if (it != entries.end())
+ {
+ DisassemblyEntry* entry = it->second;
+ entry->recheck();
+ address = entry->getLineAddress(0)+entry->getTotalSize();
+ continue;
+ }
+
+ SymbolInfo info;
+ if (!symbolMap.GetSymbolInfo(&info,address,ST_ALL))
+ {
+ if (address % 4)
+ {
+ u32 next = std::min((address+3) & ~3,symbolMap.GetNextSymbolAddress(address,ST_ALL));
+ DisassemblyData* data = new DisassemblyData(address,next-address,DATATYPE_BYTE);
+ entries[address] = data;
+ address = next;
+ continue;
+ }
+
+ u32 next = symbolMap.GetNextSymbolAddress(address,ST_ALL);
+
+ if ((next % 4) && next != -1)
+ {
+ u32 alignedNext = next & ~3;
+
+ if (alignedNext != address)
+ {
+ DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(alignedNext-address)/4);
+ entries[address] = opcode;
+ }
+
+ DisassemblyData* data = new DisassemblyData(address,next-alignedNext,DATATYPE_BYTE);
+ entries[alignedNext] = data;
+ } else {
+ DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(next-address)/4);
+ entries[address] = opcode;
+ }
+
+ address = next;
+ continue;
+ }
+
+ switch (info.type)
+ {
+ case ST_FUNCTION:
+ {
+ DisassemblyFunction* function = new DisassemblyFunction(info.address,info.size);
+ entries[info.address] = function;
+ address = info.address+info.size;
+ }
+ break;
+ case ST_DATA:
+ {
+ DisassemblyData* data = new DisassemblyData(info.address,info.size,symbolMap.GetDataType(info.address));
+ entries[info.address] = data;
+ address = info.address+info.size;
+ }
+ break;
+ }
+ }
+
+}
+
+std::vector DisassemblyManager::getBranchLines(u32 start, u32 size)
+{
+ std::vector result;
+
+ auto it = findDisassemblyEntry(entries,start,false);
+ if (it != entries.end())
+ {
+ do
+ {
+ it->second->getBranchLines(start,size,result);
+ it++;
+ } while (it != entries.end() && start+size > it->second->getLineAddress(0));
+ }
+
+ return result;
+}
+
+void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest)
+{
+ auto it = findDisassemblyEntry(entries,address,false);
+ if (it == entries.end())
+ {
+ analyze(address);
+ it = findDisassemblyEntry(entries,address,false);
+
+ if (it == entries.end())
+ {
+ if (address % 4)
+ dest.totalSize = ((address+3) & ~3)-address;
+ else
+ dest.totalSize = 4;
+ dest.name = "ERROR";
+ dest.params = "Disassembly failure";
+ return;
+ }
+ }
+
+ DisassemblyEntry* entry = it->second;
+ if (entry->disassemble(address,dest,insertSymbols))
+ return;
+
+ if (address % 4)
+ dest.totalSize = ((address+3) & ~3)-address;
+ else
+ dest.totalSize = 4;
+ dest.name = "ERROR";
+ dest.params = "Disassembly failure";
+}
+
+u32 DisassemblyManager::getStartAddress(u32 address)
+{
+ auto it = findDisassemblyEntry(entries,address,false);
+ if (it == entries.end())
+ {
+ analyze(address);
+ it = findDisassemblyEntry(entries,address,false);
+ if (it == entries.end())
+ return address;
+ }
+
+ DisassemblyEntry* entry = it->second;
+ int line = entry->getLineNum(address,true);
+ return entry->getLineAddress(line);
+}
+
+u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n)
+{
+ while (Memory::IsValidAddress(address))
+ {
+ auto it = findDisassemblyEntry(entries,address,false);
+
+ while (it != entries.end())
+ {
+ DisassemblyEntry* entry = it->second;
+ int oldLineNum = entry->getLineNum(address,true);
+ int oldNumLines = entry->getNumLines();
+ if (n <= oldLineNum)
+ {
+ return entry->getLineAddress(oldLineNum-n);
+ }
+
+ address = entry->getLineAddress(0)-1;
+ n -= oldLineNum+1;
+ it = findDisassemblyEntry(entries,address,false);
+ }
+
+ analyze(address-127,128);
+ }
+
+ return address-n*4;
+}
+
+u32 DisassemblyManager::getNthNextAddress(u32 address, int n)
+{
+ while (Memory::IsValidAddress(address))
+ {
+ auto it = findDisassemblyEntry(entries,address,false);
+
+ while (it != entries.end())
+ {
+ DisassemblyEntry* entry = it->second;
+ int oldLineNum = entry->getLineNum(address,true);
+ int oldNumLines = entry->getNumLines();
+ if (oldLineNum+n < oldNumLines)
+ {
+ return entry->getLineAddress(oldLineNum+n);
+ }
+
+ address = entry->getLineAddress(0)+entry->getTotalSize();
+ n -= (oldNumLines-oldLineNum);
+ it = findDisassemblyEntry(entries,address,false);
+ }
+
+ analyze(address);
+ }
+
+ return address+n*4;
+}
+
+void DisassemblyManager::clear()
+{
+ for (auto it = entries.begin(); it != entries.end(); it++)
+ {
+ delete it->second;
+ }
+ entries.clear();
+}
+
+DisassemblyFunction::DisassemblyFunction(u32 _address, u32 _size): address(_address), size(_size)
+{
+ hash = computeHash(address,size);
+ load();
+}
+
+void DisassemblyFunction::recheck()
+{
+ u32 newHash = computeHash(address,size);
+ if (hash != newHash)
+ {
+ hash = newHash;
+ clear();
+ load();
+ }
+}
+
+int DisassemblyFunction::getNumLines()
+{
+ return (int) lineAddresses.size();
+}
+
+int DisassemblyFunction::getLineNum(u32 address, bool findStart)
+{
+ if (findStart)
+ {
+ int last = (int)lineAddresses.size() - 1;
+ for (int i = 0; i < last; i++)
+ {
+ u32 next = lineAddresses[i + 1];
+ if (lineAddresses[i] <= address && next > address)
+ return i;
+ }
+ if (lineAddresses[last] <= address && this->address + this->size > address)
+ return last;
+ }
+ else
+ {
+ int last = (int)lineAddresses.size() - 1;
+ for (int i = 0; i < last; i++)
+ {
+ u32 next = lineAddresses[i + 1];
+ if (lineAddresses[i] == address)
+ return i;
+ }
+ if (lineAddresses[last] == address)
+ return last;
+ }
+
+ return 0;
+}
+
+u32 DisassemblyFunction::getLineAddress(int line)
+{
+ return lineAddresses[line];
+}
+
+bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
+{
+ auto it = findDisassemblyEntry(entries,address,false);
+ if (it == entries.end())
+ return false;
+
+ return it->second->disassemble(address,dest,insertSymbols);
+}
+
+void DisassemblyFunction::getBranchLines(u32 start, u32 size, std::vector& dest)
+{
+ u32 end = start+size;
+
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ BranchLine& line = lines[i];
+
+ u32 first = line.first;
+ u32 second = line.second;
+
+ // skip branches that are entirely before or entirely after the window
+ if ((first < start && second < start) ||
+ (first > end && second > end))
+ continue;
+
+ dest.push_back(line);
+ }
+}
+
+#define NUM_LANES 16
+
+void DisassemblyFunction::generateBranchLines()
+{
+ struct LaneInfo
+ {
+ bool used;
+ u32 end;
+ };
+
+ LaneInfo lanes[NUM_LANES];
+ for (int i = 0; i < NUM_LANES; i++)
+ lanes[i].used = false;
+
+ u32 end = address+size;
+
+ DebugInterface* cpu = DisassemblyManager::getCpu();
+ for (u32 funcPos = address; funcPos < end; funcPos += 4)
+ {
+ MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
+
+ bool inFunction = (opInfo.branchTarget >= address && opInfo.branchTarget < end);
+ if (opInfo.isBranch && !opInfo.isBranchToRegister && !opInfo.isLinkedBranch && inFunction)
+ {
+ BranchLine line;
+ if (opInfo.branchTarget < funcPos)
+ {
+ line.first = opInfo.branchTarget;
+ line.second = funcPos;
+ line.type = LINE_UP;
+ } else {
+ line.first = funcPos;
+ line.second = opInfo.branchTarget;
+ line.type = LINE_DOWN;
+ }
+
+ lines.push_back(line);
+ }
+ }
+
+ std::sort(lines.begin(),lines.end());
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ for (int l = 0; l < NUM_LANES; l++)
+ {
+ if (lines[i].first > lanes[l].end)
+ lanes[l].used = false;
+ }
+
+ int lane = -1;
+ for (int l = 0; l < NUM_LANES; l++)
+ {
+ if (lanes[l].used == false)
+ {
+ lane = l;
+ break;
+ }
+ }
+
+ if (lane == -1)
+ {
+ // error
+ continue;
+ }
+
+ lanes[lane].end = lines[i].second;
+ lanes[lane].used = true;
+ lines[i].laneIndex = lane;
+ }
+}
+
+void DisassemblyFunction::addOpcodeSequence(u32 start, u32 end)
+{
+ DisassemblyOpcode* opcode = new DisassemblyOpcode(start,(end-start)/4);
+ entries[start] = opcode;
+ for (u32 pos = start; pos < end; pos += 4)
+ {
+ lineAddresses.push_back(pos);
+ }
+}
+
+void DisassemblyFunction::load()
+{
+ generateBranchLines();
+
+ // gather all branch targets
+ std::set branchTargets;
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ switch (lines[i].type)
+ {
+ case LINE_DOWN:
+ branchTargets.insert(lines[i].second);
+ break;
+ case LINE_UP:
+ branchTargets.insert(lines[i].first);
+ break;
+ }
+ }
+
+ DebugInterface* cpu = DisassemblyManager::getCpu();
+ u32 funcPos = address;
+ u32 funcEnd = address+size;
+
+ u32 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
+ u32 opcodeSequenceStart = funcPos;
+ while (funcPos < funcEnd)
+ {
+ if (funcPos == nextData)
+ {
+ if (opcodeSequenceStart != funcPos)
+ addOpcodeSequence(opcodeSequenceStart,funcPos);
+
+ DisassemblyData* data = new DisassemblyData(funcPos,symbolMap.GetDataSize(funcPos),symbolMap.GetDataType(funcPos));
+ entries[funcPos] = data;
+ lineAddresses.push_back(funcPos);
+ funcPos += data->getTotalSize();
+
+ nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
+ opcodeSequenceStart = funcPos;
+ continue;
+ }
+
+ // force align
+ if (funcPos % 4)
+ {
+ u32 nextPos = (funcPos+3) & ~3;
+
+ DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4");
+ entries[funcPos] = comment;
+ lineAddresses.push_back(funcPos);
+
+ funcPos = nextPos;
+ opcodeSequenceStart = funcPos;
+ continue;
+ }
+
+ MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
+ u32 opAddress = funcPos;
+ funcPos += 4;
+
+ // skip branches and their delay slots
+ if (opInfo.isBranch)
+ {
+ funcPos += 4;
+ continue;
+ }
+
+ // lui
+ if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)
+ {
+ MIPSOpcode next = Memory::Read_Instruction(funcPos);
+ MIPSInfo nextInfo = MIPSGetInfo(next);
+
+ u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next.encoding & 0xFFFF);
+ int rt = MIPS_GET_RT(opInfo.encodedOpcode);
+
+ int nextRs = MIPS_GET_RS(next.encoding);
+ int nextRt = MIPS_GET_RT(next.encoding);
+
+ // both rs and rt of the second op have to match rt of the first,
+ // otherwise there may be hidden consequences if the macro is displayed.
+ // also, don't create a macro if something branches into the middle of it
+ if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())
+ {
+ DisassemblyMacro* macro = NULL;
+ switch (MIPS_GET_OP(next.encoding))
+ {
+ case 0x09: // addiu
+ macro = new DisassemblyMacro(opAddress);
+ macro->setMacroLi(immediate,rt);
+ funcPos += 4;
+ break;
+ case 0x20: // lb
+ case 0x21: // lh
+ case 0x23: // lw
+ case 0x24: // lbu
+ case 0x25: // lhu
+ case 0x28: // sb
+ case 0x29: // sh
+ case 0x2B: // sw
+ macro = new DisassemblyMacro(opAddress);
+
+ int dataSize;
+ switch (nextInfo & MEMTYPE_MASK) {
+ case MEMTYPE_BYTE:
+ dataSize = 1;
+ break;
+ case MEMTYPE_HWORD:
+ dataSize = 2;
+ break;
+ case MEMTYPE_WORD:
+ case MEMTYPE_FLOAT:
+ dataSize = 4;
+ break;
+ case MEMTYPE_VQUAD:
+ dataSize = 16;
+ break;
+ }
+
+ macro->setMacroMemory(MIPSGetName(next),immediate,rt,dataSize);
+ funcPos += 4;
+ break;
+ }
+
+ if (macro != NULL)
+ {
+ if (opcodeSequenceStart != opAddress)
+ addOpcodeSequence(opcodeSequenceStart,opAddress);
+
+ entries[opAddress] = macro;
+ for (int i = 0; i < macro->getNumLines(); i++)
+ {
+ lineAddresses.push_back(macro->getLineAddress(i));
+ }
+
+ opcodeSequenceStart = funcPos;
+ continue;
+ }
+ }
+ }
+
+ // just a normal opcode
+ }
+
+ if (opcodeSequenceStart != funcPos)
+ addOpcodeSequence(opcodeSequenceStart,funcPos);
+}
+
+void DisassemblyFunction::clear()
+{
+ for (auto it = entries.begin(); it != entries.end(); it++)
+ {
+ delete it->second;
+ }
+
+ entries.clear();
+ lines.clear();
+ lineAddresses.clear();
+ hash = 0;
+}
+
+bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
+{
+ char opcode[64],arguments[256];
+ const char *dizz = DisassemblyManager::getCpu()->disasm(address,4);
+ parseDisasm(dizz,opcode,arguments,insertSymbols);
+ dest.type = DISTYPE_OPCODE;
+ dest.name = opcode;
+ dest.params = arguments;
+ dest.totalSize = 4;
+ dest.info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),address);
+ return true;
+}
+
+void DisassemblyOpcode::getBranchLines(u32 start, u32 size, std::vector& dest)
+{
+ if (start < address)
+ {
+ size = start+size-address;
+ start = address;
+ }
+
+ if (start+size > address+num*4)
+ size = address+num*4-start;
+
+ int lane = 0;
+ for (u32 pos = start; pos < start+size; pos += 4)
+ {
+ MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),pos);
+ if (info.isBranch && !info.isBranchToRegister && !info.isLinkedBranch)
+ {
+ BranchLine line;
+ line.laneIndex = lane++;
+
+ if (info.branchTarget < pos)
+ {
+ line.first = info.branchTarget;
+ line.second = pos;
+ line.type = LINE_UP;
+ } else {
+ line.first = pos;
+ line.second = info.branchTarget;
+ line.type = LINE_DOWN;
+ }
+
+ dest.push_back(line);
+ }
+ }
+}
+
+
+void DisassemblyMacro::setMacroLi(u32 _immediate, u8 _rt)
+{
+ type = MACRO_LI;
+ name = "li";
+ immediate = _immediate;
+ rt = _rt;
+ numOpcodes = 2;
+}
+
+void DisassemblyMacro::setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize)
+{
+ type = MACRO_MEMORYIMM;
+ name = _name;
+ immediate = _immediate;
+ rt = _rt;
+ dataSize = _dataSize;
+ numOpcodes = 2;
+}
+
+bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
+{
+ char buffer[64];
+ dest.type = DISTYPE_MACRO;
+ dest.info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),address);
+
+ const char* addressSymbol;
+ switch (type)
+ {
+ case MACRO_LI:
+ dest.name = name;
+
+ addressSymbol = symbolMap.GetLabelName(immediate);
+ if (addressSymbol != NULL && insertSymbols)
+ {
+ sprintf(buffer,"%s,%s",DisassemblyManager::getCpu()->GetRegName(0,rt),addressSymbol);
+ } else {
+ sprintf(buffer,"%s,0x%08X",DisassemblyManager::getCpu()->GetRegName(0,rt),immediate);
+ }
+
+ dest.params = buffer;
+
+ dest.info.hasRelevantAddress = true;
+ dest.info.releventAddress = immediate;
+ break;
+ case MACRO_MEMORYIMM:
+ dest.name = name;
+
+ addressSymbol = symbolMap.GetLabelName(immediate);
+ if (addressSymbol != NULL && insertSymbols)
+ {
+ sprintf(buffer,"%s,%s",DisassemblyManager::getCpu()->GetRegName(0,rt),addressSymbol);
+ } else {
+ sprintf(buffer,"%s,0x%08X",DisassemblyManager::getCpu()->GetRegName(0,rt),immediate);
+ }
+
+ dest.params = buffer;
+
+ dest.info.isDataAccess = true;
+ dest.info.dataAddress = immediate;
+ dest.info.dataSize = dataSize;
+
+ dest.info.hasRelevantAddress = true;
+ dest.info.releventAddress = immediate;
+ break;
+ default:
+ return false;
+ }
+
+ dest.totalSize = getTotalSize();
+ return true;
+}
+
+
+DisassemblyData::DisassemblyData(u32 _address, u32 _size, DataType _type): address(_address), size(_size), type(_type)
+{
+ hash = computeHash(address,size);
+ createLines();
+}
+
+void DisassemblyData::recheck()
+{
+ u32 newHash = computeHash(address,size);
+ if (newHash != hash)
+ {
+ hash = newHash;
+ createLines();
+ }
+}
+
+bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
+{
+ dest.type = DISTYPE_DATA;
+
+ switch (type)
+ {
+ case DATATYPE_BYTE:
+ dest.name = ".byte";
+ break;
+ case DATATYPE_HALFWORD:
+ dest.name = ".half";
+ break;
+ case DATATYPE_WORD:
+ dest.name = ".word";
+ break;
+ case DATATYPE_ASCII:
+ dest.name = ".ascii";
+ break;
+ default:
+ return false;
+ }
+
+ auto it = lines.find(address);
+ if (it == lines.end())
+ return false;
+
+ dest.params = it->second.text;
+ dest.totalSize = it->second.size;
+ return true;
+}
+
+int DisassemblyData::getLineNum(u32 address, bool findStart)
+{
+ auto it = lines.upper_bound(address);
+ if (it != lines.end())
+ {
+ if (it == lines.begin())
+ return 0;
+ it--;
+ return it->second.lineNum;
+ }
+
+ return lines.rbegin()->second.lineNum;
+}
+
+void DisassemblyData::createLines()
+{
+ lines.clear();
+ lineAddresses.clear();
+
+ u32 pos = address;
+ u32 end = address+size;
+ u32 maxChars = DisassemblyManager::getMaxParamChars();
+
+ std::string currentLine;
+ u32 currentLineStart = pos;
+
+ int lineCount = 0;
+ if (type == DATATYPE_ASCII)
+ {
+ bool inString = false;
+ while (pos < end)
+ {
+ u8 b = Memory::Read_U8(pos++);
+ if (b >= 0x20 && b <= 0x7F)
+ {
+ if (currentLine.size()+1 >= maxChars)
+ {
+ if (inString == true)
+ currentLine += "\"";
+
+ DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};
+ lines[currentLineStart] = entry;
+ lineAddresses.push_back(currentLineStart);
+
+ currentLine = "";
+ currentLineStart = pos-1;
+ inString = false;
+ }
+
+ if (inString == false)
+ currentLine += "\"";
+ currentLine += (char)b;
+ inString = true;
+ } else {
+ char buffer[64];
+ if (pos == end && b == 0)
+ strcpy(buffer,"0");
+ else
+ sprintf(buffer,"0x%02X",b);
+
+ if (currentLine.size()+strlen(buffer) >= maxChars)
+ {
+ if (inString == true)
+ currentLine += "\"";
+
+ DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};
+ lines[currentLineStart] = entry;
+ lineAddresses.push_back(currentLineStart);
+
+ currentLine = "";
+ currentLineStart = pos-1;
+ inString = false;
+ }
+
+ bool comma = false;
+ if (currentLine.size() != 0)
+ comma = true;
+
+ if (inString)
+ currentLine += "\"";
+
+ if (comma)
+ currentLine += ",";
+
+ currentLine += buffer;
+ inString = false;
+ }
+ }
+
+ if (inString == true)
+ currentLine += "\"";
+
+ if (currentLine.size() != 0)
+ {
+ DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};
+ lines[currentLineStart] = entry;
+ lineAddresses.push_back(currentLineStart);
+ }
+ } else {
+ while (pos < end)
+ {
+ char buffer[64];
+ u32 value;
+
+ u32 currentPos = pos;
+
+ switch (type)
+ {
+ case DATATYPE_BYTE:
+ value = Memory::Read_U8(pos);
+ sprintf(buffer,"0x%02X",value);
+ pos++;
+ break;
+ case DATATYPE_HALFWORD:
+ value = Memory::Read_U16(pos);
+ sprintf(buffer,"0x%04X",value);
+ pos += 2;
+ break;
+ case DATATYPE_WORD:
+ {
+ value = Memory::Read_U32(pos);
+ const char* label = symbolMap.GetLabelName(value);
+ if (label != NULL)
+ sprintf(buffer,"%s",label);
+ else
+ sprintf(buffer,"0x%08X",value);
+ pos += 4;
+ }
+ break;
+ }
+
+ size_t len = strlen(buffer);
+ if (currentLine.size() != 0 && currentLine.size()+len >= maxChars)
+ {
+ DataEntry entry = {currentLine,currentPos-currentLineStart,lineCount++};
+ lines[currentLineStart] = entry;
+ lineAddresses.push_back(currentLineStart);
+
+ currentLine = "";
+ currentLineStart = currentPos;
+ }
+
+ if (currentLine.size() != 0)
+ currentLine += ",";
+ currentLine += buffer;
+ }
+
+ if (currentLine.size() != 0)
+ {
+ DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};
+ lines[currentLineStart] = entry;
+ lineAddresses.push_back(currentLineStart);
+ }
+ }
+}
+
+
+DisassemblyComment::DisassemblyComment(u32 _address, u32 _size, std::string _name, std::string _param)
+ : address(_address), size(_size), name(_name), param(_param)
+{
+
+}
+
+bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
+{
+ dest.type = DISTYPE_OTHER;
+ dest.name = name;
+ dest.params = param;
+ dest.totalSize = size;
+ return true;
+}
diff --git a/Core/Debugger/DisassemblyManager.h b/Core/Debugger/DisassemblyManager.h
new file mode 100644
index 0000000000..ae1847dcdc
--- /dev/null
+++ b/Core/Debugger/DisassemblyManager.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+#include "Globals.h"
+#include "Core/MIPS/MIPSAnalyst.h"
+
+enum DisassemblyLineType { DISTYPE_OPCODE, DISTYPE_MACRO, DISTYPE_DATA, DISTYPE_OTHER };
+
+struct DisassemblyLineInfo
+{
+ DisassemblyLineType type;
+ MIPSAnalyst::MipsOpcodeInfo info;
+ std::string name;
+ std::string params;
+ u32 totalSize;
+};
+
+enum LineType { LINE_UP, LINE_DOWN, LINE_RIGHT };
+
+struct BranchLine
+{
+ u32 first;
+ u32 second;
+ LineType type;
+ int laneIndex;
+
+ bool operator<(const BranchLine& other) const
+ {
+ return first < other.first;
+ }
+};
+
+class DisassemblyEntry
+{
+public:
+ virtual ~DisassemblyEntry() { };
+ virtual void recheck() = 0;
+ virtual int getNumLines() = 0;
+ virtual int getLineNum(u32 address, bool findStart) = 0;
+ virtual u32 getLineAddress(int line) = 0;
+ virtual u32 getTotalSize() = 0;
+ virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) = 0;
+ virtual void getBranchLines(u32 start, u32 size, std::vector& dest) { };
+};
+
+class DisassemblyFunction: public DisassemblyEntry
+{
+public:
+ DisassemblyFunction(u32 _address, u32 _size);
+ virtual void recheck();
+ virtual int getNumLines();
+ virtual int getLineNum(u32 address, bool findStart);
+ virtual u32 getLineAddress(int line);
+ virtual u32 getTotalSize() { return size; };
+ virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
+ virtual void getBranchLines(u32 start, u32 size, std::vector& dest);
+private:
+ void generateBranchLines();
+ void load();
+ void clear();
+ void addOpcodeSequence(u32 start, u32 end);
+
+ u32 address;
+ u32 size;
+ u32 hash;
+ std::vector lines;
+ std::map entries;
+ std::vector lineAddresses;
+};
+
+class DisassemblyOpcode: public DisassemblyEntry
+{
+public:
+ DisassemblyOpcode(u32 _address, int _num): address(_address), num(_num) { };
+ virtual ~DisassemblyOpcode() { };
+ virtual void recheck() { };
+ virtual int getNumLines() { return num; };
+ virtual int getLineNum(u32 address, bool findStart) { return (address-this->address)/4; };
+ virtual u32 getLineAddress(int line) { return address+line*4; };
+ virtual u32 getTotalSize() { return num*4; };
+ virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
+ virtual void getBranchLines(u32 start, u32 size, std::vector& dest);
+private:
+ u32 address;
+ int num;
+};
+
+
+class DisassemblyMacro: public DisassemblyEntry
+{
+public:
+ DisassemblyMacro(u32 _address): address(_address) { };
+ virtual ~DisassemblyMacro() { };
+
+ void setMacroLi(u32 _immediate, u8 _rt);
+ void setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize);
+
+ virtual void recheck() { };
+ virtual int getNumLines() { return 1; };
+ virtual int getLineNum(u32 address, bool findStart) { return 0; };
+ virtual u32 getLineAddress(int line) { return address; };
+ virtual u32 getTotalSize() { return numOpcodes*4; };
+ virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) ;
+private:
+ enum MacroType { MACRO_LI, MACRO_MEMORYIMM };
+
+ MacroType type;
+ std::string name;
+ u32 immediate;
+ u32 address;
+ u32 numOpcodes;
+ u8 rt;
+ int dataSize;
+};
+
+
+class DisassemblyData: public DisassemblyEntry
+{
+public:
+ DisassemblyData(u32 _address, u32 _size, DataType _type);
+ virtual ~DisassemblyData() { };
+
+ virtual void recheck();
+ virtual int getNumLines() { return (int)lines.size(); };
+ virtual int getLineNum(u32 address, bool findStart);
+ virtual u32 getLineAddress(int line) { return lineAddresses[line]; };
+ virtual u32 getTotalSize() { return size; };
+ virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
+private:
+ void createLines();
+
+ struct DataEntry
+ {
+ std::string text;
+ u32 size;
+ int lineNum;
+ };
+
+ u32 address;
+ u32 size;
+ u32 hash;
+ DataType type;
+ std::map lines;
+ std::vector lineAddresses;
+};
+
+class DisassemblyComment: public DisassemblyEntry
+{
+public:
+ DisassemblyComment(u32 _address, u32 _size, std::string name, std::string param);
+ virtual ~DisassemblyComment() { };
+
+ virtual void recheck() { };
+ virtual int getNumLines() { return 1; };
+ virtual int getLineNum(u32 address, bool findStart) { return 0; };
+ virtual u32 getLineAddress(int line) { return address; };
+ virtual u32 getTotalSize() { return size; };
+ virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
+private:
+ u32 address;
+ u32 size;
+ std::string name;
+ std::string param;
+};
+
+class DebugInterface;
+
+class DisassemblyManager
+{
+public:
+ void clear();
+
+ void setCpu(DebugInterface* _cpu) { cpu = _cpu; };
+ void setMaxParamChars(int num) { maxParamChars = num; clear(); };
+ void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest);
+ void analyze(u32 address, u32 size);
+ std::vector getBranchLines(u32 start, u32 size);
+
+ u32 getStartAddress(u32 address);
+ u32 getNthPreviousAddress(u32 address, int n = 1);
+ u32 getNthNextAddress(u32 address, int n = 1);
+
+ static DebugInterface* getCpu() { return cpu; };
+ static int getMaxParamChars() { return maxParamChars; };
+private:
+ DisassemblyEntry* getEntry(u32 address);
+ static std::map entries;
+ static DebugInterface* cpu;
+ static int maxParamChars;
+};
+
+bool isInInterval(u32 start, u32 size, u32 value);
\ No newline at end of file
diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp
index 3c3c7940f7..1482cd4d22 100644
--- a/Core/Debugger/SymbolMap.cpp
+++ b/Core/Debugger/SymbolMap.cpp
@@ -31,109 +31,20 @@
SymbolMap symbolMap;
-//need improvement
-static u32 hasher(u32 last, u32 value)
-{
- return __rotl(last,3) ^ value;
-}
-
-//#define BWLINKS
-
-// TODO: This should ignore immediates of many instructions, in order to be less sensitive. If it did,
-// this could work okay.
-static u32 ComputeHash(u32 start, u32 size)
-{
- u32 hash=0;
- for (unsigned int i=start; i> 26) {
- case 18:
- {
- if (LK) {
- u32 addr;
- if(AA)
- addr = SignExt26(LI << 2);
- else
- addr = ptr + SignExt26(LI << 2);
-
- int funNum = GetSymbolNum(addr);
- if (funNum >= 0)
- entries[funNum].backwardLinks.push_back(ptr);
- }
- break;
- }
- default:
- ;
- }
-
- ptr += 4;
- }
- }
-#endif
+ AssignFunctionIndices();
}
void SymbolMap::Clear() {
lock_guard guard(lock_);
-#ifdef BWLINKS
- for (int i=0; i 0; i--) {
if (line[i] == '\r' || line[i] == '\n') {
@@ -182,26 +92,41 @@ bool SymbolMap::LoadSymbolMap(const char *filename)
if (temp[1]==']') continue;
if (!started) continue;
- MapEntry e;
- memset(&e, 0, sizeof(e));
- sscanf(line,"%08x %08x %08x %i %127c",&e.address,&e.size,&e.vaddress,(int*)&e.type,e.name);
-
- if (e.type == ST_DATA && e.size==0)
- e.size=4;
- //e.vaddress|=0x80000000;
- if (strcmp(e.name,".text")==0 || strcmp(e.name,".init")==0 || strlen(e.name)<=1) {
- ;
+ u32 address, size, vaddress;
+ SymbolType type;
+ char name[128] = {0};
+
+ sscanf(line,"%08x %08x %08x %i %127c", &address, &size, &vaddress, (int*)&type, name);
+ if (!Memory::IsValidAddress(vaddress)) {
+ ERROR_LOG(LOADER, "Invalid address in symbol file: %08x (%s)", vaddress, name);
+ continue;
+ }
+ if (type == ST_DATA && size == 0)
+ size = 4;
+
+ if (!strcmp(name, ".text") || !strcmp(name, ".init") || strlen(name) <= 1) {
+
} else {
- e.UndecorateName();
- entries.push_back(e);
- uniqueEntries.insert((const MapEntryUniqueInfo)e);
- entryRanges[e.vaddress + e.size] = e.vaddress;
+ switch (type)
+ {
+ case ST_FUNCTION:
+ AddFunction(name, vaddress, size);
+ break;
+ case ST_DATA:
+ AddData(vaddress,size,DATATYPE_BYTE);
+ if (name[0] != 0)
+ AddLabel(name, vaddress);
+ break;
+ case ST_NONE:
+ case ST_ALL:
+ // Shouldn't be possible.
+ break;
+ }
}
}
fclose(f);
SortSymbols();
- // SymbolMap::AnalyzeBackwards();
return true;
}
@@ -213,10 +138,14 @@ void SymbolMap::SaveSymbolMap(const char *filename) const
if (!f)
return;
fprintf(f,".text\n");
- for (auto it = entries.begin(), end = entries.end(); it != end; ++it)
- {
- const MapEntry &e = *it;
- fprintf(f,"%08x %08x %08x %i %s\n",e.address,e.size,e.vaddress,e.type,e.name);
+ for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
+ const FunctionEntry& e = it->second;
+ fprintf(f,"%08x %08x %08x %i %s\n",it->first,e.size,it->first,ST_FUNCTION,GetLabelName(it->first));
+ }
+
+ for (auto it = data.begin(), end = data.end(); it != end; ++it) {
+ const DataEntry& e = it->second;
+ fprintf(f,"%08x %08x %08x %i %s\n",it->first,e.size,it->first,ST_DATA,GetLabelName(it->first));
}
fclose(f);
}
@@ -228,29 +157,51 @@ bool SymbolMap::LoadNocashSym(const char *filename)
if (!f)
return false;
- while (!feof(f))
- {
+ while (!feof(f)) {
char line[256], value[256] = {0};
- char *p = fgets(line,256,f);
- if(p == NULL)
+ char *p = fgets(line, 256, f);
+ if (p == NULL)
break;
u32 address;
- if (sscanf(line,"%08X %s",&address,value) != 2) continue;
- if (address == 0 && strcmp(value,"0") == 0) continue;
+ if (sscanf(line, "%08X %s", &address, value) != 2)
+ continue;
+ if (address == 0 && strcmp(value, "0") == 0)
+ continue;
- if (value[0] == '.') // data directives
- {
- continue; // not supported yet
+ if (value[0] == '.') {
+ // data directives
+ char* s = strchr(value, ':');
+ if (s != NULL) {
+ *s = 0;
+
+ u32 size = 0;
+ if (sscanf(s + 1, "%04X", &size) != 1)
+ continue;
+
+ if (strcasecmp(value, ".byt") == 0) {
+ AddData(address, size, DATATYPE_BYTE);
+ } else if (strcasecmp(value, ".wrd") == 0) {
+ AddData(address, size, DATATYPE_HALFWORD);
+ } else if (strcasecmp(value, ".dbl") == 0) {
+ AddData(address, size, DATATYPE_WORD);
+ } else if (strcasecmp(value, ".asc") == 0) {
+ AddData(address, size, DATATYPE_ASCII);
+ }
+ }
} else { // labels
int size = 1;
char* seperator = strchr(value,',');
- if (seperator != NULL)
- {
+ if (seperator != NULL) {
*seperator = 0;
sscanf(seperator+1,"%08X",&size);
}
- AddSymbol(value,address,size,ST_FUNCTION);
+
+ if (size != 1) {
+ AddFunction(value,address,size);
+ } else {
+ AddLabel(value,address);
+ }
}
}
@@ -258,443 +209,389 @@ bool SymbolMap::LoadNocashSym(const char *filename)
return true;
}
-int SymbolMap::GetSymbolNum(unsigned int address, SymbolType symmask) const
-{
- lock_guard guard(lock_);
- for (size_t i = 0, n = entries.size(); i < n; i++)
- {
- const MapEntry &entry = entries[i];
- unsigned int addr = entry.vaddress;
- if (address >= addr)
- {
- if (address < addr + entry.size)
- {
- if (entries[i].type & symmask)
- return (int) i;
- else
- return -1;
- }
- }
- else
- break;
- }
- return -1;
+SymbolType SymbolMap::GetSymbolType(u32 address) const {
+ if (functions.find(address) != functions.end())
+ return ST_FUNCTION;
+ if (data.find(address) != data.end())
+ return ST_DATA;
+ return ST_NONE;
}
bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) const
{
- lock_guard guard(lock_);
- // entryRanges is indexed by end. The first entry after address should contain address.
- // Otherwise, we have no entry that contains it, unless things overlap (which they shouldn't.)
- const auto containingEntry = entryRanges.upper_bound(address);
- if (containingEntry == entryRanges.end())
+ u32 functionAddress = INVALID_ADDRESS;
+ u32 dataAddress = INVALID_ADDRESS;
+
+ if (symmask & ST_FUNCTION)
+ functionAddress = GetFunctionStart(address);
+
+ if (symmask & ST_DATA)
+ dataAddress = GetDataStart(address);
+
+ if (functionAddress == INVALID_ADDRESS || dataAddress == INVALID_ADDRESS)
+ {
+ if (functionAddress != INVALID_ADDRESS)
+ {
+ if (info != NULL)
+ {
+ info->type = ST_FUNCTION;
+ info->address = functionAddress;
+ info->size = GetFunctionSize(functionAddress);
+ }
+
+ return true;
+ }
+
+ if (dataAddress != INVALID_ADDRESS)
+ {
+ if (info != NULL)
+ {
+ info->type = ST_DATA;
+ info->address = dataAddress;
+ info->size = GetDataSize(dataAddress);
+ }
+
+ return true;
+ }
+
return false;
-
- // The next most common case is a single symbol by start address.
- // So we optimize for that by looking in our uniqueEntry set.
- u32 start_address = containingEntry->second;
- if (start_address <= address)
- {
- const MapEntryUniqueInfo searchKey = {start_address, start_address};
- const auto entry = uniqueEntries.find(searchKey);
- // In case there were duplicates at some point, double check the end address.
- if (entry != uniqueEntries.end() && entry->vaddress + entry->size > address && (entry->type & symmask) != 0)
- {
- info->address = entry->vaddress;
- info->size = entry->size;
- return true;
- }
}
- // Fall back to a slower scan.
- int n = GetSymbolNum(address, symmask);
- if (n != -1)
- {
- info->address = GetSymbolAddr(n);
- info->size = GetSymbolSize(n);
- return true;
+ // if both exist, return the function
+ if (info != NULL) {
+ info->type = ST_FUNCTION;
+ info->address = functionAddress;
+ info->size = GetFunctionSize(functionAddress);
}
- return false;
+ return true;
}
-const char* SymbolMap::getDirectSymbol(u32 address)
-{
- lock_guard guard(lock_);
- SymbolInfo info;
- if (GetSymbolInfo(&info,address) == false) return NULL;
- if (info.address != address) return NULL; // has to be the START of the function
+u32 SymbolMap::GetNextSymbolAddress(u32 address, SymbolType symmask) {
+ const auto functionEntry = symmask & ST_FUNCTION ? functions.upper_bound(address) : functions.end();
+ const auto dataEntry = symmask & ST_DATA ? data.upper_bound(address) : data.end();
- // now we need the name... which we can't just get from GetSymbolInfo because of the
- // unique entries. But, there are so many less instances where there actually IS a
- // label that the speed up is still massive
- for (auto it = entries.begin(), end = entries.end(); it != end; ++it)
- {
- const MapEntry &entry = *it;
- unsigned int addr = entry.vaddress;
- if (addr == address) return entry.name;
- }
- return NULL;
-}
+ if (functionEntry == functions.end() && dataEntry == data.end())
+ return INVALID_ADDRESS;
-bool SymbolMap::getSymbolValue(char* symbol, u32& dest)
-{
- lock_guard guard(lock_);
- for (auto it = entries.begin(), end = entries.end(); it != end; ++it)
- {
- const MapEntry &entry = *it;
-#ifdef _WIN32
- if (_stricmp(entry.name,symbol) == 0)
-#else
- if (strcasecmp(entry.name,symbol) == 0)
-#endif
- {
- dest = entry.vaddress;
- return true;
- }
- }
- return false;
+ u32 funcAddress = (functionEntry != functions.end()) ? functionEntry->first : 0xFFFFFFFF;
+ u32 dataAddress = (dataEntry != data.end()) ? dataEntry->first : 0xFFFFFFFF;
+
+ if (funcAddress <= dataAddress)
+ return funcAddress;
+ else
+ return dataAddress;
}
static char descriptionTemp[256];
-const char *SymbolMap::GetDescription(unsigned int address) const
-{
- int fun = SymbolMap::GetSymbolNum(address);
- //if (address == entries[fun].vaddress)
- //{
- if (fun!=-1)
- return entries[fun].name;
- else
- {
- sprintf(descriptionTemp, "(%08x)", address);
- return descriptionTemp;
+const char *SymbolMap::GetDescription(unsigned int address) const {
+ const char* labelName = NULL;
+
+ u32 funcStart = GetFunctionStart(address);
+ if (funcStart != INVALID_ADDRESS) {
+ labelName = GetLabelName(funcStart);
+ } else {
+ u32 dataStart = GetDataStart(address);
+ if (dataStart != INVALID_ADDRESS)
+ labelName = GetLabelName(dataStart);
}
- //}
- //else
- // return "";
+
+ if (labelName != NULL)
+ return labelName;
+
+ sprintf(descriptionTemp, "(%08x)", address);
+ return descriptionTemp;
+}
+
+std::vector SymbolMap::GetAllSymbols(SymbolType symmask) {
+ std::vector result;
+
+ if (symmask & ST_FUNCTION) {
+ for (auto it = functions.begin(); it != functions.end(); it++) {
+ SymbolEntry entry;
+ entry.address = it->first;
+ entry.size = GetFunctionSize(entry.address);
+ const char* name = GetLabelName(entry.address);
+ if (name != NULL)
+ entry.name = name;
+ result.push_back(entry);
+ }
+ }
+
+ if (symmask & ST_DATA) {
+ for (auto it = data.begin(); it != data.end(); it++) {
+ SymbolEntry entry;
+ entry.address = it->first;
+ entry.size = GetDataSize(entry.address);
+ const char* name = GetLabelName(entry.address);
+ if (name != NULL)
+ entry.name = name;
+ result.push_back(entry);
+ }
+ }
+
+ return result;
+}
+
+void SymbolMap::AddFunction(const char* name, u32 address, u32 size) {
+ lock_guard guard(lock_);
+
+ FunctionEntry func;
+ func.size = size;
+ func.index = (int)functions.size();
+ functions[address] = func;
+
+ if (GetLabelName(address) == NULL)
+ AddLabel(name,address);
+}
+
+u32 SymbolMap::GetFunctionStart(u32 address) const {
+ auto it = functions.upper_bound(address);
+ if (it == functions.end()) {
+ // check last element
+ auto rit = functions.rbegin();
+ if (rit != functions.rend()) {
+ u32 start = rit->first;
+ u32 size = rit->second.size;
+ if (start <= address && start+size > address)
+ return start;
+ }
+ // otherwise there's no function that contains this address
+ return INVALID_ADDRESS;
+ }
+
+ if (it != functions.begin()) {
+ it--;
+ u32 start = it->first;
+ u32 size = it->second.size;
+ if (start <= address && start+size > address)
+ return start;
+ }
+
+ return INVALID_ADDRESS;
+}
+
+u32 SymbolMap::GetFunctionSize(u32 startAddress) const {
+ auto it = functions.find(startAddress);
+ if (it == functions.end())
+ return INVALID_ADDRESS;
+
+ return it->second.size;
+}
+
+int SymbolMap::GetFunctionNum(u32 address) const {
+ u32 start = GetFunctionStart(address);
+ if (start == INVALID_ADDRESS)
+ return INVALID_ADDRESS;
+
+ auto it = functions.find(start);
+ if (it == functions.end())
+ return INVALID_ADDRESS;
+
+ return it->second.index;
+}
+
+void SymbolMap::AssignFunctionIndices() {
+ int index = 0;
+ for (auto it = functions.begin(); it != functions.end(); it++) {
+ it->second.index = index++;
+ }
+}
+
+bool SymbolMap::SetFunctionSize(u32 startAddress, u32 newSize) {
+ lock_guard guard(lock_);
+
+ auto it = functions.find(startAddress);
+ if (it == functions.end())
+ return false;
+
+ it->second.size = newSize;
+
+ // TODO: check for overlaps
+ return true;
+}
+
+bool SymbolMap::RemoveFunction(u32 startAddress, bool removeName) {
+ lock_guard guard(lock_);
+
+ auto it = functions.find(startAddress);
+ if (it == functions.end())
+ return false;
+
+ functions.erase(it);
+ if (removeName) {
+ auto labelIt = labels.find(startAddress);
+ if (labelIt != labels.end())
+ labels.erase(labelIt);
+ }
+
+ return true;
+}
+
+void SymbolMap::AddLabel(const char* name, u32 address) {
+ // keep a label if it already exists
+ auto it = labels.find(address);
+ if (it == labels.end()) {
+ LabelEntry label;
+ strncpy(label.name, name, 128);
+ label.name[127] = 0;
+ labels[address] = label;
+ }
+}
+
+void SymbolMap::SetLabelName(const char* name, u32 address) {
+ auto it = labels.find(address);
+ if (it == labels.end()) {
+ LabelEntry label;
+ strcpy(label.name,name);
+ label.name[127] = 0;
+
+ labels[address] = label;
+ } else {
+ strcpy(it->second.name,name);
+ it->second.name[127] = 0;
+ }
+}
+
+const char* SymbolMap::GetLabelName(u32 address) const {
+ auto it = labels.find(address);
+ if (it == labels.end())
+ return NULL;
+
+ return it->second.name;
+}
+
+bool SymbolMap::GetLabelValue(const char* name, u32& dest) {
+ for (auto it = labels.begin(); it != labels.end(); it++) {
+ if (strcasecmp(name,it->second.name) == 0) {
+ dest = it->first;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void SymbolMap::AddData(u32 address, u32 size, DataType type) {
+ DataEntry entry;
+ entry.size = size;
+ entry.type = type;
+ data[address] = entry;
+}
+
+u32 SymbolMap::GetDataStart(u32 address) const {
+ auto it = data.upper_bound(address);
+ if (it == data.end())
+ {
+ // check last element
+ auto rit = data.rbegin();
+
+ if (rit != data.rend())
+ {
+ u32 start = rit->first;
+ u32 size = rit->second.size;
+ if (start <= address && start+size > address)
+ return start;
+ }
+ // otherwise there's no data that contains this address
+ return INVALID_ADDRESS;
+ }
+
+ if (it != data.begin()) {
+ it--;
+ u32 start = it->first;
+ u32 size = it->second.size;
+ if (start <= address && start+size > address)
+ return start;
+ }
+
+ return INVALID_ADDRESS;
+}
+
+u32 SymbolMap::GetDataSize(u32 startAddress) const {
+ auto it = data.find(startAddress);
+ if (it == data.end())
+ return INVALID_ADDRESS;
+ return it->second.size;
+}
+
+DataType SymbolMap::GetDataType(u32 startAddress) const {
+ auto it = data.find(startAddress);
+ if (it == data.end())
+ return DATATYPE_NONE;
+ return it->second.type;
}
#ifdef _WIN32
-static const int defaultSymbolsAddresses[] = {
- 0x08800000, 0x08804000, 0x04000000, 0x88000000, 0x00010000
+struct DefaultSymbol {
+ u32 address;
+ const char* name;
};
-static const char* defaultSymbolsNames[] = {
- "User memory", "Default load address", "VRAM","Kernel memory","Scratchpad"
+static const DefaultSymbol defaultSymbols[]= {
+ { 0x08800000, "User memory" },
+ { 0x08804000, "Default load address" },
+ { 0x04000000, "VRAM" },
+ { 0x88000000, "Kernel memory" },
+ { 0x00010000, "Scratchpad" },
};
-static const int defaultSymbolsAmount = sizeof(defaultSymbolsAddresses)/sizeof(const int);
-
-void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symmask) const
-{
- BOOL visible = ShowWindow(listbox,SW_HIDE);
- ListBox_ResetContent(listbox);
-
- if (symmask & ST_DATA)
- {
- for (int i = 0; i < defaultSymbolsAmount; i++)
- {
- wchar_t temp[256];
- wsprintf(temp, L"0x%08X (%S)", defaultSymbolsAddresses[i], defaultSymbolsNames[i]);
- int index = ListBox_AddString(listbox,temp);
- ListBox_SetItemData(listbox,index,defaultSymbolsAddresses[i]);
- }
- }
-
+void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symType) const {
+ wchar_t temp[256];
lock_guard guard(lock_);
SendMessage(listbox, WM_SETREDRAW, FALSE, 0);
- SendMessage(listbox, LB_INITSTORAGE, (WPARAM)entries.size(), (LPARAM)entries.size() * 30);
- for (auto it = entries.begin(), end = entries.end(); it != end; ++it)
- {
- const MapEntry &entry = *it;
- if (entry.type & symmask)
- {
- wchar_t temp[256];
- if (entry.type & ST_FUNCTION || !(entry.type & ST_DATA))
- {
- wsprintf(temp, L"%S", entry.name);
- } else {
- wsprintf(temp, L"0x%08X (%S)", entry.vaddress, entry.name);
- }
-
- int index = ListBox_AddString(listbox,temp);
- ListBox_SetItemData(listbox,index,entry.vaddress);
- }
- }
- SendMessage(listbox, WM_SETREDRAW, TRUE, 0);
- RedrawWindow(listbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
-
- if (visible)
- ShowWindow(listbox,SW_SHOW);
-}
-
-void SymbolMap::FillSymbolComboBox(HWND listbox,SymbolType symmask) const
-{
- ShowWindow(listbox,SW_HIDE);
- ComboBox_ResetContent(listbox);
-
- //int style = GetWindowLong(listbox,GWL_STYLE);
-
- ComboBox_AddString(listbox, L"(0x02000000)");
- ComboBox_SetItemData(listbox, 0, 0x02000000);
-
- //ListBox_AddString(listbox, L"(0x80002000)");
- //ListBox_SetItemData(listbox, 1, 0x80002000);
-
- lock_guard guard(lock_);
-
- SendMessage(listbox, WM_SETREDRAW, FALSE, 0);
- SendMessage(listbox, CB_INITSTORAGE, (WPARAM)entries.size(), (LPARAM)entries.size() * 30 * sizeof(wchar_t));
- for (size_t i = 0, end = entries.size(); i < end; ++i)
- {
- const MapEntry &entry = entries[i];
- if (entry.type & symmask)
- {
- wchar_t temp[256];
- wsprintf(temp, L"%S (%d)", entry.name, entry.size);
- int index = ComboBox_AddString(listbox,temp);
- ComboBox_SetItemData(listbox,index,entry.vaddress);
- }
- }
- SendMessage(listbox, WM_SETREDRAW, TRUE, 0);
- RedrawWindow(listbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
- ShowWindow(listbox,SW_SHOW);
-}
-
-void SymbolMap::FillListBoxBLinks(HWND listbox, int num) const
-{
ListBox_ResetContent(listbox);
- lock_guard guard(lock_);
-
- int style = GetWindowLong(listbox,GWL_STYLE);
-
- const MapEntry &e = entries[num];
-#ifdef BWLINKS
- for (int i=0; i::iterator it = uniqueEntries.find((const MapEntryUniqueInfo) e);
- if (it != uniqueEntries.end()){
- MapEntryUniqueInfo temp = *it;
- temp.size = newSize;
- uniqueEntries.erase(it);
- uniqueEntries.insert(temp);
- }
- entryRanges.erase(e.vaddress + e.size);
- entryRanges.insert(std::pair(e.vaddress+newSize,e.vaddress));
-
- e.size = newSize;
-}
-
-u32 SymbolMap::GetSymbolAddr(int i) const
-{
- return entries[i].vaddress;
-}
-
-u32 SymbolMap::GetSymbolSize(int i) const
-{
- return entries[i].size;
-}
-
-int SymbolMap::FindSymbol(const char *name) const
-{
- lock_guard guard(lock_);
- for (size_t i = 0; i < entries.size(); i++)
- if (strcmp(entries[i].name,name)==0)
- return (int) i;
- return -1;
-}
-
-u32 SymbolMap::GetAddress(int num) const
-{
- return entries[num].vaddress;
-}
-
-void SymbolMap::IncreaseRunCount(int num)
-{
- entries[num].runCount++;
-}
-
-unsigned int SymbolMap::GetRunCount(int num) const
-{
- if (num>=0)
- return entries[num].runCount;
- else
- return 0;
-}
-
-// Load an elf with symbols, use SymbolMap::compilefuncsignaturesfile
-// to make a symbol map, load a dol or somethin without symbols, then apply
-// the map with SymbolMap::usefuncsignaturesfile.
-
-void SymbolMap::CompileFuncSignaturesFile(const char *filename) const
-{
- // Store name,length,first instruction,hash into file
- FILE *f = File::OpenCFile(filename, "w");
- fprintf(f,"00000000\n");
- int count=0;
- for (auto it = entries.begin(), end = entries.end(); it != end; ++it)
- {
- const MapEntry &entry = *it;
- int size = entry.size;
- if (size >= 16 && entry.type == ST_FUNCTION)
+ switch (symType) {
+ case ST_FUNCTION:
{
- u32 inst = Memory::Read_Instruction(entry.vaddress).encoding; //try to make a bigger number of different vals sometime
- if (inst != 0)
- {
- char temp[64];
- strncpy(temp,entry.name,63);
- fprintf(f, "%08x\t%08x\t%08x\t%s\n", inst, size, ComputeHash(entry.vaddress,size), temp);
- count++;
+ SendMessage(listbox, LB_INITSTORAGE, (WPARAM)functions.size(), (LPARAM)functions.size() * 30);
+
+ for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
+ const FunctionEntry& entry = it->second;
+ const char* name = GetLabelName(it->first);
+ if (name != NULL)
+ wsprintf(temp, L"%S", name);
+ else
+ wsprintf(temp, L"0x%08X", it->first);
+ int index = ListBox_AddString(listbox,temp);
+ ListBox_SetItemData(listbox,index,it->first);
}
}
- }
- fseek(f,0,SEEK_SET);
- fprintf(f,"%08x",count);
- fclose(f);
-}
+ break;
-
-struct Sig
-{
- u32 inst;
- u32 size;
- u32 hash;
- char name[64];
- Sig(){}
- Sig(u32 _inst, u32 _size, u32 _hash, char *_name) : inst(_inst), size(_size), hash(_hash)
- {
- strncpy(name,_name,63);
- }
- bool operator <(const Sig &other) const {
- return inst < other.inst;
- }
-};
-
-std::vector sigs;
-
-typedef std::map Sigmap;
-Sigmap sigmap;
-
-void SymbolMap::UseFuncSignaturesFile(const char *filename, u32 maxAddress)
-{
- sigs.clear();
- // symbolMap.Clear();
- //#1: Read the signature file and put them in a fast data structure
- FILE *f = File::OpenCFile(filename, "r");
- int count;
- if (fscanf(f, "%08x\n", &count) != 1)
- count = 0;
- char name[256];
- for (int a=0; asecond;
- while (true)
- {
- if (sig->inst != inst)
- break;
+ for (auto it = data.begin(), end = data.end(); it != end; ++it) {
+ const DataEntry& entry = it->second;
+ const char* name = GetLabelName(it->first);
- u32 hash = ComputeHash(addr,sig->size);
- if (hash==sig->hash)
- {
- //MATCH!!!!
- MapEntry e;
- e.address=addr;
- e.size= sig->size;
- e.vaddress = addr;
- e.type=ST_FUNCTION;
- strcpy(e.name,sig->name);
- addr+=sig->size-4; //don't need to check function interior
- entries.push_back(e);
- uniqueEntries.insert((const MapEntryUniqueInfo)e);
- entryRanges[e.vaddress + e.size] = e.vaddress;
- break;
- }
- sig++;
+ if (name != NULL)
+ wsprintf(temp, L"%S", name);
+ else
+ wsprintf(temp, L"0x%08X", it->first);
+
+ int index = ListBox_AddString(listbox,temp);
+ ListBox_SetItemData(listbox,index,it->first);
}
}
+ break;
}
- //ensure code coloring even if symbols were loaded before
- SymbolMap::SortSymbols();
+
+ SendMessage(listbox, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(listbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
+
+#endif
diff --git a/Core/Debugger/SymbolMap.h b/Core/Debugger/SymbolMap.h
index 97263a9112..284eb5d006 100644
--- a/Core/Debugger/SymbolMap.h
+++ b/Core/Debugger/SymbolMap.h
@@ -24,15 +24,28 @@
#include