mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-23 16:19:44 +00:00
Merge branch 'master' into mediaengine
Conflicts: Common/LogManager.cpp Core/CMakeLists.txt Core/Core.vcxproj Core/Core.vcxproj.filters Core/CoreParameter.h Core/HLE/sceAudio.cpp Core/HLE/sceKernel.cpp Core/HLE/sceKernelThread.cpp Core/HLE/sceMpeg.cpp android/jni/Android.mk
This commit is contained in:
commit
bc214dcf37
3
.gitignore
vendored
3
.gitignore
vendored
@ -32,3 +32,6 @@ Memstick
|
||||
android/ui_atlas.zim
|
||||
__testoutput.txt
|
||||
__testerror.txt
|
||||
ppge_atlas.zim.png
|
||||
local.properties
|
||||
build*/
|
||||
|
905
CMakeLists.txt
Normal file
905
CMakeLists.txt
Normal file
@ -0,0 +1,905 @@
|
||||
# vim:noexpandtab:
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(PPSSPP)
|
||||
|
||||
if(ANDROID)
|
||||
if(ARMEABI OR ARMEABI_V7A)
|
||||
set(ARM ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (IOS)
|
||||
if (${IOS_PLATFORM} STREQUAL "OS")
|
||||
set(ARM ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BLACKBERRY)
|
||||
set(ARM ON)
|
||||
endif()
|
||||
|
||||
if(ARM)
|
||||
set(USING_GLES2 ON)
|
||||
else() # Assume x86
|
||||
set(X86 ON)
|
||||
endif()
|
||||
|
||||
if(ANDROID OR BLACKBERRY OR IOS)
|
||||
set(HEADLESS OFF)
|
||||
elseif(NOT DEFINED HEADLESS)
|
||||
set(HEADLESS ON)
|
||||
endif()
|
||||
|
||||
# User-editable options (go into CMakeCache.txt)
|
||||
option(ARM "Set to ON if targeting an ARM processor" ${ARM})
|
||||
option(X86 "Set to ON if targeting an X86 processor" ${X86})
|
||||
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(BLACKBERRY "Set to ON if targeting a Blackberry device" ${BLACKBERRY})
|
||||
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(DEBUG "Set to ON to enable full debug logging" ${DEBUG})
|
||||
|
||||
if(ANDROID)
|
||||
if(NOT ANDROID_ABI)
|
||||
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\"")
|
||||
endif()
|
||||
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)
|
||||
endif()
|
||||
|
||||
#find_package(Qt5Widgets)
|
||||
if(USING_GLES2)
|
||||
set(OPENGL_LIBRARIES GLESv2)
|
||||
else()
|
||||
include(FindOpenGL REQUIRED)
|
||||
endif()
|
||||
if (NOT BLACKBERRY AND NOT ANDROID)
|
||||
include(FindSDL)
|
||||
endif()
|
||||
include(FindThreads)
|
||||
if(APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
endif()
|
||||
|
||||
# Needed for Globals.h
|
||||
include_directories("${CMAKE_SOURCE_DIR}")
|
||||
|
||||
if(BLACKBERRY)
|
||||
add_definitions(-DBLACKBERRY)
|
||||
if(BLACKBERRY VERSION_GREATER 10)
|
||||
add_definitions(-DBLACKBERRY10)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
add_definitions(-DIOS)
|
||||
endif()
|
||||
|
||||
if(ARM)
|
||||
add_definitions(-DARM)
|
||||
endif()
|
||||
if(USING_GLES2)
|
||||
add_definitions(-DUSING_GLES2)
|
||||
endif()
|
||||
|
||||
if(DEBUG)
|
||||
add_definitions(-D_DEBUG)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
# Disable some warnings
|
||||
add_definitions(-Wno-multichar)
|
||||
add_definitions(-fno-strict-aliasing)
|
||||
if(NOT APPLE)
|
||||
add_definitions(-Wno-psabi)
|
||||
add_definitions(-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -D__BSD_VISIBLE=1)
|
||||
add_definitions(-D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64)
|
||||
endif()
|
||||
|
||||
if(BLACKBERRY)
|
||||
add_definitions(-D_QNX_SOURCE=1 -D_C99=1)
|
||||
endif()
|
||||
|
||||
if(X86)
|
||||
# enable sse2 code generation
|
||||
add_definitions(-msse2)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif()
|
||||
else()
|
||||
# Disable warnings about MS-specific _s variants of libc functions
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||
|
||||
if(ANDROID)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/android/libs/${ANDROID_ABI}")
|
||||
endif()
|
||||
|
||||
# This sets up the MSVC project dirs according to the physical project dirs
|
||||
macro(setup_target_project TargetName ProjectDir)
|
||||
get_property(TargetSources TARGET "${TargetName}" PROPERTY SOURCES)
|
||||
foreach(Source ${TargetSources})
|
||||
# Figure out the file's path relative to the ProjectDir
|
||||
# NOTE: &#$@ double-quoted regexps
|
||||
string(REGEX REPLACE "${ProjectDir}" "" RelativePath "${Source}")
|
||||
string(REGEX REPLACE "[\\\\/][^\\\\/]*$" "" RelativePath "${RelativePath}")
|
||||
string(REGEX REPLACE "^[\\\\/]" "" RelativePath "${RelativePath}")
|
||||
string(REGEX REPLACE "/" "\\\\\\\\" RelativePath "${RelativePath}")
|
||||
# put the source file in a source_group equivalent to the relative path
|
||||
source_group("${RelativePath}" FILES ${Source})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Commented-out files are files that don't compile
|
||||
# and were disabled in the original MSVC project anyway
|
||||
|
||||
set(CommonExtra)
|
||||
if(ARM)
|
||||
set(CommonExtra ${CommonExtra}
|
||||
Common/ArmABI.h
|
||||
Common/ArmABI.cpp
|
||||
Common/ArmEmitter.h
|
||||
Common/ArmEmitter.cpp
|
||||
Common/ThunkARM.cpp)
|
||||
elseif(X86)
|
||||
set(CommonExtra ${CommonExtra}
|
||||
Common/ABI.cpp
|
||||
Common/ABI.h
|
||||
Common/CPUDetect.cpp
|
||||
Common/CPUDetect.h
|
||||
Common/MathUtil.cpp
|
||||
Common/MathUtil.h
|
||||
Common/Thunk.cpp
|
||||
Common/Thunk.h
|
||||
Common/x64Analyzer.cpp
|
||||
Common/x64Analyzer.h
|
||||
Common/x64Emitter.cpp
|
||||
Common/x64Emitter.h)
|
||||
endif()
|
||||
if(WIN32)
|
||||
set(CommonExtra ${CommonExtra}
|
||||
Common/stdafx.cpp
|
||||
Common/stdafx.h)
|
||||
endif()
|
||||
|
||||
add_library(Common STATIC
|
||||
${CommonExtra}
|
||||
Common/Action.cpp
|
||||
Common/Action.h
|
||||
Common/ColorUtil.cpp
|
||||
Common/ColorUtil.h
|
||||
Common/ConsoleListener.cpp
|
||||
Common/ConsoleListener.h
|
||||
Common/Crypto/aes_cbc.cpp
|
||||
Common/Crypto/aes_core.cpp
|
||||
Common/Crypto/bn.cpp
|
||||
Common/Crypto/ec.cpp
|
||||
Common/Crypto/md5.cpp
|
||||
Common/Crypto/md5.h
|
||||
Common/Crypto/sha1.cpp
|
||||
Common/Crypto/sha1.h
|
||||
Common/ExtendedTrace.cpp
|
||||
Common/ExtendedTrace.h
|
||||
Common/FPURoundModeGeneric.cpp
|
||||
# Common/FPURoundModeX86.cpp
|
||||
Common/FileSearch.cpp
|
||||
Common/FileSearch.h
|
||||
Common/FileUtil.cpp
|
||||
Common/FileUtil.h
|
||||
Common/Hash.cpp
|
||||
Common/Hash.h
|
||||
Common/IniFile.cpp
|
||||
Common/IniFile.h
|
||||
Common/LogManager.cpp
|
||||
Common/LogManager.h
|
||||
Common/MemArena.cpp
|
||||
Common/MemArena.h
|
||||
Common/MemoryUtil.cpp
|
||||
Common/MemoryUtil.h
|
||||
Common/Misc.cpp
|
||||
Common/MsgHandler.cpp
|
||||
Common/MsgHandler.h
|
||||
Common/StringUtil.cpp
|
||||
Common/StringUtil.h
|
||||
Common/Thread.cpp
|
||||
Common/Thread.h
|
||||
Common/Timer.cpp
|
||||
Common/Timer.h
|
||||
Common/Version.cpp)
|
||||
include_directories(Common)
|
||||
setup_target_project(Common Common)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(Common winmm)
|
||||
endif()
|
||||
|
||||
add_library(zlib STATIC
|
||||
ext/zlib/adler32.c
|
||||
ext/zlib/compress.c
|
||||
ext/zlib/crc32.c
|
||||
ext/zlib/crc32.h
|
||||
ext/zlib/deflate.c
|
||||
ext/zlib/deflate.h
|
||||
ext/zlib/gzclose.c
|
||||
ext/zlib/gzguts.h
|
||||
ext/zlib/gzlib.c
|
||||
ext/zlib/gzread.c
|
||||
ext/zlib/gzwrite.c
|
||||
ext/zlib/infback.c
|
||||
ext/zlib/inffast.c
|
||||
ext/zlib/inffast.h
|
||||
ext/zlib/inffixed.h
|
||||
ext/zlib/inflate.c
|
||||
ext/zlib/inflate.h
|
||||
ext/zlib/inftrees.c
|
||||
ext/zlib/inftrees.h
|
||||
ext/zlib/make_vms.com
|
||||
ext/zlib/trees.c
|
||||
ext/zlib/trees.h
|
||||
ext/zlib/uncompr.c
|
||||
ext/zlib/zconf.h
|
||||
ext/zlib/zlib.h
|
||||
ext/zlib/zutil.c
|
||||
ext/zlib/zutil.h
|
||||
)
|
||||
include_directories(ext/zlib)
|
||||
|
||||
add_library(etcpack STATIC
|
||||
native/ext/etcpack/etcdec.cpp
|
||||
native/ext/etcpack/etcdec.h
|
||||
native/ext/etcpack/etcpack.cpp
|
||||
native/ext/etcpack/etcpack.h
|
||||
native/ext/etcpack/image.cpp
|
||||
native/ext/etcpack/image.h)
|
||||
include_directories(native/ext/etcpack)
|
||||
|
||||
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(sha1 STATIC
|
||||
native/ext/sha1/sha1.cpp
|
||||
native/ext/sha1/sha1.h)
|
||||
include_directories(native/ext/sha1)
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
set(nativeExtra)
|
||||
set(nativeExtraLibs)
|
||||
if(ANDROID)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
native/base/NativeApp.h
|
||||
native/android/app-android.cpp
|
||||
native/android/native_audio.cpp
|
||||
native/android/native_audio.h)
|
||||
|
||||
add_library(native_audio SHARED
|
||||
native/android/native-audio-so.cpp
|
||||
native/android/native-audio-so.h)
|
||||
target_link_libraries(native_audio OpenSLES)
|
||||
# No target
|
||||
elseif(USING_QT_UI)
|
||||
# Currently unused
|
||||
find_package(Qt4 COMPONENTS QtMultimedia QtOpenGL QtGui QtCore)
|
||||
include(${QT_USE_FILE})
|
||||
qt4_wrap_cpp(nativeQtHeader native/base/QtMain.h)
|
||||
set(nativeExtra ${nativeExtra} native/base/QtMain.cpp ${nativeQtHeader})
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${QT_LIBRARIES})
|
||||
set(TargetBin PPSSPPQt)
|
||||
elseif(BLACKBERRY)
|
||||
set(nativeExtra ${nativeExtra} native/base/BlackberryMain.cpp)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} asound bps screen socket EGL)
|
||||
set(TargetBin PPSSPPBlackberry)
|
||||
elseif(SDL_FOUND)
|
||||
# Require SDL
|
||||
include_directories(${SDL_INCLUDE_DIR})
|
||||
set(nativeExtra ${nativeExtra} native/base/PCMain.cpp)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${SDL_LIBRARY})
|
||||
if(APPLE)
|
||||
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY})
|
||||
endif()
|
||||
if(NOT IOS) # No target
|
||||
set(TargetBin PPSSPPSDL)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find SDL. Failing.")
|
||||
endif()
|
||||
|
||||
if(X86)
|
||||
set(nativeExtra ${nativeExtra}
|
||||
native/base/backtrace.cpp
|
||||
native/base/backtrace.h)
|
||||
endif()
|
||||
|
||||
add_library(native STATIC
|
||||
${nativeExtra}
|
||||
native/audio/mixer.cpp
|
||||
native/audio/mixer.h
|
||||
native/audio/wav_read.cpp
|
||||
native/audio/wav_read.h
|
||||
native/base/basictypes.h
|
||||
native/base/buffer.cpp
|
||||
native/base/buffer.h
|
||||
native/base/color.h
|
||||
native/base/colorutil.cpp
|
||||
native/base/colorutil.h
|
||||
native/base/display.cpp
|
||||
native/base/display.h
|
||||
native/base/error_context.cpp
|
||||
native/base/error_context.h
|
||||
native/base/fastlist.h
|
||||
native/base/fastlist_test.cpp
|
||||
native/base/linked_ptr.h
|
||||
native/base/logging.h
|
||||
native/base/mutex.h
|
||||
native/base/scoped_ptr.h
|
||||
native/base/stats.h
|
||||
native/base/stringutil.cpp
|
||||
native/base/stringutil.h
|
||||
native/base/threadutil.cpp
|
||||
native/base/threadutil.h
|
||||
native/base/timeutil.cpp
|
||||
native/base/timeutil.h
|
||||
native/file/chunk_file.cpp
|
||||
native/file/chunk_file.h
|
||||
native/file/dialog.cpp
|
||||
native/file/dialog.h
|
||||
native/file/easy_file.cpp
|
||||
native/file/easy_file.h
|
||||
native/file/fd_util.cpp
|
||||
native/file/fd_util.h
|
||||
native/file/file_util.cpp
|
||||
native/file/file_util.h
|
||||
native/file/vfs.h
|
||||
native/file/zip_read.cpp
|
||||
native/file/zip_read.h
|
||||
native/gfx/gl_debug_log.cpp
|
||||
native/gfx/gl_debug_log.h
|
||||
native/gfx/gl_lost_manager.cpp
|
||||
native/gfx/gl_lost_manager.h
|
||||
native/gfx/texture.cpp
|
||||
native/gfx/texture.h
|
||||
native/gfx/texture_atlas.cpp
|
||||
native/gfx/texture_atlas.h
|
||||
# native/gfx/texture_dx11.cpp
|
||||
native/gfx/texture_gen.cpp
|
||||
native/gfx/texture_gen.h
|
||||
native/gfx_es2/draw_buffer.cpp
|
||||
native/gfx_es2/draw_buffer.h
|
||||
native/gfx_es2/fbo.cpp
|
||||
native/gfx_es2/fbo.h
|
||||
native/gfx_es2/gl_state.cpp
|
||||
native/gfx_es2/gl_state.h
|
||||
native/gfx_es2/glsl_program.cpp
|
||||
native/gfx_es2/glsl_program.h
|
||||
native/gfx_es2/vertex_format.cpp
|
||||
native/gfx_es2/vertex_format.h
|
||||
native/image/png_load.cpp
|
||||
native/image/png_load.h
|
||||
native/image/zim_load.cpp
|
||||
native/image/zim_load.h
|
||||
native/image/zim_save.cpp
|
||||
native/image/zim_save.h
|
||||
native/input/gesture_detector.cpp
|
||||
native/input/gesture_detector.h
|
||||
native/input/input_state.h
|
||||
native/json/json_writer.cpp
|
||||
native/json/json_writer.h
|
||||
native/math/compression.h
|
||||
native/math/curves.cpp
|
||||
native/math/curves.h
|
||||
native/math/lin/aabb.cpp
|
||||
native/math/lin/aabb.h
|
||||
native/math/lin/matrix4x4.cpp
|
||||
native/math/lin/matrix4x4.h
|
||||
native/math/lin/plane.cpp
|
||||
native/math/lin/plane.h
|
||||
native/math/lin/quat.cpp
|
||||
native/math/lin/quat.h
|
||||
native/math/lin/ray.h
|
||||
native/math/lin/vec3.cpp
|
||||
native/math/lin/vec3.h
|
||||
native/math/math_util.cpp
|
||||
native/math/math_util.h
|
||||
native/midi/midi_input.cpp
|
||||
native/midi/midi_input.h
|
||||
native/net/http_client.cpp
|
||||
native/net/http_client.h
|
||||
native/net/resolve.cpp
|
||||
native/net/resolve.h
|
||||
native/profiler/profiler.cpp
|
||||
native/profiler/profiler.h
|
||||
native/ui/screen.cpp
|
||||
native/ui/screen.h
|
||||
native/ui/ui.cpp
|
||||
native/ui/ui.h
|
||||
native/ui/virtual_input.cpp
|
||||
native/ui/virtual_input.h
|
||||
native/util/bits/bits.cpp
|
||||
native/util/bits/bits.h
|
||||
native/util/bits/hamming.h
|
||||
native/util/bits/varint.cpp
|
||||
native/util/bits/varint.h
|
||||
native/util/hash/hash.cpp
|
||||
native/util/hash/hash.h
|
||||
native/util/random/perlin.cpp
|
||||
native/util/random/perlin.h
|
||||
native/util/random/rng.h
|
||||
native/ext/rapidxml/rapidxml.hpp
|
||||
native/ext/rapidxml/rapidxml_iterators.hpp
|
||||
native/ext/rapidxml/rapidxml_print.hpp
|
||||
native/ext/rapidxml/rapidxml_utils.hpp)
|
||||
include_directories(native)
|
||||
# rapidxml is headers only so we can't make a lib specific for it
|
||||
include_directories(native/ext/rapidxml)
|
||||
target_link_libraries(native ${LIBZIP} etcpack sha1 stb_image stb_vorbis #vjson
|
||||
zlib ${GLEW_LIBRARIES})
|
||||
if(ANDROID)
|
||||
target_link_libraries(native log)
|
||||
endif()
|
||||
setup_target_project(native native)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(native ws2_32 winmm)
|
||||
endif()
|
||||
|
||||
add_library(kirk STATIC
|
||||
ext/libkirk/AES.c
|
||||
ext/libkirk/AES.h
|
||||
ext/libkirk/SHA1.c
|
||||
ext/libkirk/SHA1.h
|
||||
ext/libkirk/bn.c
|
||||
ext/libkirk/ec.c
|
||||
ext/libkirk/kirk_engine.c
|
||||
ext/libkirk/kirk_engine.h)
|
||||
include_directories(ext/libkirk)
|
||||
|
||||
set(CoreExtra)
|
||||
if(ARM)
|
||||
set(CoreExtra ${CoreExtra}
|
||||
Core/MIPS/ARM/Asm.cpp
|
||||
Core/MIPS/ARM/Asm.h
|
||||
Core/MIPS/ARM/CompALU.cpp
|
||||
Core/MIPS/ARM/CompBranch.cpp
|
||||
Core/MIPS/ARM/CompFPU.cpp
|
||||
Core/MIPS/ARM/CompLoadStore.cpp
|
||||
Core/MIPS/ARM/CompVFPU.cpp
|
||||
Core/MIPS/ARM/Jit.cpp
|
||||
Core/MIPS/ARM/Jit.h
|
||||
Core/MIPS/ARM/JitCache.cpp
|
||||
Core/MIPS/ARM/JitCache.h
|
||||
Core/MIPS/ARM/RegCache.cpp
|
||||
Core/MIPS/ARM/RegCache.h)
|
||||
elseif(X86)
|
||||
set(CoreExtra ${CoreExtra}
|
||||
Core/MIPS/x86/Asm.cpp
|
||||
Core/MIPS/x86/Asm.h
|
||||
Core/MIPS/x86/CompALU.cpp
|
||||
Core/MIPS/x86/CompBranch.cpp
|
||||
Core/MIPS/x86/CompFPU.cpp
|
||||
Core/MIPS/x86/CompLoadStore.cpp
|
||||
Core/MIPS/x86/CompVFPU.cpp
|
||||
Core/MIPS/x86/Jit.cpp
|
||||
Core/MIPS/x86/Jit.h
|
||||
Core/MIPS/x86/JitCache.cpp
|
||||
Core/MIPS/x86/JitCache.h
|
||||
Core/MIPS/x86/RegCache.cpp
|
||||
Core/MIPS/x86/RegCache.h)
|
||||
endif()
|
||||
|
||||
# 'ppsspp_jni' on ANDROID, 'Core' everywhere else
|
||||
# SHARED on ANDROID, STATIC everywhere else
|
||||
add_library(${CoreLibName} ${CoreLinkType}
|
||||
${CoreExtra}
|
||||
Core/CPU.cpp
|
||||
Core/CPU.h
|
||||
Core/Config.cpp
|
||||
Core/Config.h
|
||||
Core/Core.cpp
|
||||
Core/Core.h
|
||||
Core/CoreParameter.h
|
||||
Core/CoreTiming.cpp
|
||||
Core/CoreTiming.h
|
||||
Core/Debugger/Breakpoints.cpp
|
||||
Core/Debugger/Breakpoints.h
|
||||
Core/Debugger/DebugInterface.h
|
||||
Core/Debugger/SymbolMap.cpp
|
||||
Core/Debugger/SymbolMap.h
|
||||
Core/Dialog/PSPDialog.cpp
|
||||
Core/Dialog/PSPDialog.h
|
||||
Core/Dialog/PSPMsgDialog.cpp
|
||||
Core/Dialog/PSPMsgDialog.h
|
||||
Core/Dialog/PSPOskDialog.cpp
|
||||
Core/Dialog/PSPOskDialog.h
|
||||
Core/Dialog/PSPPlaceholderDialog.cpp
|
||||
Core/Dialog/PSPPlaceholderDialog.h
|
||||
Core/Dialog/PSPSaveDialog.cpp
|
||||
Core/Dialog/PSPSaveDialog.h
|
||||
Core/Dialog/SavedataParam.cpp
|
||||
Core/Dialog/SavedataParam.h
|
||||
Core/ELF/ElfReader.cpp
|
||||
Core/ELF/ElfReader.h
|
||||
Core/ELF/ElfTypes.h
|
||||
Core/ELF/PrxDecrypter.cpp
|
||||
Core/ELF/PrxDecrypter.h
|
||||
Core/ELF/ParamSFO.cpp
|
||||
Core/ELF/ParamSFO.h
|
||||
Core/FileSystems/BlockDevices.cpp
|
||||
Core/FileSystems/BlockDevices.h
|
||||
Core/FileSystems/DirectoryFileSystem.cpp
|
||||
Core/FileSystems/DirectoryFileSystem.h
|
||||
Core/FileSystems/FileSystem.h
|
||||
Core/FileSystems/ISOFileSystem.cpp
|
||||
Core/FileSystems/ISOFileSystem.h
|
||||
Core/FileSystems/MetaFileSystem.cpp
|
||||
Core/FileSystems/MetaFileSystem.h
|
||||
Core/HLE/FunctionWrappers.h
|
||||
Core/HLE/HLE.cpp
|
||||
Core/HLE/HLE.h
|
||||
Core/HLE/HLETables.cpp
|
||||
Core/HLE/HLETables.h
|
||||
Core/HLE/__sceAudio.cpp
|
||||
Core/HLE/__sceAudio.h
|
||||
Core/HLE/sceAtrac.cpp
|
||||
Core/HLE/sceAtrac.h
|
||||
Core/HLE/sceAudio.cpp
|
||||
Core/HLE/sceAudio.h
|
||||
Core/HLE/sceCtrl.cpp
|
||||
Core/HLE/sceCtrl.h
|
||||
Core/HLE/sceDisplay.cpp
|
||||
Core/HLE/sceDisplay.h
|
||||
Core/HLE/sceDmac.cpp
|
||||
Core/HLE/sceDmac.h
|
||||
Core/HLE/sceGe.cpp
|
||||
Core/HLE/sceGe.h
|
||||
Core/HLE/sceFont.cpp
|
||||
Core/HLE/sceFont.h
|
||||
Core/HLE/sceHprm.cpp
|
||||
Core/HLE/sceHprm.h
|
||||
Core/HLE/sceHttp.cpp
|
||||
Core/HLE/sceHttp.h
|
||||
Core/HLE/sceImpose.cpp
|
||||
Core/HLE/sceImpose.h
|
||||
Core/HLE/sceIo.cpp
|
||||
Core/HLE/sceIo.h
|
||||
Core/HLE/sceKernel.cpp
|
||||
Core/HLE/sceKernel.h
|
||||
Core/HLE/sceKernelAlarm.cpp
|
||||
Core/HLE/sceKernelAlarm.h
|
||||
Core/HLE/sceKernelEventFlag.cpp
|
||||
Core/HLE/sceKernelEventFlag.h
|
||||
Core/HLE/sceKernelInterrupt.cpp
|
||||
Core/HLE/sceKernelInterrupt.h
|
||||
Core/HLE/sceKernelMbx.cpp
|
||||
Core/HLE/sceKernelMbx.h
|
||||
Core/HLE/sceKernelMemory.cpp
|
||||
Core/HLE/sceKernelMemory.h
|
||||
Core/HLE/sceKernelModule.cpp
|
||||
Core/HLE/sceKernelModule.h
|
||||
Core/HLE/sceKernelMsgPipe.cpp
|
||||
Core/HLE/sceKernelMsgPipe.h
|
||||
Core/HLE/sceKernelMutex.cpp
|
||||
Core/HLE/sceKernelMutex.h
|
||||
Core/HLE/sceKernelSemaphore.cpp
|
||||
Core/HLE/sceKernelSemaphore.h
|
||||
Core/HLE/sceKernelThread.cpp
|
||||
Core/HLE/sceKernelThread.h
|
||||
Core/HLE/sceKernelTime.cpp
|
||||
Core/HLE/sceKernelTime.h
|
||||
Core/HLE/sceKernelVTimer.cpp
|
||||
Core/HLE/sceKernelVTimer.h
|
||||
Core/HLE/sceMpeg.cpp
|
||||
Core/HLE/sceMpeg.h
|
||||
Core/HLE/sceNet.cpp
|
||||
Core/HLE/sceNet.h
|
||||
Core/HLE/sceOpenPSID.cpp
|
||||
Core/HLE/sceOpenPSID.h
|
||||
Core/HLE/sceParseHttp.cpp
|
||||
Core/HLE/sceParseHttp.h
|
||||
Core/HLE/sceParseUri.cpp
|
||||
Core/HLE/sceParseUri.h
|
||||
Core/HLE/scePower.cpp
|
||||
Core/HLE/scePower.h
|
||||
Core/HLE/scePsmf.cpp
|
||||
Core/HLE/scePsmf.h
|
||||
Core/HLE/sceRtc.cpp
|
||||
Core/HLE/sceRtc.h
|
||||
Core/HLE/sceSas.cpp
|
||||
Core/HLE/sceSas.h
|
||||
Core/HLE/sceSsl.cpp
|
||||
Core/HLE/sceSsl.h
|
||||
Core/HLE/scesupPreAcc.cpp
|
||||
Core/HLE/scesupPreAcc.h
|
||||
Core/HLE/sceUmd.cpp
|
||||
Core/HLE/sceUmd.h
|
||||
Core/HLE/sceUtility.cpp
|
||||
Core/HLE/sceUtility.h
|
||||
Core/HLE/sceVaudio.cpp
|
||||
Core/HLE/sceVaudio.h
|
||||
Core/HW/MemoryStick.cpp
|
||||
Core/HW/MemoryStick.h
|
||||
Core/HW/SasAudio.cpp
|
||||
Core/HW/SasAudio.h
|
||||
Core/Host.cpp
|
||||
Core/Host.h
|
||||
Core/Loaders.cpp
|
||||
Core/Loaders.h
|
||||
Core/MIPS/JitCommon/JitCommon.cpp
|
||||
Core/MIPS/JitCommon/JitCommon.h
|
||||
Core/MIPS/MIPS.cpp
|
||||
Core/MIPS/MIPS.h
|
||||
Core/MIPS/MIPSAnalyst.cpp
|
||||
Core/MIPS/MIPSAnalyst.h
|
||||
Core/MIPS/MIPSCodeUtils.cpp
|
||||
Core/MIPS/MIPSCodeUtils.h
|
||||
Core/MIPS/MIPSDebugInterface.cpp
|
||||
Core/MIPS/MIPSDebugInterface.h
|
||||
Core/MIPS/MIPSDis.cpp
|
||||
Core/MIPS/MIPSDis.h
|
||||
Core/MIPS/MIPSDisVFPU.cpp
|
||||
Core/MIPS/MIPSDisVFPU.h
|
||||
Core/MIPS/MIPSInt.cpp
|
||||
Core/MIPS/MIPSInt.h
|
||||
Core/MIPS/MIPSIntVFPU.cpp
|
||||
Core/MIPS/MIPSIntVFPU.h
|
||||
Core/MIPS/MIPSTables.cpp
|
||||
Core/MIPS/MIPSTables.h
|
||||
Core/MIPS/MIPSVFPUUtils.cpp
|
||||
Core/MIPS/MIPSVFPUUtils.h
|
||||
Core/MemMap.cpp
|
||||
Core/MemMap.h
|
||||
Core/MemMapFunctions.cpp
|
||||
Core/PSPLoaders.cpp
|
||||
Core/PSPLoaders.h
|
||||
Core/PSPMixer.cpp
|
||||
Core/PSPMixer.h
|
||||
Core/System.cpp
|
||||
Core/System.h
|
||||
Core/Util/BlockAllocator.cpp
|
||||
Core/Util/BlockAllocator.h
|
||||
Core/Util/PPGeDraw.cpp
|
||||
Core/Util/PPGeDraw.h
|
||||
Core/Util/Pool.h
|
||||
Core/Util/ppge_atlas.cpp
|
||||
Core/Util/ppge_atlas.h
|
||||
$<TARGET_OBJECTS:GPU>
|
||||
Globals.h)
|
||||
target_link_libraries(${CoreLibName} Common native kirk
|
||||
${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||
setup_target_project(${CoreLibName} Core)
|
||||
|
||||
add_library(GPU OBJECT
|
||||
GPU/GLES/DisplayListInterpreter.cpp
|
||||
GPU/GLES/DisplayListInterpreter.h
|
||||
GPU/GLES/FragmentShaderGenerator.cpp
|
||||
GPU/GLES/FragmentShaderGenerator.h
|
||||
GPU/GLES/Framebuffer.cpp
|
||||
GPU/GLES/Framebuffer.h
|
||||
GPU/GLES/ShaderManager.cpp
|
||||
GPU/GLES/ShaderManager.h
|
||||
GPU/GLES/StateMapping.cpp
|
||||
GPU/GLES/StateMapping.h
|
||||
GPU/GLES/TextureCache.cpp
|
||||
GPU/GLES/TextureCache.h
|
||||
GPU/GLES/TransformPipeline.cpp
|
||||
GPU/GLES/TransformPipeline.h
|
||||
GPU/GLES/VertexDecoder.cpp
|
||||
GPU/GLES/VertexDecoder.h
|
||||
GPU/GLES/VertexShaderGenerator.cpp
|
||||
GPU/GLES/VertexShaderGenerator.h
|
||||
GPU/GPUInterface.h
|
||||
GPU/GPUState.cpp
|
||||
GPU/GPUState.h
|
||||
GPU/Math3D.cpp
|
||||
GPU/Math3D.h
|
||||
# GPU/Null/NullDisplayListInterpreter.cpp
|
||||
# GPU/Null/NullDisplayListInterpreter.h
|
||||
GPU/Null/NullGpu.cpp
|
||||
GPU/Null/NullGpu.h
|
||||
GPU/ge_constants.h)
|
||||
setup_target_project(GPU GPU)
|
||||
|
||||
if(WIN32)
|
||||
add_executable(PPSSPPWindows WIN32
|
||||
Windows/Breakpoints.h
|
||||
Windows/DSoundStream.cpp
|
||||
Windows/DSoundStream.h
|
||||
Windows/Debugger/CPURegsInterface.h
|
||||
Windows/Debugger/CtrlDisAsmView.cpp
|
||||
Windows/Debugger/CtrlDisAsmView.h
|
||||
Windows/Debugger/CtrlMemView.cpp
|
||||
Windows/Debugger/CtrlMemView.h
|
||||
Windows/Debugger/CtrlRegisterList.cpp
|
||||
Windows/Debugger/CtrlRegisterList.h
|
||||
Windows/Debugger/Debugger.h
|
||||
Windows/Debugger/Debugger_Disasm.cpp
|
||||
Windows/Debugger/Debugger_Disasm.h
|
||||
Windows/Debugger/Debugger_MemoryDlg.cpp
|
||||
Windows/Debugger/Debugger_MemoryDlg.h
|
||||
Windows/Debugger/Debugger_Misc.cpp
|
||||
Windows/Debugger/Debugger_Misc.h
|
||||
# Windows/Debugger/Debugger_Profiler.cpp
|
||||
# Windows/Debugger/Debugger_Profiler.h
|
||||
Windows/Debugger/Debugger_SymbolMap.h
|
||||
Windows/Debugger/Debugger_VFPUDlg.cpp
|
||||
Windows/Debugger/Debugger_VFPUDlg.h
|
||||
Windows/Debugger/SimpleELF.h
|
||||
# Windows/DlgDynaView.cpp
|
||||
# Windows/DlgDynaView.h
|
||||
Windows/EmuThread.cpp
|
||||
Windows/EmuThread.h
|
||||
Windows/Globals.cpp
|
||||
Windows/InputBox.cpp
|
||||
Windows/InputBox.h
|
||||
Windows/InputDevice.cpp
|
||||
Windows/InputDevice.h
|
||||
Windows/KeyboardDevice.cpp
|
||||
Windows/KeyboardDevice.h
|
||||
Windows/MIPSCompALU.h
|
||||
Windows/MIPSCompBranch.h
|
||||
Windows/OpenGLBase.cpp
|
||||
Windows/OpenGLBase.h
|
||||
Windows/W32Util/DialogManager.cpp
|
||||
Windows/W32Util/DialogManager.h
|
||||
Windows/W32Util/Misc.cpp
|
||||
Windows/W32Util/Misc.h
|
||||
Windows/W32Util/PropertySheet.cpp
|
||||
Windows/W32Util/PropertySheet.h
|
||||
Windows/W32Util/ShellUtil.cpp
|
||||
Windows/W32Util/ShellUtil.h
|
||||
Windows/W32Util/XPTheme.h
|
||||
Windows/WindowsFileSystem.h
|
||||
Windows/WindowsHost.cpp
|
||||
Windows/WindowsHost.h
|
||||
Windows/WndMainWindow.cpp
|
||||
Windows/WndMainWindow.h
|
||||
Windows/XPTheme.h
|
||||
Windows/XinputDevice.cpp
|
||||
Windows/XinputDevice.h
|
||||
Windows/main.cpp
|
||||
Windows/main.h
|
||||
Windows/ppsspp.rc
|
||||
Windows/resource.h
|
||||
Windows/stdafx.cpp
|
||||
Windows/stdafx.h)
|
||||
target_link_libraries(PPSSPPWindows ${CoreLibName}
|
||||
kernel32 user32 gdi32 shell32 comctl32 dsound xinput)
|
||||
setup_target_project(PPSSPPWindows Windows)
|
||||
endif()
|
||||
|
||||
if(HEADLESS)
|
||||
add_executable(PPSSPPHeadless headless/Headless.cpp)
|
||||
target_link_libraries(PPSSPPHeadless ${CoreLibName}
|
||||
${COCOA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
|
||||
setup_target_project(PPSSPPHeadless headless)
|
||||
endif()
|
||||
|
||||
set(NativeAppSource
|
||||
android/jni/NativeApp.cpp
|
||||
android/jni/EmuScreen.cpp
|
||||
android/jni/MenuScreens.cpp
|
||||
android/jni/GamepadEmu.cpp
|
||||
android/jni/UIShader.cpp
|
||||
android/jni/ui_atlas.cpp)
|
||||
set(NativeAssets
|
||||
android/assets/ui_atlas.zim
|
||||
assets/ppge_atlas.zim)
|
||||
set(LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT} ${nativeExtraLibs})
|
||||
|
||||
if (TargetBin)
|
||||
add_executable(${TargetBin} ${NativeAppSource})
|
||||
target_link_libraries(${TargetBin} ${LinkCommon})
|
||||
endif()
|
||||
|
||||
file(INSTALL ${NativeAssets} DESTINATION assets)
|
||||
|
||||
#include(CPack)
|
@ -61,7 +61,7 @@ const u8 *ARMXEmitter::AlignCodePage()
|
||||
|
||||
void ARMXEmitter::Flush()
|
||||
{
|
||||
__clear_cache (startcode, code);
|
||||
__builtin___clear_cache (startcode, code);
|
||||
SLEEP(0);
|
||||
}
|
||||
void ARMXEmitter::SetCC(CCFlags cond)
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#undef _SP
|
||||
|
||||
|
@ -22,7 +22,7 @@ set(SRCS
|
||||
if (ARM)
|
||||
set(SRCS ${SRCS} ArmEmitter.cpp ArmABI.cpp)
|
||||
else()
|
||||
set(SRCS ${SRCS} CPUDetect.cpp MathUtil.cpp Thunk.cpp x64Analyzer.cpp x64Emitter.cpp x86Disasm.cpp ABI.cpp)
|
||||
set(SRCS ${SRCS} CPUDetect.cpp MathUtil.cpp Thunk.cpp x64Analyzer.cpp x64Emitter.cpp ABI.cpp)
|
||||
endif (ARM)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
@ -93,6 +93,10 @@ CPUInfo::CPUInfo() {
|
||||
Detect();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Detects the various cpu features
|
||||
void CPUInfo::Detect()
|
||||
{
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(ANDROID) || defined(BLACKBERRY)
|
||||
#if defined(ARM)
|
||||
#define _M_ARM32
|
||||
#endif
|
||||
|
||||
|
@ -193,7 +193,6 @@
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
<ClInclude Include="x86Disasm.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ABI.cpp" />
|
||||
@ -243,7 +242,9 @@
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
<ClCompile Include="x86Disasm.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -43,7 +43,6 @@
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
<ClInclude Include="ArmEmitter.h" />
|
||||
<ClInclude Include="ArmABI.h" />
|
||||
<ClInclude Include="x86Disasm.h" />
|
||||
<ClInclude Include="Action.h" />
|
||||
<ClInclude Include="FixedSizeUnorderedSet.h" />
|
||||
</ItemGroup>
|
||||
@ -73,8 +72,10 @@
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
<ClCompile Include="ArmEmitter.cpp" />
|
||||
<ClCompile Include="ArmABI.cpp" />
|
||||
<ClCompile Include="x86Disasm.cpp" />
|
||||
<ClCompile Include="Action.cpp" />
|
||||
<ClCompile Include="ThunkArm.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -25,6 +25,10 @@
|
||||
#define SLEEP(x) usleep(x*1000)
|
||||
#endif
|
||||
|
||||
#ifdef IOS
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
template <bool> struct CompileTimeAssert;
|
||||
template<> struct CompileTimeAssert<true> {};
|
||||
|
||||
@ -36,7 +40,8 @@ template<> struct CompileTimeAssert<true> {};
|
||||
#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
|
||||
|
||||
#if defined __GNUC__ && !defined __SSSE3__
|
||||
#if !defined(ANDROID) && !defined(BLACKBERRY)
|
||||
// Assume !ARM = x86
|
||||
#if !defined(ARM)
|
||||
#include <emmintrin.h>
|
||||
static __inline __m128i __attribute__((__always_inline__))
|
||||
_mm_shuffle_epi8(__m128i a, __m128i mask)
|
||||
@ -63,7 +68,8 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
|
||||
#ifdef GEKKO
|
||||
#define Crash()
|
||||
#else
|
||||
#if !defined(ANDROID) && !defined(BLACKBERRY)
|
||||
// Assume !ARM = x86
|
||||
#if !defined(ARM)
|
||||
#define Crash() {asm ("int $3");}
|
||||
#else
|
||||
#define Crash() {kill( getpid(), SIGINT ) ; }
|
||||
|
@ -23,7 +23,11 @@
|
||||
|
||||
// Directory seperators, do we need this?
|
||||
#define DIR_SEP "/"
|
||||
#define DIR_SEP_CHR '/'
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEP_CHRS "/\\"
|
||||
#else
|
||||
#define DIR_SEP_CHRS "/"
|
||||
#endif
|
||||
|
||||
// The user data dir
|
||||
#define ROOT_DIR "."
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// strcasecmp
|
||||
#ifdef __APPLE__
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
#include "FileSearch.h"
|
||||
@ -98,7 +102,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
|
||||
((s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) ))
|
||||
{
|
||||
std::string full_name;
|
||||
if (_strPath.c_str()[_strPath.size()-1] == DIR_SEP_CHR)
|
||||
if (strchr(DIR_SEP_CHRS, _strPath.c_str()[_strPath.size()-1]))
|
||||
full_name = _strPath + s;
|
||||
else
|
||||
full_name = _strPath + DIR_SEP + s;
|
||||
|
@ -48,11 +48,38 @@
|
||||
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#ifdef BSD4_4
|
||||
#if !defined(__linux__) && !defined(_WIN32) && !defined(__QNX__)
|
||||
#define stat64 stat
|
||||
#define fstat64 fstat
|
||||
#endif
|
||||
|
||||
// Hack
|
||||
#if defined(__SYMBIAN32__)
|
||||
static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
||||
struct dirent *readdir_entry;
|
||||
|
||||
readdir_entry = readdir(dirp);
|
||||
if (readdir_entry == NULL) {
|
||||
*result = NULL;
|
||||
return errno;
|
||||
}
|
||||
|
||||
*entry = *readdir_entry;
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// No thread safe
|
||||
#ifdef _WIN32
|
||||
inline struct tm* localtime_r (const time_t *clock, struct tm *result) {
|
||||
if (!clock || !result) return NULL;
|
||||
memcpy(result,localtime(clock),sizeof(*result));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// This namespace has various generic functions related to files and paths.
|
||||
// The code still needs a ton of cleanup.
|
||||
// REMEMBER: strdup considered harmful!
|
||||
@ -66,7 +93,7 @@ static void StripTailDirSlashes(std::string &fname)
|
||||
if (fname.length() > 1)
|
||||
{
|
||||
size_t i = fname.length() - 1;
|
||||
while (fname[i] == DIR_SEP_CHR)
|
||||
while (strchr(DIR_SEP_CHRS, fname[i]))
|
||||
fname[i--] = '\0';
|
||||
}
|
||||
return;
|
||||
@ -188,17 +215,26 @@ bool CreateFullPath(const std::string &fullPath)
|
||||
}
|
||||
|
||||
size_t position = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Skip the drive letter, no need to create C:\.
|
||||
position = 3;
|
||||
#endif
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Find next sub path
|
||||
position = fullPath.find(DIR_SEP_CHR, position);
|
||||
position = fullPath.find_first_of(DIR_SEP_CHRS, position);
|
||||
|
||||
// we're done, yay!
|
||||
if (position == fullPath.npos)
|
||||
{
|
||||
if (!File::Exists(fullPath))
|
||||
File::CreateDir(fullPath);
|
||||
return true;
|
||||
|
||||
}
|
||||
std::string subPath = fullPath.substr(0, position);
|
||||
if (!File::IsDirectory(subPath))
|
||||
if (!File::Exists(subPath))
|
||||
File::CreateDir(subPath);
|
||||
|
||||
// A safety check
|
||||
@ -320,6 +356,34 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||
#endif
|
||||
}
|
||||
|
||||
tm GetModifTime(const std::string &filename)
|
||||
{
|
||||
tm return_time = {0};
|
||||
if (!Exists(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "GetCreateTime: failed %s: No such file", filename.c_str());
|
||||
return return_time;
|
||||
}
|
||||
|
||||
if (IsDirectory(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "GetCreateTime: failed %s: is a directory", filename.c_str());
|
||||
return return_time;
|
||||
}
|
||||
struct stat64 buf;
|
||||
if (stat64(filename.c_str(), &buf) == 0)
|
||||
{
|
||||
DEBUG_LOG(COMMON, "GetCreateTime: %s: %lld",
|
||||
filename.c_str(), (long long)buf.st_mtime);
|
||||
localtime_r((time_t*)&buf.st_mtime,&return_time);
|
||||
return return_time;
|
||||
}
|
||||
|
||||
ERROR_LOG(COMMON, "GetCreateTime: Stat failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
return return_time;
|
||||
}
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string &filename)
|
||||
{
|
||||
@ -417,14 +481,16 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
|
||||
FSTEntry entry;
|
||||
const std::string virtualName(ffd.cFileName);
|
||||
#else
|
||||
struct dirent dirent, *result = NULL;
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
||||
struct dirent_large diren;
|
||||
struct dirent *result = NULL;
|
||||
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
if (!dirp)
|
||||
return 0;
|
||||
|
||||
// non windows loop
|
||||
while (!readdir_r(dirp, &dirent, &result) && result)
|
||||
while (!readdir_r(dirp, (dirent*)&diren, &result) && result)
|
||||
{
|
||||
FSTEntry entry;
|
||||
const std::string virtualName(result->d_name);
|
||||
@ -502,7 +568,7 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
(virtualName[2] == '\0')))
|
||||
continue;
|
||||
|
||||
std::string newPath = directory + DIR_SEP_CHR + virtualName;
|
||||
std::string newPath = directory + DIR_SEP + virtualName;
|
||||
if (IsDirectory(newPath))
|
||||
{
|
||||
if (!DeleteDirRecursively(newPath))
|
||||
@ -534,11 +600,13 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
if (!File::Exists(source_path)) return;
|
||||
if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
|
||||
|
||||
struct dirent dirent, *result = NULL;
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
||||
struct dirent_large diren;
|
||||
struct dirent *result = NULL;
|
||||
DIR *dirp = opendir(source_path.c_str());
|
||||
if (!dirp) return;
|
||||
|
||||
while (!readdir_r(dirp, &dirent, &result) && result)
|
||||
while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
|
||||
{
|
||||
const std::string virtualName(result->d_name);
|
||||
// check for "." and ".."
|
||||
|
@ -56,6 +56,9 @@ bool Exists(const std::string &filename);
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string &filename);
|
||||
|
||||
// Returns struct with modification date of file
|
||||
tm GetModifTime(const std::string &filename);
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string &filename);
|
||||
|
||||
|
@ -25,68 +25,84 @@
|
||||
|
||||
// Not fully featured, no safety checking yet. Add features as needed.
|
||||
|
||||
// TODO: "inline" storage?
|
||||
|
||||
template <class T, int N>
|
||||
class FixedSizeQueue
|
||||
{
|
||||
T *storage;
|
||||
int head;
|
||||
int tail;
|
||||
int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
|
||||
|
||||
// Make copy constructor private for now.
|
||||
FixedSizeQueue(FixedSizeQueue &other) { }
|
||||
|
||||
class FixedSizeQueue {
|
||||
public:
|
||||
FixedSizeQueue()
|
||||
{
|
||||
storage = new T[N];
|
||||
FixedSizeQueue() {
|
||||
storage_ = new T[N];
|
||||
clear();
|
||||
}
|
||||
|
||||
~FixedSizeQueue()
|
||||
{
|
||||
delete [] storage;
|
||||
~FixedSizeQueue() {
|
||||
delete [] storage_;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
head = 0;
|
||||
tail = 0;
|
||||
count = 0;
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
count_ = 0;
|
||||
}
|
||||
|
||||
void push(T t) {
|
||||
storage[tail] = t;
|
||||
tail++;
|
||||
if (tail == N)
|
||||
tail = 0;
|
||||
count++;
|
||||
storage_[tail_] = t;
|
||||
tail_++;
|
||||
if (tail_ == N)
|
||||
tail_ = 0;
|
||||
count_++;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
head++;
|
||||
if (head == N)
|
||||
head = 0;
|
||||
count--;
|
||||
head_++;
|
||||
if (head_ == N)
|
||||
head_ = 0;
|
||||
count_--;
|
||||
}
|
||||
|
||||
/*
|
||||
void push_array(const T *ptr, size_t num) {
|
||||
// TODO: memcpy
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
push(ptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void pop_array(T *outptr, size_t num) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
outptr[i] = front();
|
||||
pop();
|
||||
}
|
||||
}*/
|
||||
|
||||
T pop_front() {
|
||||
const T &temp = storage[head];
|
||||
const T &temp = storage_[head_];
|
||||
pop();
|
||||
return temp;
|
||||
}
|
||||
|
||||
T &front() { return storage[head]; }
|
||||
const T &front() const { return storage[head]; }
|
||||
T &front() { return storage_[head_]; }
|
||||
|
||||
const T &front() const { return storage_[head_]; }
|
||||
|
||||
size_t size() const {
|
||||
return count;
|
||||
return count_;
|
||||
}
|
||||
|
||||
int room() const {
|
||||
return N - count_;
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
return count;
|
||||
return count_;
|
||||
}
|
||||
|
||||
private:
|
||||
T *storage_;
|
||||
int head_;
|
||||
int tail_;
|
||||
int count_; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
|
||||
|
||||
// Make copy constructor private for now.
|
||||
FixedSizeQueue(FixedSizeQueue &other) { }
|
||||
};
|
||||
|
||||
#endif // _FIXED_SIZE_QUEUE_H_
|
||||
|
@ -10,7 +10,7 @@ class FixedSizeUnorderedSet
|
||||
public:
|
||||
bool insert(T item)
|
||||
{
|
||||
if (count_ < maxCount - 1)
|
||||
if (count_ < (int)maxCount - 1)
|
||||
{
|
||||
data_[count_++] = item;
|
||||
return true;
|
||||
@ -41,7 +41,7 @@ public:
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return count_;
|
||||
return (size_t)count_;
|
||||
}
|
||||
|
||||
T &operator[](size_t index) {
|
||||
|
@ -19,6 +19,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
@ -23,6 +23,10 @@
|
||||
#define INFO_LEVEL 4 // General information.
|
||||
#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow.
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
namespace LogTypes
|
||||
{
|
||||
|
||||
@ -41,6 +45,7 @@ enum LOG_TYPE {
|
||||
INTC,
|
||||
MEMMAP,
|
||||
SOUND,
|
||||
SAS,
|
||||
HLE,
|
||||
TIMER,
|
||||
VIDEO,
|
||||
@ -102,6 +107,7 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type,
|
||||
}
|
||||
#define _dbg_assert_msg_(_t_, _a_, ...)\
|
||||
if (!(_a_)) {\
|
||||
printf(__VA_ARGS__); \
|
||||
ERROR_LOG(_t_, __VA_ARGS__); \
|
||||
if (!PanicYesNo(__VA_ARGS__)) {Crash();} \
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
@ -22,6 +22,9 @@
|
||||
#include "Timer.h"
|
||||
#include "Thread.h"
|
||||
#include "FileUtil.h"
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <e32debug.h>
|
||||
#endif
|
||||
|
||||
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
|
||||
const char *file, int line, const char* fmt, ...)
|
||||
@ -39,28 +42,30 @@ LogManager *LogManager::m_logManager = NULL;
|
||||
LogManager::LogManager()
|
||||
{
|
||||
// create log files
|
||||
m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
|
||||
m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
|
||||
m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
|
||||
m_Log[LogTypes::CPU] = new LogContainer("CPU", "CPU");
|
||||
m_Log[LogTypes::LOADER] = new LogContainer("LOAD", "Loader");
|
||||
m_Log[LogTypes::IO] = new LogContainer("IO", "IO");
|
||||
m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "DiscIO");
|
||||
m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
|
||||
m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
|
||||
m_Log[LogTypes::G3D] = new LogContainer("G3D", "3D Graphics");
|
||||
m_Log[LogTypes::DMA] = new LogContainer("DMA", "DMA");
|
||||
m_Log[LogTypes::INTC] = new LogContainer("INTC", "Interrupts");
|
||||
m_Log[LogTypes::MEMMAP] = new LogContainer("MM", "Memory Map");
|
||||
m_Log[LogTypes::SOUND] = new LogContainer("SND", "Sound");
|
||||
m_Log[LogTypes::HLE] = new LogContainer("HLE", "HLE");
|
||||
m_Log[LogTypes::TIMER] = new LogContainer("TMR", "Timer");
|
||||
m_Log[LogTypes::VIDEO] = new LogContainer("VID", "Video");
|
||||
m_Log[LogTypes::DYNA_REC] = new LogContainer("Jit", "JIT compiler");
|
||||
m_Log[LogTypes::NETPLAY] = new LogContainer("NET", "Net play");
|
||||
m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
|
||||
m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
|
||||
m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
|
||||
m_Log[LogTypes::CPU] = new LogContainer("CPU", "CPU");
|
||||
m_Log[LogTypes::LOADER] = new LogContainer("LOAD", "Loader");
|
||||
m_Log[LogTypes::IO] = new LogContainer("IO", "IO");
|
||||
m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "DiscIO");
|
||||
m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
|
||||
m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
|
||||
m_Log[LogTypes::G3D] = new LogContainer("G3D", "3D Graphics");
|
||||
m_Log[LogTypes::DMA] = new LogContainer("DMA", "DMA");
|
||||
m_Log[LogTypes::INTC] = new LogContainer("INTC", "Interrupts");
|
||||
m_Log[LogTypes::MEMMAP] = new LogContainer("MM", "Memory Map");
|
||||
m_Log[LogTypes::SOUND] = new LogContainer("SND", "Sound");
|
||||
m_Log[LogTypes::SAS] = new LogContainer("SAS", "Sound Mixer (Sas)");
|
||||
m_Log[LogTypes::HLE] = new LogContainer("HLE", "HLE");
|
||||
m_Log[LogTypes::TIMER] = new LogContainer("TMR", "Timer");
|
||||
m_Log[LogTypes::VIDEO] = new LogContainer("VID", "Video");
|
||||
m_Log[LogTypes::DYNA_REC] = new LogContainer("Jit", "JIT compiler");
|
||||
m_Log[LogTypes::NETPLAY] = new LogContainer("NET", "Net play");
|
||||
m_Log[LogTypes::ME] = new LogContainer("ME", "Media Engine");
|
||||
|
||||
#ifndef ANDROID
|
||||
// Remove file logging on small devices
|
||||
#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY)
|
||||
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
|
||||
m_consoleLog = new ConsoleListener();
|
||||
m_debuggerLog = new DebuggerLogListener();
|
||||
@ -69,7 +74,7 @@ LogManager::LogManager()
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
m_Log[i]->SetEnable(true);
|
||||
#ifndef ANDROID
|
||||
#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY)
|
||||
m_Log[i]->AddListener(m_fileLog);
|
||||
m_Log[i]->AddListener(m_consoleLog);
|
||||
#ifdef _MSC_VER
|
||||
@ -84,7 +89,7 @@ LogManager::~LogManager()
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
#ifndef ANDROID
|
||||
#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY)
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog);
|
||||
@ -93,7 +98,7 @@ LogManager::~LogManager()
|
||||
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
delete m_Log[i];
|
||||
#ifndef ANDROID
|
||||
#if !defined(ANDROID) && !defined(IOS) && !defined(BLACKBERRY)
|
||||
delete m_fileLog;
|
||||
delete m_consoleLog;
|
||||
#endif
|
||||
@ -101,24 +106,24 @@ LogManager::~LogManager()
|
||||
|
||||
void LogManager::SaveConfig(IniFile::Section *section)
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||
{
|
||||
section->Set((std::string(m_Log[i]->GetShortName()) + "Enabled").c_str(), m_Log[i]->IsEnabled());
|
||||
section->Set((std::string(m_Log[i]->GetShortName()) + "Level").c_str(), (int)m_Log[i]->GetLevel());
|
||||
}
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||
{
|
||||
section->Set((std::string(m_Log[i]->GetShortName()) + "Enabled").c_str(), m_Log[i]->IsEnabled());
|
||||
section->Set((std::string(m_Log[i]->GetShortName()) + "Level").c_str(), (int)m_Log[i]->GetLevel());
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::LoadConfig(IniFile::Section *section)
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||
{
|
||||
bool enabled;
|
||||
int level;
|
||||
section->Get((std::string(m_Log[i]->GetShortName()) + "Enabled").c_str(), &enabled, true);
|
||||
section->Get((std::string(m_Log[i]->GetShortName()) + "Level").c_str(), &level, 0);
|
||||
m_Log[i]->SetEnable(enabled);
|
||||
m_Log[i]->SetLevel((LogTypes::LOG_LEVELS)level);
|
||||
}
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
|
||||
{
|
||||
bool enabled;
|
||||
int level;
|
||||
section->Get((std::string(m_Log[i]->GetShortName()) + "Enabled").c_str(), &enabled, true);
|
||||
section->Get((std::string(m_Log[i]->GetShortName()) + "Level").c_str(), &level, 0);
|
||||
m_Log[i]->SetEnable(enabled);
|
||||
m_Log[i]->SetLevel((LogTypes::LOG_LEVELS)level);
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char *format, va_list args)
|
||||
@ -132,8 +137,8 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const
|
||||
CharArrayFromFormatV(temp, MAX_MSGLEN, format, args);
|
||||
|
||||
static const char level_to_char[7] = "-NEWID";
|
||||
char formattedTime[13];
|
||||
Common::Timer::GetTimeFormatted(formattedTime);
|
||||
char formattedTime[13];
|
||||
Common::Timer::GetTimeFormatted(formattedTime);
|
||||
sprintf(msg, "%s %s:%u %c[%s]: %s\n",
|
||||
formattedTime,
|
||||
file, line, level_to_char[(int)level],
|
||||
@ -197,7 +202,11 @@ void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lk(m_log_lock);
|
||||
#ifdef __SYMBIAN32__
|
||||
RDebug::Printf("%s",msg);
|
||||
#else
|
||||
m_logfile << msg << std::flush;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
|
@ -22,10 +22,10 @@
|
||||
#include <numeric>
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef USE_SSE
|
||||
static u32 saved_sse_state = _mm_getcsr();
|
||||
static const u32 default_sse_state = _mm_getcsr();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace MathUtil
|
||||
@ -116,19 +116,25 @@ namespace MathUtil
|
||||
|
||||
void LoadDefaultSSEState()
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
_mm_setcsr(default_sse_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void LoadSSEState()
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
_mm_setcsr(saved_sse_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SaveSSEState()
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
saved_sse_state = _mm_getcsr();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MatrixMul(int n, const float *a, const float *b, float *result)
|
||||
@ -247,3 +253,28 @@ void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result)
|
||||
MatrixMul(4, a.data, b.data, result.data);
|
||||
}
|
||||
|
||||
int Pow2roundup(int x)
|
||||
{
|
||||
if (x < 0)
|
||||
return 0;
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return x+1;
|
||||
}
|
||||
|
||||
int GetPow2(int x)
|
||||
{
|
||||
int ret = 0;
|
||||
int val = 1;
|
||||
while(x > val)
|
||||
{
|
||||
ret++;
|
||||
val *= 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,14 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#ifndef ARM
|
||||
#define USE_SSE
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSE
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MathUtil
|
||||
@ -146,6 +153,8 @@ struct Rectangle
|
||||
|
||||
inline float pow2f(float x) {return x * x;}
|
||||
inline double pow2(double x) {return x * x;}
|
||||
int Pow2roundup(int x);
|
||||
int GetPow2(int x);
|
||||
|
||||
|
||||
/*
|
||||
@ -163,7 +172,6 @@ float MathFloatVectorSum(const std::vector<float>&);
|
||||
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
|
||||
|
||||
|
||||
// Tiny matrix/vector library.
|
||||
// Used for things like Free-Look in the gfx backend.
|
||||
|
||||
|
@ -33,6 +33,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__SYMBIAN32__)
|
||||
// Also Xbox 360
|
||||
#define UNUSABLE_MMAP 1
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
@ -98,7 +103,8 @@ int ashmem_unpin_region(int fd, size_t offset, size_t len)
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
static std::string ram_temp_file = "/tmp/gc_mem.tmp";
|
||||
// do not make this "static"
|
||||
std::string ram_temp_file = "/tmp/gc_mem.tmp";
|
||||
#else
|
||||
SYSTEM_INFO sysInfo;
|
||||
#endif
|
||||
@ -107,12 +113,12 @@ SYSTEM_INFO sysInfo;
|
||||
// Windows mappings need to be on 64K boundaries, due to Alpha legacy.
|
||||
#ifdef _WIN32
|
||||
size_t roundup(size_t x) {
|
||||
int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
|
||||
return (x + gran - 1) & ~(gran - 1);
|
||||
int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
|
||||
return (x + gran - 1) & ~(gran - 1);
|
||||
}
|
||||
#else
|
||||
size_t roundup(size_t x) {
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -121,8 +127,8 @@ void MemArena::GrabLowMemSpace(size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
|
||||
GetSystemInfo(&sysInfo);
|
||||
#elif ANDROID
|
||||
GetSystemInfo(&sysInfo);
|
||||
#elif defined(ANDROID)
|
||||
// Use ashmem so we don't have to allocate a file on disk!
|
||||
fd = ashmem_create_region("PPSSPP_RAM", size);
|
||||
// Note that it appears that ashmem is pinned by default, so no need to pin.
|
||||
@ -131,6 +137,8 @@ void MemArena::GrabLowMemSpace(size_t size)
|
||||
ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
|
||||
return;
|
||||
}
|
||||
#elif defined(UNUSABLE_MMAP)
|
||||
// Do nothing as we are using malloc()
|
||||
#else
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode);
|
||||
@ -155,6 +163,8 @@ void MemArena::ReleaseSpace()
|
||||
#ifdef _WIN32
|
||||
CloseHandle(hMemoryMapping);
|
||||
hMemoryMapping = 0;
|
||||
#elif defined(UNUSABLE_MMAP)
|
||||
// Do nothing as we are using malloc()
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
@ -164,30 +174,32 @@ void MemArena::ReleaseSpace()
|
||||
void *MemArena::CreateView(s64 offset, size_t size, void *base)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
size = roundup(size);
|
||||
void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base);
|
||||
if (!ptr) {
|
||||
//ERROR_LOG(MEMMAP, "Failed to map memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg());
|
||||
} else {
|
||||
//ERROR_LOG(MEMMAP, "Mapped memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg());
|
||||
}
|
||||
return ptr;
|
||||
size = roundup(size);
|
||||
void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base);
|
||||
if (!ptr) {
|
||||
//ERROR_LOG(MEMMAP, "Failed to map memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg());
|
||||
} else {
|
||||
//ERROR_LOG(MEMMAP, "Mapped memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg());
|
||||
}
|
||||
return ptr;
|
||||
#elif defined(UNUSABLE_MMAP)
|
||||
void *retval = malloc(size);
|
||||
if (!retval)
|
||||
{
|
||||
NOTICE_LOG(MEMMAP, "malloc failed: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return retval;
|
||||
#else
|
||||
void *retval = mmap(
|
||||
base, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | ((base == 0) ? 0 : MAP_FIXED),
|
||||
fd, offset);
|
||||
void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |
|
||||
((base == 0) ? 0 : MAP_FIXED), fd, offset);
|
||||
|
||||
if (retval == MAP_FAILED)
|
||||
{
|
||||
NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
return retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -196,6 +208,8 @@ void MemArena::ReleaseView(void* view, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UnmapViewOfFile(view);
|
||||
#elif defined(UNUSABLE_MMAP)
|
||||
free(view);
|
||||
#else
|
||||
munmap(view, size);
|
||||
#endif
|
||||
@ -225,14 +239,17 @@ u8* MemArena::Find4GBBase()
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
}
|
||||
return base;
|
||||
#elif defined(UNUSABLE_MMAP)
|
||||
// We are unable to use relative addresses due to lack of mmap()
|
||||
return NULL;
|
||||
#else
|
||||
void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE,
|
||||
void* base = mmap(0, 0x5000000, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_SHARED, -1, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
|
||||
PanicAlert("Failed to map 100 MB of memory space: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
munmap(base, 0x10000000);
|
||||
munmap(base, 0x5000000);
|
||||
return static_cast<u8*>(base);
|
||||
#endif
|
||||
#endif
|
||||
@ -390,7 +407,7 @@ void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemAr
|
||||
if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
|
||||
arena->ReleaseView(*views[i].out_ptr, views[i].size);
|
||||
*views[i].out_ptr = NULL;
|
||||
if (views[i].out_ptr_low)
|
||||
if (views[i].out_ptr_low)
|
||||
*views[i].out_ptr_low = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -25,19 +25,27 @@
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
#define PAGE_MASK (4096-1)
|
||||
#else
|
||||
#define PAGE_MASK (getpagesize() - 1)
|
||||
#endif
|
||||
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
|
||||
#endif
|
||||
|
||||
|
||||
// This is purposely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
|
||||
@ -45,6 +53,9 @@ void* AllocateExecutableMemory(size_t size, bool low)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
// On Symbian, we will need to create an RChunk and allocate with ->CreateLocalCode(size, size);
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, -1, 0);
|
||||
#else
|
||||
static char *map_hint = 0;
|
||||
#if defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
@ -67,7 +78,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
|
||||
|
||||
// printf("Mapped executable memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (ptr == MAP_FAILED)
|
||||
{
|
||||
@ -75,7 +86,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
|
||||
#else
|
||||
if (ptr == NULL)
|
||||
{
|
||||
#endif
|
||||
#endif
|
||||
PanicAlert("Failed to allocate executable memory");
|
||||
}
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
@ -122,9 +133,12 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
#else
|
||||
void* ptr = NULL;
|
||||
#ifdef ANDROID
|
||||
ptr = memalign(alignment, size);
|
||||
ptr = memalign(alignment, size);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
// On Symbian, we will want to create an RChunk.
|
||||
ptr = malloc(size);
|
||||
#else
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -17,10 +17,14 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__SYMBIAN32__)
|
||||
#define __thread
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
|
@ -98,6 +98,10 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Default non library dependent panic alert
|
||||
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style)
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
#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)
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
|
||||
// GCC 4.4 provides <condition_variable>
|
||||
#include <condition_variable>
|
||||
#else
|
||||
|
@ -5,7 +5,7 @@
|
||||
#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)
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
|
||||
// GCC 4.4 provides <mutex>
|
||||
#include <mutex>
|
||||
#else
|
||||
|
@ -5,7 +5,7 @@
|
||||
#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)
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !defined(ANDROID) && !defined(__SYMBIAN32__)
|
||||
// GCC 4.4 provides <thread>
|
||||
#ifndef _GLIBCXX_USE_SCHED_YIELD
|
||||
#define _GLIBCXX_USE_SCHED_YIELD
|
||||
|
@ -83,11 +83,10 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::setfill('0') << std::hex;
|
||||
|
||||
|
||||
for (int line = 0; size; ++data, --size)
|
||||
{
|
||||
oss << std::setw(2) << (int)*data;
|
||||
|
||||
if (line_len == ++line)
|
||||
{
|
||||
oss << '\n';
|
||||
@ -212,8 +211,8 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P
|
||||
_CompleteFilename = _Path;
|
||||
|
||||
// check for seperator
|
||||
if (DIR_SEP_CHR != *_CompleteFilename.rbegin())
|
||||
_CompleteFilename += DIR_SEP_CHR;
|
||||
if (!strchr(DIR_SEP_CHRS, *_CompleteFilename.rbegin()))
|
||||
_CompleteFilename += DIR_SEP;
|
||||
|
||||
// add the filename
|
||||
_CompleteFilename += _Filename;
|
||||
@ -259,31 +258,31 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
||||
// Uri encode and decode.
|
||||
// RFC1630, RFC1738, RFC2396
|
||||
|
||||
//#include <string>
|
||||
//#include <assert.h>
|
||||
|
||||
const char HEX2DEC[256] =
|
||||
// Some compilers don't like to assume (int)-1 will safely cast to (char)-1 as
|
||||
// the MSBs aren't 0's. Workaround the issue while maintaining table spacing.
|
||||
#define N1 (char)-1
|
||||
const char HEX2DEC[256] =
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
/* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
/* 0 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 1 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 2 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,N1,N1, N1,N1,N1,N1,
|
||||
|
||||
/* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 4 */ N1,10,11,12, 13,14,15,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 5 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 6 */ N1,10,11,12, 13,14,15,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 7 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
|
||||
/* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* 8 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* 9 */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* A */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* B */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
|
||||
/* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
/* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
|
||||
/* C */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* D */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* E */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1,
|
||||
/* F */ N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1, N1,N1,N1,N1
|
||||
};
|
||||
|
||||
std::string UriDecode(const std::string & sSrc)
|
||||
|
@ -129,7 +129,7 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
#ifdef __APPLE__
|
||||
thread_policy_set(pthread_mach_thread_np(thread),
|
||||
THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1);
|
||||
#elif defined __linux__ || defined BSD4_4
|
||||
#elif (defined __linux__ || defined BSD4_4) && !defined(ANDROID)
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
||||
|
@ -33,7 +33,8 @@
|
||||
#define INFINITE 0xffffffff
|
||||
#endif
|
||||
|
||||
#if !defined(ANDROID) && !defined(BLACKBERRY)
|
||||
// Assume !ARM = x86
|
||||
#if !defined(ARM)
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "Common.h"
|
||||
#if defined(ANDROID) || defined(BLACKBERRY)
|
||||
#if defined(ARM)
|
||||
#include "ArmEmitter.h"
|
||||
#else
|
||||
#include "x64Emitter.h"
|
||||
@ -38,7 +38,7 @@
|
||||
// we don't want to pollute the stack, so we store away regs somewhere global.
|
||||
// NOT THREAD SAFE. This may only be used from the CPU thread.
|
||||
// Any other thread using this stuff will be FATAL.
|
||||
#if defined(ANDROID) || defined(BLACKBERRY)
|
||||
#if defined(ARM)
|
||||
class ThunkManager : public ArmGen::ARMXCodeBlock
|
||||
#else
|
||||
class ThunkManager : public Gen::XCodeBlock
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
#if !defined(_M_IX86) && !defined(_M_X64)
|
||||
#error Don't build this on arm.
|
||||
#error "Don't build this on arm."
|
||||
#endif
|
||||
|
||||
namespace Gen
|
||||
|
@ -1,828 +0,0 @@
|
||||
// X86 disassembler - 95% ripped from some GNU source if I remember
|
||||
// correctly, probably GCC or some GCC tool
|
||||
|
||||
#if defined(ANDROID) || defined(BLACKBERRY)
|
||||
#error DO NOT COMPILE THIS INTO ANDROID BUILDS
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cstdarg>
|
||||
#include "x86Disasm.h"
|
||||
|
||||
/*==============================unasmt.h==============================*/
|
||||
/* Percent tokens in strings:
|
||||
First char after '%':
|
||||
A - direct address
|
||||
C - reg of r/m picks control register
|
||||
D - reg of r/m picks debug register
|
||||
E - r/m picks operand
|
||||
F - flags register
|
||||
G - reg of r/m picks general register
|
||||
I - immediate data
|
||||
J - relative IP offset
|
||||
M - r/m picks memory
|
||||
O - no r/m, offset only
|
||||
R - mod of r/m picks register only
|
||||
S - reg of r/m picks segment register
|
||||
T - reg of r/m picks test register
|
||||
X - DS:ESI
|
||||
Y - ES:EDI
|
||||
2 - prefix of two-byte opcode
|
||||
e - put in 'e' if use32 (second char is part of reg name)
|
||||
put in 'w' for use16 or 'd' for use32 (second char is 'w')
|
||||
f - floating point (second char is esc value)
|
||||
g - do r/m group 'n'
|
||||
p - prefix
|
||||
s - size override (second char is a,o)
|
||||
Second char after '%':
|
||||
a - two words in memory (BOUND)
|
||||
b - byte
|
||||
c - byte or word
|
||||
d - dword
|
||||
p - 32 or 48 bit pointer
|
||||
s - six byte pseudo-descriptor
|
||||
v - word or dword
|
||||
w - word
|
||||
F - use floating regs in mod/rm
|
||||
1-8 - group number, esc value, etc
|
||||
*/
|
||||
|
||||
char *opmap1[] = {
|
||||
/* 0 */
|
||||
"add %Eb,%Gb", "add %Ev,%Gv", "add %Gb,%Eb", "add %Gv,%Ev",
|
||||
"add al,%Ib", "add %eax,%Iv", "push es", "pop es",
|
||||
"or %Eb,%Gb", "or %Ev,%Gv", "or %Gb,%Eb", "or %Gv,%Ev",
|
||||
"or al,%Ib", "or %eax,%Iv", "push cs", "%2 ",
|
||||
/* 1 */
|
||||
"adc %Eb,%Gb", "adc %Ev,%Gv", "adc %Gb,%Eb", "adc %Gv,%Ev",
|
||||
"adc al,%Ib", "adc %eax,%Iv", "push ss", "pop ss",
|
||||
"sbb %Eb,%Gb", "sbb %Ev,%Gv", "sbb %Gb,%Eb", "sbb %Gv,%Ev",
|
||||
"sbb al,%Ib", "sbb %eax,%Iv", "push ds", "pop ds",
|
||||
/* 2 */
|
||||
"and %Eb,%Gb", "and %Ev,%Gv", "and %Gb,%Eb", "and %Gv,%Ev",
|
||||
"and al,%Ib", "and %eax,%Iv", "%pe", "daa",
|
||||
"sub %Eb,%Gb", "sub %Ev,%Gv", "sub %Gb,%Eb", "sub %Gv,%Ev",
|
||||
"sub al,%Ib", "sub %eax,%Iv", "%pc", "das",
|
||||
/* 3 */
|
||||
"xor %Eb,%Gb", "xor %Ev,%Gv", "xor %Gb,%Eb", "xor %Gv,%Ev",
|
||||
"xor al,%Ib", "xor %eax,%Iv", "%ps", "aaa",
|
||||
"cmp %Eb,%Gb", "cmp %Ev,%Gv", "cmp %Gb,%Eb", "cmp %Gv,%Ev",
|
||||
"cmp al,%Ib", "cmp %eax,%Iv", "%pd", "aas",
|
||||
/* 4 */
|
||||
"inc %eax", "inc %ecx", "inc %edx", "inc %ebx",
|
||||
"inc %esp", "inc %ebp", "inc %esi", "inc %edi",
|
||||
"dec %eax", "dec %ecx", "dec %edx", "dec %ebx",
|
||||
"dec %esp", "dec %ebp", "dec %esi", "dec %edi",
|
||||
/* 5 */
|
||||
"push %eax", "push %ecx", "push %edx", "push %ebx",
|
||||
"push %esp", "push %ebp", "push %esi", "push %edi",
|
||||
"pop %eax", "pop %ecx", "pop %edx", "pop %ebx",
|
||||
"pop %esp", "pop %ebp", "pop %esi", "pop %edi",
|
||||
/* 6 */
|
||||
"pusha", "popa", "bound %Gv,%Ma", "arpl %Ew,%Rw",
|
||||
"%pf", "%pg", "%so", "%sa",
|
||||
"push %Iv", "imul %Gv,%Ev,%Iv", "push %Ib", "imul %Gv,%Ev,%Ib",
|
||||
"insb", "ins%ew", "outsb", "outs%ew",
|
||||
/* 7 */
|
||||
"jo %Jb", "jno %Jb", "jnc %Jb", "jc %Jb",
|
||||
"jz %Jb", "jnz %Jb", "jbe %Jb", "jnbe %Jb",
|
||||
"js %Jb", "jns %Jb", "jpe %Jb", "jpo %Jb",
|
||||
"jl %Jb", "jge %Jb", "jle %Jb", "jg %Jb",
|
||||
/* 8 */
|
||||
"%g1 %Eb,%Ib", "%g1 %Ev,%Iv", "mov al,%Ib", "%g1 %Ev,+%Ib",
|
||||
"test %Eb,%Gb", "test %Ev,%Gv", "xchg %Eb,%Gb", "xchg %Ev,%Gv",
|
||||
"mov %Eb,%Gb", "mov %Ev,%Gv", "mov %Gb,%Eb", "mov %Gv,%Ev",
|
||||
"mov %Ew,%Sw", "lea %Gv,%M ", "mov %Sw,%Ew", "pop %Ev",
|
||||
/* 9 */
|
||||
"nop", "xchg %eax,%ecx", "xchg %eax,%edx", "xchg %eax,%ebx",
|
||||
"xchg %eax,%esp", "xchg %eax,%ebp", "xchg %eax,%esi", "xchg %eax,%edi",
|
||||
"cbw", "cwd", "call %Ap", "fwait",
|
||||
"push %eflags", "pop %eflags", "sahf", "lahf",
|
||||
/* a */
|
||||
"mov al,%Ob", "mov %eax,%Ov", "mov %Ob,al", "mov %Ov,%eax",
|
||||
"movsb %Xb,%Yb", "movs%ew %Xv,%Yv", "cmpsb %Xb,%Yb", "cmps%ew %Xv,%Yv",
|
||||
"test al,%Ib", "test %eax,%Iv", "stosb %Yb,al", "stos%ew %Yv,%eax",
|
||||
"lodsb al,%Xb", "lods%ew %eax,%Xv", "scasb al,%Xb", "scas%ew %eax,%Xv",
|
||||
/* b */
|
||||
"mov al,%Ib", "mov cl,%Ib", "mov dl,%Ib", "mov bl,%Ib",
|
||||
"mov ah,%Ib", "mov ch,%Ib", "mov dh,%Ib", "mov bh,%Ib",
|
||||
"mov %eax,%Iv", "mov %ecx,%Iv", "mov %edx,%Iv", "mov %ebx,%Iv",
|
||||
"mov %esp,%Iv", "mov %ebp,%Iv", "mov %esi,%Iv", "mov %edi,%Iv",
|
||||
/* c */
|
||||
"%g2 %Eb,%Ib", "%g2 %Ev,%Ib", "ret %Iw", "ret",
|
||||
"les %Gv,%Mp", "lds %Gv,%Mp", "mov %Eb,%Ib", "mov %Ev,%Iv",
|
||||
"enter %Iw,%Ib", "leave", "retf %Iw", "retf",
|
||||
"int 3", "int %Ib", "into", "iret",
|
||||
/* d */
|
||||
"%g2 %Eb,1", "%g2 %Ev,1", "%g2 %Eb,cl", "%g2 %Ev,cl",
|
||||
"aam", "aad", 0, "xlat",
|
||||
#if 0
|
||||
"esc 0,%Ib", "esc 1,%Ib", "esc 2,%Ib", "esc 3,%Ib",
|
||||
"esc 4,%Ib", "esc 5,%Ib", "esc 6,%Ib", "esc 7,%Ib",
|
||||
#else
|
||||
"%f0", "%f1", "%f2", "%f3",
|
||||
"%f4", "%f5", "%f6", "%f7",
|
||||
#endif
|
||||
/* e */
|
||||
"loopne %Jb", "loope %Jb", "loop %Jb", "jcxz %Jb",
|
||||
"in al,%Ib", "in %eax,%Ib", "out %Ib,al", "out %Ib,%eax",
|
||||
"call %Jv", "jmp %Jv", "jmp %Ap", "jmp %Jb",
|
||||
"in al,dx", "in %eax,dx", "out dx,al", "out dx,%eax",
|
||||
/* f */
|
||||
"lock %p ", 0, "repne %p ", "repe %p ",
|
||||
"hlt", "cmc", "%g3", "%g0",
|
||||
"clc", "stc", "cli", "sti",
|
||||
"cld", "std", "%g4", "%g5"
|
||||
};
|
||||
|
||||
char *second[] = {
|
||||
/* 0 */
|
||||
"%g6", "%g7", "lar %Gv,%Ew", "lsl %Gv,%Ew", 0, 0, "clts", 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 1 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 2 */
|
||||
"mov %Rd,%Cd", "mov %Rd,%Dd", "mov %Cd,%Rd", "mov %Dd,%Rd",
|
||||
"mov %Rd,%Td", 0, "mov %Td,%Rd", 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 3 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 8 */
|
||||
"jo %Jv", "jno %Jv", "jnc %Jv", "jc %Jv",
|
||||
"jz %Jv", "jnz %Jv", "jbe %Jv", "jnbe %Jv",
|
||||
"js %Jv", "jns %Jv", "jpe %Jv", "jpo %Jv",
|
||||
"jl %Jv", "jge %Jv", "jle %Jv", "jg %Jv",
|
||||
/* 9 */
|
||||
"seto %Eb", "setno %Eb", "setb %Eb", "setnb %Eb",
|
||||
"setz %Eb", "setnz %Eb", "setbe %Eb", "setnbe %Eb",
|
||||
"sets %Eb", "setns %Eb", "setp %Eb", "setnp %Eb",
|
||||
"setl %Eb", "setge %Eb", "setle %Eb", "setg %Eb",
|
||||
/* a */
|
||||
"push fs", "pop fs", 0, "bt %Ev,%Gv",
|
||||
"shld %Ev,%Gv,%Ib", "shld %Ev,%Gv,cl", 0, 0,
|
||||
"push gs", "pop gs", 0, "bts %Ev,%Gv",
|
||||
"shrd %Ev,%Gv,%Ib", "shrd %Ev,%Gv,cl", 0, "imul %Gv,%Ev",
|
||||
/* b */
|
||||
0, 0, "lss %Mp", "btr %Ev,%Gv",
|
||||
"lfs %Mp", "lgs %Mp", "movzx %Gv,%Eb", "movzx %Gv,%Ew",
|
||||
0, 0, "%g8 %Ev,%Ib", "btc %Ev,%Gv",
|
||||
"bsf %Gv,%Ev", "bsr%Gv,%Ev", "movsx %Gv,%Eb", "movsx %Gv,%Ew",
|
||||
/* c */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
char *groups[][8] = { /* group 0 is group 3 for %Ev set */
|
||||
{ "test %Ev,%Iv", "test %Ev,%Iv,", "not %Ev", "neg %Ev",
|
||||
"mul %eax,%Ev", "imul %eax,%Ev", "div %eax,%Ev", "idiv %eax,%Ev" },
|
||||
{ "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
|
||||
{ "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" },
|
||||
{ "test %Eb,%Ib", "test %Eb,%Ib,", "not %Eb", "neg %Eb",
|
||||
"mul al,%Eb", "imul al,%Eb", "div al,%Eb", "idiv al,%Eb" },
|
||||
{ "inc %Eb", "dec %Eb", 0, 0, 0, 0, 0, 0 },
|
||||
{ "inc %Ev", "dec %Ev", "call %Ev", "call %Ep",
|
||||
"jmp %Ev", "jmp %Ep", "push %Ev", 0 },
|
||||
{ "sldt %Ew", "str %Ew", "lldt %Ew", "ltr %Ew",
|
||||
"verr %Ew", "verw %Ew", 0, 0 },
|
||||
{ "sgdt %Ms", "sidt %Ms", "lgdt %Ms", "lidt %Ms",
|
||||
"smsw %Ew", 0, "lmsw %Ew", 0 },
|
||||
{ 0, 0, 0, 0, "bt", "bts", "btr", "btc" }
|
||||
};
|
||||
|
||||
/* zero here means invalid. If first entry starts with '*', use st(i) */
|
||||
/* no assumed %EFs here. Indexed by rm(modrm()) */
|
||||
char *f0[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
char *fop_9[] = { "*fxch st,%GF" };
|
||||
char *fop_10[] = { "fnop", 0, 0, 0, 0, 0, 0, 0 };
|
||||
char *fop_12[] = { "fchs", "fabs", 0, 0, "ftst", "fxam", 0, 0 };
|
||||
char *fop_13[] = { "fld1", "fldl2t", "fldl2e", "fldpi",
|
||||
"fldlg2", "fldln2", "fldz", 0 };
|
||||
char *fop_14[] = { "f2xm1", "fyl2x", "fptan", "fpatan",
|
||||
"fxtract", "fprem1", "fdecstp", "fincstp" };
|
||||
char *fop_15[] = { "fprem", "fyl2xp1", "fsqrt", "fsincos",
|
||||
"frndint", "fscale", "fsin", "fcos" };
|
||||
char *fop_21[] = { 0, "fucompp", 0, 0, 0, 0, 0, 0 };
|
||||
char *fop_28[] = { 0, 0, "fclex", "finit", 0, 0, 0, 0 };
|
||||
char *fop_32[] = { "*fadd %GF,st" };
|
||||
char *fop_33[] = { "*fmul %GF,st" };
|
||||
char *fop_36[] = { "*fsubr %GF,st" };
|
||||
char *fop_37[] = { "*fsub %GF,st" };
|
||||
char *fop_38[] = { "*fdivr %GF,st" };
|
||||
char *fop_39[] = { "*fdiv %GF,st" };
|
||||
char *fop_40[] = { "*ffree %GF" };
|
||||
char *fop_42[] = { "*fst %GF" };
|
||||
char *fop_43[] = { "*fstp %GF" };
|
||||
char *fop_44[] = { "*fucom %GF" };
|
||||
char *fop_45[] = { "*fucomp %GF" };
|
||||
char *fop_48[] = { "*faddp %GF,st" };
|
||||
char *fop_49[] = { "*fmulp %GF,st" };
|
||||
char *fop_51[] = { 0, "fcompp", 0, 0, 0, 0, 0, 0 };
|
||||
char *fop_52[] = { "*fsubrp %GF,st" };
|
||||
char *fop_53[] = { "*fsubp %GF,st" };
|
||||
char *fop_54[] = { "*fdivrp %GF,st" };
|
||||
char *fop_55[] = { "*fdivp %GF,st" };
|
||||
char *fop_60[] = { "fstsw ax", 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
char **fspecial[] = { /* 0=use st(i), 1=undefined 0 in fop_* means undefined */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, fop_9, fop_10, 0, fop_12, fop_13, fop_14, fop_15,
|
||||
f0, f0, f0, f0, f0, fop_21, f0, f0,
|
||||
f0, f0, f0, f0, fop_28, f0, f0, f0,
|
||||
fop_32, fop_33, f0, f0, fop_36, fop_37, fop_38, fop_39,
|
||||
fop_40, f0, fop_42, fop_43, fop_44, fop_45, f0, f0,
|
||||
fop_48, fop_49, f0, fop_51, fop_52, fop_53, fop_54, fop_55,
|
||||
f0, f0, f0, f0, fop_60, f0, f0, f0,
|
||||
};
|
||||
|
||||
char *floatops[] = { /* assumed " %EF" at end of each. mod != 3 only */
|
||||
/*00*/ "fadd", "fmul", "fcom", "fcomp",
|
||||
"fsub", "fsubr", "fdiv", "fdivr",
|
||||
/*08*/ "fld", 0, "fst", "fstp",
|
||||
"fldenv", "fldcw", "fstenv", "fstcw",
|
||||
/*16*/ "fiadd", "fimul", "ficomw", "ficompw",
|
||||
"fisub", "fisubr", "fidiv", "fidivr",
|
||||
/*24*/ "fild", 0, "fist", "fistp",
|
||||
"frstor", "fldt", 0, "fstpt",
|
||||
/*32*/ "faddq", "fmulq", "fcomq", "fcompq",
|
||||
"fsubq", "fsubrq", "fdivq", "fdivrq",
|
||||
/*40*/ "fldq", 0, "fstq", "fstpq",
|
||||
0, 0, "fsave", "fstsww",
|
||||
/*48*/ "fiaddw", "fimulw", "ficomw", "ficompw",
|
||||
"fisubw", "fisubrw", "fidivw", "fidivr",
|
||||
/*56*/ "fildw", 0, "fistw", "fistpw",
|
||||
"fbldt", "fildq", "fbstpt", "fistpq"
|
||||
};
|
||||
/*====================================================================*/
|
||||
|
||||
#define COL_DUMP (0)
|
||||
#define COL_INST (2)
|
||||
#define COL_PARM (12)
|
||||
|
||||
typedef unsigned long word32;
|
||||
typedef unsigned short word16;
|
||||
typedef unsigned char word8;
|
||||
typedef signed long int32;
|
||||
typedef signed short int16;
|
||||
typedef signed char int8;
|
||||
|
||||
int seg_size=32;
|
||||
|
||||
static word8 buf[20];
|
||||
static word32 vaddr;
|
||||
static int bufp, bufe;
|
||||
static char ubuf[100], *ubufp, *ubufp2, *ubufp2end;
|
||||
static int col;
|
||||
|
||||
char *hex1=""; // ="0x";
|
||||
char *hex2=""; // ="h";
|
||||
|
||||
unsigned char *codepnt;
|
||||
unsigned codeseg;
|
||||
long codeoff;
|
||||
|
||||
static void percent(char c, char t);
|
||||
|
||||
void uprintf(char *s,...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, s);
|
||||
vsprintf(ubufp,s,va);
|
||||
while(*ubufp) ubufp++;
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static void ua_str(char *s)
|
||||
{
|
||||
int c;
|
||||
if (!s)
|
||||
{
|
||||
uprintf("<invalid>");
|
||||
return;
|
||||
}
|
||||
while ((c = *s++) != 0)
|
||||
{
|
||||
if (c == '%')
|
||||
{
|
||||
c = *s++;
|
||||
percent((char)c, *s++);
|
||||
}
|
||||
else
|
||||
if (c == ' ')
|
||||
do uprintf(" "); while(ubufp-ubuf<COL_PARM);
|
||||
else
|
||||
uprintf("%c",c);
|
||||
}
|
||||
}
|
||||
|
||||
static word8 getbyte()
|
||||
{
|
||||
if(ubufp2<ubufp2end)
|
||||
{
|
||||
sprintf(ubufp2, "%02X", *codepnt);
|
||||
while(*ubufp2) ubufp2++;
|
||||
}
|
||||
else *ubufp2end='*';
|
||||
codeoff++;
|
||||
return *(codepnt++);
|
||||
}
|
||||
|
||||
static int prefix;
|
||||
static int modrmv;
|
||||
static int sibv;
|
||||
static int opsize;
|
||||
static int addrsize;
|
||||
|
||||
static int modrm()
|
||||
{
|
||||
if (modrmv == -1)
|
||||
modrmv = getbyte();
|
||||
return modrmv;
|
||||
}
|
||||
|
||||
static int sib()
|
||||
{
|
||||
if (sibv == -1)
|
||||
sibv = getbyte();
|
||||
return sibv;
|
||||
}
|
||||
|
||||
#define mod(a) (((a)>>6)&7)
|
||||
#define reg(a) (((a)>>3)&7)
|
||||
#define rm(a) ((a)&7)
|
||||
#define ss(a) (((a)>>6)&7)
|
||||
#define indx(a) (((a)>>3)&7)
|
||||
#define base(a) ((a)&7)
|
||||
|
||||
int bytes(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'b':
|
||||
return 1;
|
||||
case 'w':
|
||||
return 2;
|
||||
case 'd':
|
||||
return 4;
|
||||
case 'v':
|
||||
if (opsize == 32)
|
||||
return 4;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ohex(char c, int extend, int optional, int defsize)
|
||||
{
|
||||
int n=0, s=0, i;
|
||||
int32 delta;
|
||||
unsigned char buf[6];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
break;
|
||||
case 'b':
|
||||
n = 1;
|
||||
break;
|
||||
case 'w':
|
||||
n = 2;
|
||||
break;
|
||||
case 'd':
|
||||
n = 4;
|
||||
break;
|
||||
case 's':
|
||||
n = 6;
|
||||
break;
|
||||
case 'c':
|
||||
case 'v':
|
||||
if (defsize == 32)
|
||||
n = 4;
|
||||
else
|
||||
n = 2;
|
||||
break;
|
||||
case 'p':
|
||||
if (defsize == 32)
|
||||
n = 6;
|
||||
else
|
||||
n = 4;
|
||||
s = 1;
|
||||
break;
|
||||
}
|
||||
for (i=0; i<n; i++)
|
||||
buf[i] = getbyte();
|
||||
for (; i<extend; i++)
|
||||
buf[i] = (buf[i-1] & 0x80) ? 0xff : 0;
|
||||
if (s)
|
||||
{
|
||||
uprintf("%s02x%02x%s:", hex1,buf[n-1], buf[n-2],hex2);
|
||||
n -= 2;
|
||||
}
|
||||
switch (n)
|
||||
{
|
||||
case 1:
|
||||
delta = *(signed char *)buf;
|
||||
break;
|
||||
case 2:
|
||||
delta = *(signed int *)buf;
|
||||
break;
|
||||
case 4:
|
||||
delta = *(signed long *)buf;
|
||||
break;
|
||||
}
|
||||
if (extend > n)
|
||||
{
|
||||
if (delta || !optional)
|
||||
{
|
||||
if(delta<0) { uprintf("-"); delta=-delta; }
|
||||
else uprintf("+");
|
||||
}
|
||||
}
|
||||
switch (n)
|
||||
{
|
||||
case 1:
|
||||
uprintf("%s%02X%s",hex1,(unsigned char)delta,hex2);
|
||||
break;
|
||||
case 2:
|
||||
uprintf("%s%04X%s",hex1,(unsigned int)delta,hex2);
|
||||
break;
|
||||
case 4:
|
||||
uprintf("%s%08lX%s",hex1,(unsigned long)delta,hex2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *reg_names[3][8]=
|
||||
{
|
||||
"al","cl","dl","bl","ah","ch","dh","bh",
|
||||
"ax","cx","dx","bx","sp","bp","si","di",
|
||||
"eax","ecx","edx","ebx","esp","ebp","esi","edi" };
|
||||
|
||||
void reg_name(int which, char size)
|
||||
{
|
||||
if (size == 'F')
|
||||
{
|
||||
uprintf("st(%d)", which);
|
||||
return;
|
||||
}
|
||||
if (((size == 'v') && (opsize == 32)) || (size == 'd'))
|
||||
{
|
||||
uprintf("%c",'e');
|
||||
}
|
||||
if (size == 'b')
|
||||
{
|
||||
uprintf("%c","acdbacdb"[which]);
|
||||
uprintf("%c","llllhhhh"[which]);
|
||||
}
|
||||
else
|
||||
{
|
||||
uprintf("%c","acdbsbsd"[which]);
|
||||
uprintf("%c","xxxxppii"[which]);
|
||||
}
|
||||
}
|
||||
|
||||
void do_sib(int m)
|
||||
{
|
||||
int s, i, b;
|
||||
s = ss(sib());
|
||||
i = indx(sib());
|
||||
b = base(sib());
|
||||
switch (b)
|
||||
{
|
||||
case 0: ua_str("%p:[eax"); break;
|
||||
case 1: ua_str("%p:[ecx"); break;
|
||||
case 2: ua_str("%p:[edx"); break;
|
||||
case 3: ua_str("%p:[ebx"); break;
|
||||
case 4: ua_str("%p:[esp"); break;
|
||||
case 5:
|
||||
if (m == 0)
|
||||
{
|
||||
ua_str("%p:[");
|
||||
ohex('d', 4, 0, addrsize);
|
||||
}
|
||||
else
|
||||
ua_str("%p:[ebp");
|
||||
break;
|
||||
case 6: ua_str("%p:[esi"); break;
|
||||
case 7: ua_str("%p:[edi"); break;
|
||||
}
|
||||
switch (i)
|
||||
{
|
||||
case 0: uprintf("+eax"); break;
|
||||
case 1: uprintf("+ecx"); break;
|
||||
case 2: uprintf("+edx"); break;
|
||||
case 3: uprintf("+ebx"); break;
|
||||
case 4: break;
|
||||
case 5: uprintf("+ebp"); break;
|
||||
case 6: uprintf("+esi"); break;
|
||||
case 7: uprintf("+edi"); break;
|
||||
}
|
||||
if (i != 4)
|
||||
switch (s)
|
||||
{
|
||||
case 0: uprintf(""); break;
|
||||
case 1: uprintf("*2"); break;
|
||||
case 2: uprintf("*4"); break;
|
||||
case 3: uprintf("*8"); break;
|
||||
}
|
||||
}
|
||||
|
||||
void do_modrm(char t)
|
||||
{
|
||||
int m = mod(modrm());
|
||||
int r = rm(modrm());
|
||||
int extend = (addrsize == 32) ? 4 : 2;
|
||||
if (m == 3)
|
||||
{
|
||||
reg_name(r, t);
|
||||
return;
|
||||
}
|
||||
switch(bytes(t))
|
||||
{
|
||||
case 1 : ua_str("byte ptr "); break;
|
||||
case 2 : ua_str("word ptr "); break;
|
||||
case 4 : ua_str("dword ptr "); break;
|
||||
default : ua_str("?word ptr "); break;
|
||||
}
|
||||
if ((m == 0) && (r == 5) && (addrsize == 32))
|
||||
{
|
||||
ua_str("%p:[");
|
||||
ohex('d', extend, 0, addrsize);
|
||||
uprintf("%c",']');
|
||||
return;
|
||||
}
|
||||
if ((m == 0) && (r == 6) && (addrsize == 16))
|
||||
{
|
||||
ua_str("%p:[");
|
||||
ohex('w', extend, 0, addrsize);
|
||||
uprintf("%c",']');
|
||||
return;
|
||||
}
|
||||
if ((addrsize != 32) || (r != 4))
|
||||
ua_str("%p:[");
|
||||
if (addrsize == 16)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case 0: uprintf("bx+si"); break;
|
||||
case 1: uprintf("bx+di"); break;
|
||||
case 2: uprintf("bp+si"); break;
|
||||
case 3: uprintf("bp+di"); break;
|
||||
case 4: uprintf("si"); break;
|
||||
case 5: uprintf("di"); break;
|
||||
case 6: uprintf("bp"); break;
|
||||
case 7: uprintf("bx"); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case 0: uprintf("eax"); break;
|
||||
case 1: uprintf("ecx"); break;
|
||||
case 2: uprintf("edx"); break;
|
||||
case 3: uprintf("ebx"); break;
|
||||
case 4: do_sib(m); break;
|
||||
case 5: uprintf("ebp"); break;
|
||||
case 6: uprintf("esi"); break;
|
||||
case 7: uprintf("edi"); break;
|
||||
}
|
||||
}
|
||||
switch (m)
|
||||
{
|
||||
case 1:
|
||||
ohex('b', extend, 1, addrsize);
|
||||
break;
|
||||
case 2:
|
||||
uprintf("+");
|
||||
ohex('v', extend, 1, addrsize);
|
||||
break;
|
||||
}
|
||||
uprintf("%c",']');
|
||||
}
|
||||
|
||||
static void floating_point(int e1)
|
||||
{
|
||||
int esc = e1*8 + reg(modrm());
|
||||
if (mod(modrm()) == 3)
|
||||
{
|
||||
if (fspecial[esc])
|
||||
{
|
||||
if(fspecial[esc][0] && fspecial[esc][0][0] == '*')
|
||||
{
|
||||
ua_str(fspecial[esc][0]+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fspecial[esc][rm(modrm())]) ua_str(fspecial[esc][rm(modrm())]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ua_str(floatops[esc]);
|
||||
ua_str(" %EF");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ua_str(floatops[esc]);
|
||||
ua_str(" %EF");
|
||||
}
|
||||
}
|
||||
|
||||
static void percent(char c, char t)
|
||||
{
|
||||
word32 vofs;
|
||||
long l;
|
||||
int extend = (addrsize == 32) ? 4 : 2;
|
||||
switch (c)
|
||||
{
|
||||
case 'A':
|
||||
ohex(t, extend, 0, addrsize);
|
||||
break;
|
||||
case 'C':
|
||||
uprintf("C%d", reg(modrm()));
|
||||
break;
|
||||
case 'D':
|
||||
uprintf("D%d", reg(modrm()));
|
||||
break;
|
||||
case 'E':
|
||||
do_modrm(t);
|
||||
break;
|
||||
case 'G':
|
||||
if (t == 'F')
|
||||
reg_name(rm(modrm()), t);
|
||||
else
|
||||
reg_name(reg(modrm()), t);
|
||||
break;
|
||||
case 'I':
|
||||
ohex(t, 0, 0, opsize);
|
||||
break;
|
||||
case 'J':
|
||||
switch (bytes(t))
|
||||
{
|
||||
case 1:
|
||||
vofs = (int8)getbyte();
|
||||
break;
|
||||
case 2:
|
||||
vofs = getbyte();
|
||||
vofs += getbyte()<<8;
|
||||
vofs = (int16)vofs;
|
||||
break;
|
||||
case 4:
|
||||
vofs = (word32)getbyte();
|
||||
vofs |= (word32)getbyte() << 8;
|
||||
vofs |= (word32)getbyte() << 16;
|
||||
vofs |= (word32)getbyte() << 24;
|
||||
break;
|
||||
}
|
||||
l=vofs+codeoff;
|
||||
if(l<0x10000L)
|
||||
uprintf("%s%04lx%s %c", hex1, l, hex2,
|
||||
(vofs & 0x80000000L) ? 0x18 : 0x19);
|
||||
else
|
||||
uprintf("%s%08lX%s %c", hex1, l, hex2,
|
||||
(vofs & 0x80000000L) ? 0x18 : 0x19);
|
||||
break;
|
||||
case 'M':
|
||||
do_modrm(t);
|
||||
break;
|
||||
case 'O':
|
||||
ua_str("%p:[");
|
||||
ohex(t, extend, 0, addrsize);
|
||||
uprintf("%c",']');
|
||||
break;
|
||||
case 'R':
|
||||
reg_name(reg(modrm()), t);
|
||||
//do_modrm(t);
|
||||
break;
|
||||
case 'S':
|
||||
uprintf("%c","ecsdfg"[reg(modrm())]);
|
||||
uprintf("%c",'s');
|
||||
break;
|
||||
case 'T':
|
||||
uprintf("tr%d", reg(modrm()));
|
||||
break;
|
||||
case 'X':
|
||||
uprintf("ds:[");
|
||||
if (addrsize == 32)
|
||||
uprintf("%c",'e');
|
||||
uprintf("si]");
|
||||
break;
|
||||
case 'Y':
|
||||
uprintf("es:[");
|
||||
if (addrsize == 32)
|
||||
uprintf("%c",'e');
|
||||
uprintf("di]");
|
||||
break;
|
||||
case '2':
|
||||
ua_str(second[getbyte()]);
|
||||
break;
|
||||
case 'e':
|
||||
if (opsize == 32)
|
||||
{
|
||||
if (t == 'w')
|
||||
uprintf("%c",'d');
|
||||
else
|
||||
{
|
||||
uprintf("%c",'e');
|
||||
uprintf("%c",t);
|
||||
}
|
||||
}
|
||||
else
|
||||
uprintf("%c",t);
|
||||
break;
|
||||
case 'f':
|
||||
floating_point(t-'0');
|
||||
break;
|
||||
case 'g':
|
||||
ua_str(groups[t-'0'][reg(modrm())]);
|
||||
break;
|
||||
case 'p':
|
||||
switch (t)
|
||||
{
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 's':
|
||||
prefix = t;
|
||||
ua_str(opmap1[getbyte()]);
|
||||
break;
|
||||
case ':':
|
||||
if (prefix)
|
||||
uprintf("%cs:", prefix);
|
||||
break;
|
||||
case ' ':
|
||||
ua_str(opmap1[getbyte()]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
switch (t)
|
||||
{
|
||||
case 'a':
|
||||
addrsize = 48 - addrsize;
|
||||
ua_str(opmap1[getbyte()]);
|
||||
break;
|
||||
case 'o':
|
||||
opsize = 48 - opsize;
|
||||
ua_str(opmap1[getbyte()]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *unasm(int segmentsize)
|
||||
{
|
||||
seg_size=segmentsize;
|
||||
|
||||
prefix = 0;
|
||||
modrmv = sibv = -1;
|
||||
opsize = addrsize = seg_size;
|
||||
ubufp = ubuf;
|
||||
|
||||
memset(ubuf,0,100);
|
||||
|
||||
//sprintf(ubuf,"%04X:%08lX ",codeseg,codeoff);
|
||||
ubufp2=ubuf+COL_DUMP;
|
||||
ubufp2end=ubuf+COL_INST-2;
|
||||
ubufp=COL_INST+ubuf;
|
||||
|
||||
ua_str(opmap1[getbyte()]);
|
||||
while(--ubufp>=ubuf) if(!*ubufp) *ubufp=' ';
|
||||
|
||||
return(ubuf);
|
||||
}
|
||||
|
||||
char *disasmx86(unsigned char *opcode1,int codeoff1,int *len)
|
||||
{
|
||||
char *res;
|
||||
codepnt=opcode1;
|
||||
codeseg=0;
|
||||
codeoff=codeoff1;
|
||||
res=unasm(32);
|
||||
*len=codeoff-codeoff1;
|
||||
return(res);
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(ANDROID) || defined(BLACKBERRY)
|
||||
#error DO NOT COMPILE THIS INTO ANDROID BUILDS
|
||||
#endif
|
||||
|
||||
char *disasmx86(unsigned char *opcode1,int codeoff1,int *len);
|
@ -1,6 +1,12 @@
|
||||
set(SRCS
|
||||
Debugger/Breakpoints.cpp
|
||||
Debugger/SymbolMap.cpp
|
||||
Dialog/PSPDialog.cpp
|
||||
Dialog/PSPMsgDialog.cpp
|
||||
Dialog/PSPPlaceholderDialog.cpp
|
||||
Dialog/PSPSaveDialog.cpp
|
||||
Dialog/SavedataParam.cpp
|
||||
Dialog/PSPOskDialog.cpp
|
||||
MIPS/MIPS.cpp
|
||||
MIPS/MIPSAnalyst.cpp
|
||||
MIPS/MIPSCodeUtils.cpp
|
||||
@ -13,6 +19,7 @@ set(SRCS
|
||||
MIPS/MIPSVFPUUtils.cpp
|
||||
MIPS/JitCommon/JitCommon.cpp
|
||||
ELF/ElfReader.cpp
|
||||
ELF/ParamSFO.cpp
|
||||
ELF/PrxDecrypter.cpp
|
||||
HLE/HLE.cpp
|
||||
HLE/HLETables.cpp
|
||||
@ -23,6 +30,7 @@ set(SRCS
|
||||
HLE/sceDisplay.cpp
|
||||
HLE/sceDmac.cpp
|
||||
HLE/sceGe.cpp
|
||||
HLE/sceFont.cpp
|
||||
HLE/sceHprm.cpp
|
||||
HLE/sceHttp.cpp
|
||||
HLE/sceImpose.cpp
|
||||
@ -48,13 +56,22 @@ set(SRCS
|
||||
HLE/sceSas.cpp
|
||||
HLE/sceUmd.cpp
|
||||
HLE/sceUtility.cpp
|
||||
HLE/sceParseUri.cpp
|
||||
HLE/sceSsl.cpp
|
||||
HLE/sceParseUri.cpp
|
||||
HLE/sceParseHttp.cpp
|
||||
HLE/scesupPreAcc.cpp
|
||||
HLE/sceVaudio.cpp
|
||||
HW/MemoryStick.cpp
|
||||
HW/MediaEngine.cpp
|
||||
HW/SasAudio.cpp
|
||||
FileSystems/BlockDevices.cpp
|
||||
FileSystems/ISOFileSystem.cpp
|
||||
FileSystems/DirectoryFileSystem.cpp
|
||||
FileSystems/MetaFileSystem.cpp
|
||||
Util/BlockAllocator.cpp
|
||||
Util/ppge_atlas.cpp
|
||||
Util/PPGeDraw.cpp
|
||||
CPU.cpp
|
||||
CoreTiming.cpp
|
||||
Config.cpp
|
||||
|
@ -41,7 +41,7 @@ private:
|
||||
u32 id;
|
||||
public:
|
||||
virtual void SingleStep() = 0;
|
||||
virtual void RunLoopUntil(u64 globalTicks) = 0;
|
||||
virtual int RunLoopUntil(u64 globalTicks) = 0;
|
||||
};
|
||||
|
||||
#define MAX_NUM_CPU 2
|
||||
|
@ -45,18 +45,25 @@ void CConfig::Load(const char *iniFileName)
|
||||
general->Get("FirstRun", &bFirstRun, true);
|
||||
general->Get("AutoLoadLast", &bAutoLoadLast, false);
|
||||
general->Get("AutoRun", &bAutoRun, false);
|
||||
general->Get("Jit", &bJIT, false);
|
||||
general->Get("ConfirmOnQuit", &bConfirmOnQuit, false);
|
||||
general->Get("IgnoreBadMemAccess", &bIgnoreBadMemAccess, true);
|
||||
general->Get("DisplayFramebuffer", &bDisplayFramebuffer, false);
|
||||
general->Get("CurrentDirectory", ¤tDirectory, "");
|
||||
general->Get("ShowFPSCounter", &bShowFPSCounter, false);
|
||||
general->Get("ShowDebuggerOnLoad", &bShowDebuggerOnLoad, false);
|
||||
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
|
||||
cpu->Get("Core", &iCpuCore, 0);
|
||||
|
||||
IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics");
|
||||
graphics->Get("ShowFPSCounter", &bShowFPSCounter, false);
|
||||
graphics->Get("DisplayFramebuffer", &bDisplayFramebuffer, false);
|
||||
graphics->Get("WindowZoom", &iWindowZoom, 1);
|
||||
graphics->Get("BufferedRendering", &bBufferedRendering, true);
|
||||
|
||||
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
|
||||
sound->Get("Enable", &bEnableSound, true);
|
||||
|
||||
IniFile::Section *control = iniFile.GetOrCreateSection("Control");
|
||||
control->Get("ShowStick", &bShowAnalogStick, false);
|
||||
control->Get("ShowTouchControls", &bShowTouchControls, true);
|
||||
}
|
||||
|
||||
void CConfig::Save()
|
||||
@ -70,18 +77,25 @@ void CConfig::Save()
|
||||
general->Set("FirstRun", bFirstRun);
|
||||
general->Set("AutoLoadLast", bAutoLoadLast);
|
||||
general->Set("AutoRun", bAutoRun);
|
||||
general->Set("Jit", bJIT);
|
||||
general->Set("ConfirmOnQuit", bConfirmOnQuit);
|
||||
general->Set("IgnoreBadMemAccess", bIgnoreBadMemAccess);
|
||||
general->Set("DisplayFramebuffer", bDisplayFramebuffer);
|
||||
general->Set("CurrentDirectory", currentDirectory);
|
||||
general->Set("ShowFPSCounter", bShowFPSCounter);
|
||||
general->Set("ShowDebuggerOnLoad", bShowDebuggerOnLoad);
|
||||
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
|
||||
cpu->Set("Core", iCpuCore);
|
||||
|
||||
IniFile::Section *graphics = iniFile.GetOrCreateSection("Graphics");
|
||||
graphics->Set("ShowFPSCounter", bShowFPSCounter);
|
||||
graphics->Set("DisplayFramebuffer", bDisplayFramebuffer);
|
||||
graphics->Set("WindowZoom", iWindowZoom);
|
||||
graphics->Set("BufferedRendering", bBufferedRendering);
|
||||
|
||||
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
|
||||
sound->Set("Enable", bEnableSound);
|
||||
|
||||
IniFile::Section *control = iniFile.GetOrCreateSection("Control");
|
||||
control->Set("ShowStick", bShowAnalogStick);
|
||||
control->Set("ShowTouchControls", bShowTouchControls);
|
||||
|
||||
iniFile.Save(iniFilename_.c_str());
|
||||
NOTICE_LOG(LOADER, "Config saved: %s", iniFilename_.c_str());
|
||||
|
@ -39,15 +39,22 @@ public:
|
||||
bool bFirstRun;
|
||||
bool bAutoRun;
|
||||
bool bSpeedLimit;
|
||||
bool bJIT;
|
||||
bool bConfirmOnQuit;
|
||||
bool bIgnoreBadMemAccess;
|
||||
bool bDisplayFramebuffer;
|
||||
bool bBufferedRendering;
|
||||
|
||||
bool bShowTouchControls;
|
||||
bool bShowDebuggerOnLoad;
|
||||
bool bShowAnalogStick;
|
||||
bool bShowFPSCounter;
|
||||
bool bShowDebugStats;
|
||||
int iWindowZoom; // for Windows
|
||||
int iCpuCore;
|
||||
|
||||
std::string currentDirectory;
|
||||
std::string memCardDirectory;
|
||||
std::string flashDirectory;
|
||||
|
||||
void Load(const char *iniFileName = "ppsspp.ini");
|
||||
void Save();
|
||||
@ -55,6 +62,5 @@ private:
|
||||
std::string iniFilename_;
|
||||
};
|
||||
|
||||
|
||||
extern SState g_State;
|
||||
extern CConfig g_Config;
|
||||
|
@ -38,7 +38,8 @@ enum CoreState
|
||||
CORE_RUNNING,
|
||||
CORE_STEPPING,
|
||||
CORE_POWERDOWN,
|
||||
CORE_ERROR
|
||||
CORE_ERROR,
|
||||
CORE_NEXTFRAME,
|
||||
};
|
||||
|
||||
|
||||
|
@ -119,7 +119,14 @@
|
||||
<ClCompile Include="CPU.cpp" />
|
||||
<ClCompile Include="Debugger\Breakpoints.cpp" />
|
||||
<ClCompile Include="Debugger\SymbolMap.cpp" />
|
||||
<ClCompile Include="Dialog\PSPDialog.cpp" />
|
||||
<ClCompile Include="Dialog\PSPMsgDialog.cpp" />
|
||||
<ClCompile Include="Dialog\PSPOskDialog.cpp" />
|
||||
<ClCompile Include="Dialog\PSPPlaceholderDialog.cpp" />
|
||||
<ClCompile Include="Dialog\PSPSaveDialog.cpp" />
|
||||
<ClCompile Include="Dialog\SavedataParam.cpp" />
|
||||
<ClCompile Include="ELF\ElfReader.cpp" />
|
||||
<ClCompile Include="ELF\ParamSFO.cpp" />
|
||||
<ClCompile Include="ELF\PrxDecrypter.cpp" />
|
||||
<ClCompile Include="FileSystems\BlockDevices.cpp" />
|
||||
<ClCompile Include="FileSystems\DirectoryFileSystem.cpp" />
|
||||
@ -132,6 +139,7 @@
|
||||
<ClCompile Include="HLE\sceCtrl.cpp" />
|
||||
<ClCompile Include="HLE\sceDisplay.cpp" />
|
||||
<ClCompile Include="HLE\sceDmac.cpp" />
|
||||
<ClCompile Include="HLE\sceFont.cpp" />
|
||||
<ClCompile Include="HLE\sceGe.cpp" />
|
||||
<ClCompile Include="HLE\sceHprm.cpp" />
|
||||
<ClCompile Include="HLE\sceHttp.cpp" />
|
||||
@ -152,16 +160,23 @@
|
||||
<ClCompile Include="HLE\sceKernelVTimer.cpp" />
|
||||
<ClCompile Include="HLE\sceMpeg.cpp" />
|
||||
<ClCompile Include="HLE\sceNet.cpp" />
|
||||
<ClCompile Include="HLE\sceOpenPSID.cpp" />
|
||||
<ClCompile Include="HLE\sceParseHttp.cpp" />
|
||||
<ClCompile Include="HLE\sceParseUri.cpp" />
|
||||
<ClCompile Include="HLE\scePower.cpp" />
|
||||
<ClCompile Include="HLE\scePsmf.cpp" />
|
||||
<ClCompile Include="HLE\sceRtc.cpp" />
|
||||
<ClCompile Include="HLE\sceSas.cpp" />
|
||||
<ClCompile Include="HLE\sceSsl.cpp" />
|
||||
<ClCompile Include="HLE\scesupPreAcc.cpp" />
|
||||
<ClCompile Include="HLE\sceUmd.cpp" />
|
||||
<ClCompile Include="HLE\sceUtility.cpp" />
|
||||
<ClCompile Include="HLE\sceVaudio.cpp" />
|
||||
<ClCompile Include="HLE\__sceAudio.cpp" />
|
||||
<ClCompile Include="Host.cpp" />
|
||||
<ClCompile Include="HW\MediaEngine.cpp" />
|
||||
<ClCompile Include="HW\MemoryStick.cpp" />
|
||||
<ClCompile Include="HW\SasAudio.cpp" />
|
||||
<ClCompile Include="Loaders.cpp" />
|
||||
<ClCompile Include="MemMap.cpp" />
|
||||
<ClCompile Include="MemmapFunctions.cpp" />
|
||||
@ -237,6 +252,8 @@
|
||||
<ClCompile Include="PSPMixer.cpp" />
|
||||
<ClCompile Include="System.cpp" />
|
||||
<ClCompile Include="Util\BlockAllocator.cpp" />
|
||||
<ClCompile Include="Util\PPGeDraw.cpp" />
|
||||
<ClCompile Include="Util\ppge_atlas.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Config.h" />
|
||||
@ -247,8 +264,15 @@
|
||||
<ClInclude Include="Debugger\Breakpoints.h" />
|
||||
<ClInclude Include="Debugger\DebugInterface.h" />
|
||||
<ClInclude Include="Debugger\SymbolMap.h" />
|
||||
<ClInclude Include="Dialog\PSPDialog.h" />
|
||||
<ClInclude Include="Dialog\PSPMsgDialog.h" />
|
||||
<ClInclude Include="Dialog\PSPOskDialog.h" />
|
||||
<ClInclude Include="Dialog\PSPPlaceholderDialog.h" />
|
||||
<ClInclude Include="Dialog\PSPSaveDialog.h" />
|
||||
<ClInclude Include="Dialog\SavedataParam.h" />
|
||||
<ClInclude Include="ELF\ElfReader.h" />
|
||||
<ClInclude Include="ELF\ElfTypes.h" />
|
||||
<ClInclude Include="ELF\ParamSFO.h" />
|
||||
<ClInclude Include="ELF\PrxDecrypter.h" />
|
||||
<ClInclude Include="FileSystems\BlockDevices.h" />
|
||||
<ClInclude Include="FileSystems\DirectoryFileSystem.h" />
|
||||
@ -263,6 +287,7 @@
|
||||
<ClInclude Include="HLE\sceCtrl.h" />
|
||||
<ClInclude Include="HLE\sceDisplay.h" />
|
||||
<ClInclude Include="HLE\sceDmac.h" />
|
||||
<ClInclude Include="HLE\sceFont.h" />
|
||||
<ClInclude Include="HLE\sceGe.h" />
|
||||
<ClInclude Include="HLE\sceHprm.h" />
|
||||
<ClInclude Include="HLE\sceHttp.h" />
|
||||
@ -282,16 +307,23 @@
|
||||
<ClInclude Include="HLE\sceKernelTime.h" />
|
||||
<ClInclude Include="HLE\sceMpeg.h" />
|
||||
<ClInclude Include="HLE\sceNet.h" />
|
||||
<ClInclude Include="HLE\sceOpenPSID.h" />
|
||||
<ClInclude Include="HLE\sceParseHttp.h" />
|
||||
<ClInclude Include="HLE\sceParseUri.h" />
|
||||
<ClInclude Include="HLE\scePower.h" />
|
||||
<ClInclude Include="HLE\scePsmf.h" />
|
||||
<ClInclude Include="HLE\sceRtc.h" />
|
||||
<ClInclude Include="HLE\sceSas.h" />
|
||||
<ClInclude Include="HLE\sceSsl.h" />
|
||||
<ClInclude Include="HLE\scesupPreAcc.h" />
|
||||
<ClInclude Include="HLE\sceUmd.h" />
|
||||
<ClInclude Include="HLE\sceUtility.h" />
|
||||
<ClInclude Include="HLE\sceKernelVTimer.h" />
|
||||
<ClInclude Include="HLE\sceVaudio.h" />
|
||||
<ClInclude Include="HLE\__sceAudio.h" />
|
||||
<ClInclude Include="Host.h" />
|
||||
<ClInclude Include="HW\MediaEngine.h" />
|
||||
<ClInclude Include="HW\SasAudio.h" />
|
||||
<ClInclude Include="HW\MemoryStick.h" />
|
||||
<ClInclude Include="Loaders.h" />
|
||||
<ClInclude Include="MemMap.h" />
|
||||
@ -339,6 +371,8 @@
|
||||
<ClInclude Include="System.h" />
|
||||
<ClInclude Include="Util\BlockAllocator.h" />
|
||||
<ClInclude Include="Util\Pool.h" />
|
||||
<ClInclude Include="Util\PPGeDraw.h" />
|
||||
<ClInclude Include="Util\ppge_atlas.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\android\jni\Android.mk" />
|
||||
@ -354,7 +388,7 @@
|
||||
<Project>{457f45d2-556f-47bc-a31d-aff0d15beaed}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\native\native.vcxproj">
|
||||
<Project>{e8b58922-9827-493d-81e0-4b6e6bd77171}</Project>
|
||||
<Project>{C4DF647E-80EA-4111-A0A8-218B1B711E18}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ext\zlib\zlib.vcxproj">
|
||||
<Project>{f761046e-6c38-4428-a5f1-38391a37bb34}</Project>
|
||||
@ -363,4 +397,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -40,6 +40,9 @@
|
||||
<Filter Include="HW">
|
||||
<UniqueIdentifier>{9696662f-7398-489a-a358-5ebbf4ad4d97}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Dialog">
|
||||
<UniqueIdentifier>{41034c99-9b76-477f-8a77-bffaaffd5e82}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ELF\ElfReader.cpp">
|
||||
@ -291,7 +294,59 @@
|
||||
<ClCompile Include="HLE\sceImpose.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<<<<<<< HEAD
|
||||
<ClCompile Include="HW\MediaEngine.cpp">
|
||||
=======
|
||||
<ClCompile Include="Util\PPGeDraw.cpp">
|
||||
<Filter>Util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Util\ppge_atlas.cpp">
|
||||
<Filter>Util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceFont.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ELF\ParamSFO.cpp">
|
||||
<Filter>ELF</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceOpenPSID.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceParseUri.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceSsl.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceParseHttp.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\scesupPreAcc.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\sceVaudio.cpp">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Dialog\PSPDialog.cpp">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Dialog\PSPMsgDialog.cpp">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Dialog\PSPPlaceholderDialog.cpp">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Dialog\PSPSaveDialog.cpp">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Dialog\SavedataParam.cpp">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Dialog\PSPOskDialog.cpp">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\SasAudio.cpp">
|
||||
>>>>>>> master
|
||||
<Filter>HW</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@ -534,6 +589,55 @@
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\MediaEngine.h">
|
||||
<ClInclude Include="Util\PPGeDraw.h">
|
||||
<Filter>Util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Util\ppge_atlas.h">
|
||||
<Filter>Util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceFont.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ELF\ParamSFO.h">
|
||||
<Filter>ELF</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceOpenPSID.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceParseUri.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceSsl.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceParseHttp.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\scesupPreAcc.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\sceVaudio.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dialog\PSPDialog.h">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dialog\PSPMsgDialog.h">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dialog\PSPPlaceholderDialog.h">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dialog\PSPSaveDialog.h">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dialog\SavedataParam.h">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dialog\PSPOskDialog.h">
|
||||
<Filter>Dialog</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\SasAudio.h">
|
||||
<Filter>HW</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@ -543,4 +647,4 @@
|
||||
<None Include="..\android\jni\Android.mk" />
|
||||
<None Include="GameLogNotes.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
enum CPUCore {
|
||||
CPU_INTERPRETER,
|
||||
CPU_FASTINTERPRETER, // unsafe, a bit faster than INTERPRETER
|
||||
CPU_JIT,
|
||||
};
|
||||
|
||||
@ -31,7 +32,6 @@ enum GPUCore {
|
||||
GPU_SOFTWARE,
|
||||
};
|
||||
|
||||
|
||||
struct CoreParameter
|
||||
{
|
||||
// 0 = Interpreter
|
||||
@ -49,4 +49,16 @@ struct CoreParameter
|
||||
bool printfEmuLog; // writes "emulator:" logging to stdout
|
||||
bool headLess; // Try to avoid messageboxes etc
|
||||
bool useMediaEngine;
|
||||
|
||||
// Internal PSP resolution
|
||||
int renderWidth;
|
||||
int renderHeight;
|
||||
|
||||
// Virtual (dpi-adjusted) output resolution
|
||||
int outputWidth;
|
||||
int outputHeight;
|
||||
|
||||
// Actual pixel output resolution (for use by glViewport and the like)
|
||||
int pixelWidth;
|
||||
int pixelHeight;
|
||||
};
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "StdMutex.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "Core.h"
|
||||
#include "HLE/sceKernelThread.h"
|
||||
|
||||
int CPU_HZ = 222000000;
|
||||
|
||||
@ -248,6 +249,51 @@ void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata)
|
||||
AddEventToQueue(ne);
|
||||
}
|
||||
|
||||
// Returns cycles left in timer.
|
||||
u64 UnscheduleEvent(int event_type, u64 userdata)
|
||||
{
|
||||
u64 result = 0;
|
||||
if (!first)
|
||||
return result;
|
||||
while(first)
|
||||
{
|
||||
if (first->type == event_type && first->userdata == userdata)
|
||||
{
|
||||
result = first->time - globalTimer;
|
||||
|
||||
Event *next = first->next;
|
||||
FreeEvent(first);
|
||||
first = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!first)
|
||||
return result;
|
||||
Event *prev = first;
|
||||
Event *ptr = prev->next;
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr->type == event_type && ptr->userdata == userdata)
|
||||
{
|
||||
result = ptr->time - globalTimer;
|
||||
|
||||
prev->next = ptr->next;
|
||||
FreeEvent(ptr);
|
||||
ptr = prev->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
|
||||
{
|
||||
advanceCallback = callback;
|
||||
@ -363,6 +409,8 @@ void ProcessFifoWaitEvents()
|
||||
{
|
||||
if (first->time <= globalTimer)
|
||||
{
|
||||
// LOG(CPU, "[Scheduler] %s (%lld, %lld) ",
|
||||
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
|
||||
Event* evt = first;
|
||||
first = first->next;
|
||||
event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
|
||||
@ -400,28 +448,12 @@ void MoveEvents()
|
||||
|
||||
void Advance()
|
||||
{
|
||||
MoveEvents();
|
||||
|
||||
int cyclesExecuted = slicelength - downcount;
|
||||
globalTimer += cyclesExecuted;
|
||||
downcount = slicelength;
|
||||
|
||||
while (first)
|
||||
{
|
||||
if (first->time <= globalTimer)
|
||||
{
|
||||
// LOG(CPU, "[Scheduler] %s (%lld, %lld) ",
|
||||
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
|
||||
Event* evt = first;
|
||||
first = first->next;
|
||||
event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
|
||||
FreeEvent(evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
ProcessFifoWaitEvents();
|
||||
|
||||
if (!first)
|
||||
{
|
||||
// WARN_LOG(CPU, "WARNING - no events in queue. Setting downcount to 10000");
|
||||
@ -454,6 +486,20 @@ void Idle(int maxIdle)
|
||||
if (maxIdle != 0 && cyclesDown > maxIdle)
|
||||
cyclesDown = maxIdle;
|
||||
|
||||
if (first && cyclesDown > 0)
|
||||
{
|
||||
int cyclesExecuted = slicelength - downcount;
|
||||
int cyclesNextEvent = (int) (first->time - globalTimer);
|
||||
|
||||
if (cyclesNextEvent < cyclesExecuted + cyclesDown)
|
||||
{
|
||||
cyclesDown = cyclesNextEvent - cyclesExecuted;
|
||||
// Now, now... no time machines, please.
|
||||
if (cyclesDown < 0)
|
||||
cyclesDown = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(CPU, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(CPU_HZ * 0.001f));
|
||||
|
||||
idledCycles += cyclesDown;
|
||||
@ -474,7 +520,7 @@ std::string GetScheduledEventsSummary()
|
||||
if (!name)
|
||||
name = "[unknown]";
|
||||
char temp[512];
|
||||
sprintf(temp, "%s : %i %08x%08x\n", event_types[ptr->type].name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
|
||||
sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
|
||||
text += temp;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ inline int usToCycles(int us) {
|
||||
return (int)(CPU_HZ / 1000000 * us);
|
||||
}
|
||||
|
||||
inline u64 cyclesToUs(u64 cycles) {
|
||||
return cycles / (CPU_HZ / 1000000);
|
||||
}
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
void Init();
|
||||
@ -77,8 +81,8 @@ namespace CoreTiming
|
||||
void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata=0);
|
||||
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata=0);
|
||||
void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata=0);
|
||||
u64 UnscheduleEvent(int event_type, u64 userdata);
|
||||
|
||||
// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(int event_type);
|
||||
void RemoveThreadsafeEvent(int event_type);
|
||||
void RemoveAllEvents(int event_type);
|
||||
|
71
Core/Dialog/PSPDialog.cpp
Normal file
71
Core/Dialog/PSPDialog.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
// 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 "../Util/PPGeDraw.h"
|
||||
#include "PSPDialog.h"
|
||||
|
||||
PSPDialog::PSPDialog() : status(SCE_UTILITY_STATUS_SHUTDOWN)
|
||||
, lastButtons(0)
|
||||
, buttons(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PSPDialog::~PSPDialog() {
|
||||
}
|
||||
|
||||
PSPDialog::DialogStatus PSPDialog::GetStatus()
|
||||
{
|
||||
PSPDialog::DialogStatus retval = status;
|
||||
if (status == SCE_UTILITY_STATUS_SHUTDOWN)
|
||||
status = SCE_UTILITY_STATUS_NONE;
|
||||
if (status == SCE_UTILITY_STATUS_INITIALIZE)
|
||||
status = SCE_UTILITY_STATUS_RUNNING;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void PSPDialog::StartDraw()
|
||||
{
|
||||
PPGeBegin();
|
||||
PPGeDraw4Patch(I_BUTTON, 0, 0, 480, 272, 0xcFFFFFFF);
|
||||
}
|
||||
void PSPDialog::EndDraw()
|
||||
{
|
||||
PPGeEnd();
|
||||
}
|
||||
|
||||
void PSPDialog::DisplayMessage(std::string text)
|
||||
{
|
||||
PPGeDrawText(text.c_str(), 480/2, 100, PPGE_ALIGN_CENTER, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void PSPDialog::Shutdown()
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_SHUTDOWN;
|
||||
}
|
||||
|
||||
void PSPDialog::Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PSPDialog::IsButtonPressed(int checkButton)
|
||||
{
|
||||
return (!(lastButtons & checkButton)) && (buttons & checkButton);
|
||||
}
|
||||
|
||||
|
71
Core/Dialog/PSPDialog.h
Normal file
71
Core/Dialog/PSPDialog.h
Normal file
@ -0,0 +1,71 @@
|
||||
// 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 "../Config.h"
|
||||
|
||||
#define SCE_UTILITY_DIALOG_RESULT_SUCCESS 0
|
||||
#define SCE_UTILITY_DIALOG_RESULT_CANCEL 1
|
||||
#define SCE_UTILITY_DIALOG_RESULT_ABORT 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int size; /** Size of the structure */
|
||||
int language; /** Language */
|
||||
int buttonSwap; /** Set to 1 for X/O button swap */
|
||||
int graphicsThread; /** Graphics thread priority */
|
||||
int accessThread; /** Access/fileio thread priority (SceJobThread) */
|
||||
int fontThread; /** Font thread priority (ScePafThread) */
|
||||
int soundThread; /** Sound thread priority */
|
||||
int result; /** Result */
|
||||
int reserved[4]; /** Set to 0 */
|
||||
|
||||
} pspUtilityDialogCommon;
|
||||
|
||||
|
||||
class PSPDialog
|
||||
{
|
||||
public:
|
||||
PSPDialog();
|
||||
virtual ~PSPDialog();
|
||||
|
||||
virtual void Update();
|
||||
virtual void Shutdown();
|
||||
|
||||
enum DialogStatus
|
||||
{
|
||||
SCE_UTILITY_STATUS_NONE = 0,
|
||||
SCE_UTILITY_STATUS_INITIALIZE = 1,
|
||||
SCE_UTILITY_STATUS_RUNNING = 2,
|
||||
SCE_UTILITY_STATUS_FINISHED = 3,
|
||||
SCE_UTILITY_STATUS_SHUTDOWN = 4
|
||||
};
|
||||
|
||||
DialogStatus GetStatus();
|
||||
|
||||
void StartDraw();
|
||||
void EndDraw();
|
||||
protected:
|
||||
bool IsButtonPressed(int checkButton);
|
||||
void DisplayMessage(std::string text);
|
||||
DialogStatus status;
|
||||
|
||||
unsigned int lastButtons;
|
||||
unsigned int buttons;
|
||||
};
|
201
Core/Dialog/PSPMsgDialog.cpp
Normal file
201
Core/Dialog/PSPMsgDialog.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
// 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 "PSPMsgDialog.h"
|
||||
#include "../Util/PPGeDraw.h"
|
||||
#include "../HLE/sceCtrl.h"
|
||||
#include "../Core/MemMap.h"
|
||||
|
||||
PSPMsgDialog::PSPMsgDialog()
|
||||
: PSPDialog()
|
||||
, display(DS_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
PSPMsgDialog::~PSPMsgDialog() {
|
||||
}
|
||||
|
||||
void PSPMsgDialog::Init(unsigned int paramAddr)
|
||||
{
|
||||
messageDialogAddr = paramAddr;
|
||||
if (!Memory::IsValidAddress(messageDialogAddr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Memory::ReadStruct(messageDialogAddr, &messageDialog);
|
||||
|
||||
yesnoChoice = 1;
|
||||
if (messageDialog.type == 0) // number
|
||||
{
|
||||
INFO_LOG(HLE, "MsgDialog: %08x", messageDialog.errorNum);
|
||||
display = DS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(HLE, "MsgDialog: %s", messageDialog.string);
|
||||
display = DS_MESSAGE;
|
||||
if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_YESNO)
|
||||
display = DS_YESNO;
|
||||
if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO)
|
||||
yesnoChoice = 0;
|
||||
}
|
||||
|
||||
status = SCE_UTILITY_STATUS_INITIALIZE;
|
||||
|
||||
lastButtons = __CtrlPeekButtons();
|
||||
|
||||
}
|
||||
|
||||
void PSPMsgDialog::DisplayBack()
|
||||
{
|
||||
PPGeDrawImage(cancelButtonImg, 250, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Back", 270, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void PSPMsgDialog::DisplayYesNo()
|
||||
{
|
||||
|
||||
PPGeDrawText("Yes", 200, 150, PPGE_ALIGN_LEFT, 0.5f, (yesnoChoice == 1?0xFF0000FF:0xFFFFFFFF));
|
||||
PPGeDrawText("No", 320, 150, PPGE_ALIGN_LEFT, 0.5f, (yesnoChoice == 0?0xFF0000FF:0xFFFFFFFF));
|
||||
|
||||
if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0)
|
||||
{
|
||||
yesnoChoice = 1;
|
||||
}
|
||||
else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1)
|
||||
{
|
||||
yesnoChoice = 0;
|
||||
}
|
||||
}
|
||||
void PSPMsgDialog::DisplayEnterBack()
|
||||
{
|
||||
PPGeDrawImage(okButtonImg, 200, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Enter", 230, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
PPGeDrawImage(cancelButtonImg, 290, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Back", 320, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void PSPMsgDialog::Update()
|
||||
{
|
||||
switch (status) {
|
||||
case SCE_UTILITY_STATUS_FINISHED:
|
||||
status = SCE_UTILITY_STATUS_SHUTDOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != SCE_UTILITY_STATUS_RUNNING)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char *text;
|
||||
if (messageDialog.type == 0) {
|
||||
char temp[256];
|
||||
sprintf(temp, "Error code: %08x", messageDialog.errorNum);
|
||||
text = temp;
|
||||
} else {
|
||||
text = messageDialog.string;
|
||||
}
|
||||
|
||||
buttons = __CtrlPeekButtons();
|
||||
|
||||
okButtonImg = I_CIRCLE;
|
||||
cancelButtonImg = I_CROSS;
|
||||
okButtonFlag = CTRL_CIRCLE;
|
||||
cancelButtonFlag = CTRL_CROSS;
|
||||
if(messageDialog.common.buttonSwap == 1)
|
||||
{
|
||||
okButtonImg = I_CROSS;
|
||||
cancelButtonImg = I_CIRCLE;
|
||||
okButtonFlag = CTRL_CROSS;
|
||||
cancelButtonFlag = CTRL_CIRCLE;
|
||||
}
|
||||
|
||||
switch(display)
|
||||
{
|
||||
case DS_MESSAGE:
|
||||
StartDraw();
|
||||
|
||||
DisplayMessage(text);
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 0;
|
||||
}
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_ERROR:
|
||||
StartDraw();
|
||||
|
||||
DisplayMessage(text);
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 0;
|
||||
}
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_YESNO:
|
||||
StartDraw();
|
||||
|
||||
DisplayMessage(text);
|
||||
DisplayYesNo();
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 3;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
if(yesnoChoice == 0)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
messageDialog.buttonPressed = 1;
|
||||
}
|
||||
}
|
||||
EndDraw();
|
||||
break;
|
||||
default:
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
lastButtons = buttons;
|
||||
|
||||
Memory::WriteStruct(messageDialogAddr, &messageDialog);
|
||||
}
|
||||
|
||||
void PSPMsgDialog::Shutdown()
|
||||
{
|
||||
PSPDialog::Shutdown();
|
||||
}
|
||||
|
74
Core/Dialog/PSPMsgDialog.h
Normal file
74
Core/Dialog/PSPMsgDialog.h
Normal file
@ -0,0 +1,74 @@
|
||||
// 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 "PSPDialog.h"
|
||||
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_ERROR 0 // Do nothing
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_TEXT 0x00000001
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_YESNO 0x00000010
|
||||
#define SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO 0x00000100
|
||||
|
||||
struct pspMessageDialog
|
||||
{
|
||||
pspUtilityDialogCommon common;
|
||||
int result;
|
||||
int type;
|
||||
unsigned int errorNum;
|
||||
char string[512];
|
||||
unsigned int options;
|
||||
unsigned int buttonPressed; // 0=?, 1=Yes, 2=No, 3=Back
|
||||
};
|
||||
|
||||
|
||||
class PSPMsgDialog: public PSPDialog {
|
||||
public:
|
||||
PSPMsgDialog();
|
||||
virtual ~PSPMsgDialog();
|
||||
|
||||
virtual void Init(unsigned int paramAddr);
|
||||
virtual void Update();
|
||||
void Shutdown();
|
||||
|
||||
private :
|
||||
void DisplayBack();
|
||||
void DisplayYesNo();
|
||||
void DisplayEnterBack();
|
||||
|
||||
enum DisplayState
|
||||
{
|
||||
DS_NONE,
|
||||
|
||||
DS_MESSAGE,
|
||||
DS_ERROR,
|
||||
DS_YESNO,
|
||||
};
|
||||
|
||||
DisplayState display;
|
||||
|
||||
pspMessageDialog messageDialog;
|
||||
int messageDialogAddr;
|
||||
|
||||
int yesnoChoice;
|
||||
|
||||
int okButtonImg;
|
||||
int cancelButtonImg;
|
||||
int okButtonFlag;
|
||||
int cancelButtonFlag;
|
||||
};
|
||||
|
238
Core/Dialog/PSPOskDialog.cpp
Normal file
238
Core/Dialog/PSPOskDialog.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
// 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 "PSPOskDialog.h"
|
||||
#include "../Util/PPGeDraw.h"
|
||||
#include "../HLE/sceCtrl.h"
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration for input language
|
||||
*/
|
||||
enum SceUtilityOskInputLanguage
|
||||
{
|
||||
PSP_UTILITY_OSK_LANGUAGE_DEFAULT = 0x00,
|
||||
PSP_UTILITY_OSK_LANGUAGE_JAPANESE = 0x01,
|
||||
PSP_UTILITY_OSK_LANGUAGE_ENGLISH = 0x02,
|
||||
PSP_UTILITY_OSK_LANGUAGE_FRENCH = 0x03,
|
||||
PSP_UTILITY_OSK_LANGUAGE_SPANISH = 0x04,
|
||||
PSP_UTILITY_OSK_LANGUAGE_GERMAN = 0x05,
|
||||
PSP_UTILITY_OSK_LANGUAGE_ITALIAN = 0x06,
|
||||
PSP_UTILITY_OSK_LANGUAGE_DUTCH = 0x07,
|
||||
PSP_UTILITY_OSK_LANGUAGE_PORTUGESE = 0x08,
|
||||
PSP_UTILITY_OSK_LANGUAGE_RUSSIAN = 0x09,
|
||||
PSP_UTILITY_OSK_LANGUAGE_KOREAN = 0x0a
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumeration for OSK internal state
|
||||
*/
|
||||
enum SceUtilityOskState
|
||||
{
|
||||
PSP_UTILITY_OSK_DIALOG_NONE = 0, /**< No OSK is currently active */
|
||||
PSP_UTILITY_OSK_DIALOG_INITING, /**< The OSK is currently being initialized */
|
||||
PSP_UTILITY_OSK_DIALOG_INITED, /**< The OSK is initialised */
|
||||
PSP_UTILITY_OSK_DIALOG_VISIBLE, /**< The OSK is visible and ready for use */
|
||||
PSP_UTILITY_OSK_DIALOG_QUIT, /**< The OSK has been cancelled and should be shut down */
|
||||
PSP_UTILITY_OSK_DIALOG_FINISHED /**< The OSK has successfully shut down */
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumeration for OSK field results
|
||||
*/
|
||||
enum SceUtilityOskResult
|
||||
{
|
||||
PSP_UTILITY_OSK_RESULT_UNCHANGED = 0,
|
||||
PSP_UTILITY_OSK_RESULT_CANCELLED,
|
||||
PSP_UTILITY_OSK_RESULT_CHANGED
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumeration for input types (these are limited by initial choice of language)
|
||||
*/
|
||||
enum SceUtilityOskInputType
|
||||
{
|
||||
PSP_UTILITY_OSK_INPUTTYPE_ALL = 0x00000000,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT = 0x00000001,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_LATIN_SYMBOL = 0x00000002,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_LATIN_LOWERCASE = 0x00000004,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_LATIN_UPPERCASE = 0x00000008,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_DIGIT = 0x00000100,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_SYMBOL = 0x00000200,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_LOWERCASE = 0x00000400,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_UPPERCASE = 0x00000800,
|
||||
// http://en.wikipedia.org/wiki/Hiragana
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HIRAGANA = 0x00001000,
|
||||
// http://en.wikipedia.org/wiki/Katakana
|
||||
// Half-width Katakana
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_HALF_KATAKANA = 0x00002000,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KATAKANA = 0x00004000,
|
||||
// http://en.wikipedia.org/wiki/Kanji
|
||||
PSP_UTILITY_OSK_INPUTTYPE_JAPANESE_KANJI = 0x00008000,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_LOWERCASE = 0x00010000,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_RUSSIAN_UPPERCASE = 0x00020000,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_KOREAN = 0x00040000,
|
||||
PSP_UTILITY_OSK_INPUTTYPE_URL = 0x00080000
|
||||
};
|
||||
|
||||
/**
|
||||
* OSK Field data
|
||||
*/
|
||||
typedef struct _SceUtilityOskData
|
||||
{
|
||||
/** Unknown. Pass 0. */
|
||||
int unk_00;
|
||||
/** Unknown. Pass 0. */
|
||||
int unk_04;
|
||||
/** One of ::SceUtilityOskInputLanguage */
|
||||
int language;
|
||||
/** Unknown. Pass 0. */
|
||||
int unk_12;
|
||||
/** One or more of ::SceUtilityOskInputType (types that are selectable by pressing SELECT) */
|
||||
int inputtype;
|
||||
/** Number of lines */
|
||||
int lines;
|
||||
/** Unknown. Pass 0. */
|
||||
int unk_24;
|
||||
/** Description text */
|
||||
u32 descPtr;
|
||||
/** Initial text */
|
||||
u32 intextPtr;
|
||||
/** Length of output text */
|
||||
int outtextlength;
|
||||
/** Pointer to the output text */
|
||||
u32 outtextPtr;
|
||||
/** Result. One of ::SceUtilityOskResult */
|
||||
int result;
|
||||
/** The max text that can be input */
|
||||
int outtextlimit;
|
||||
|
||||
} SceUtilityOskData;
|
||||
|
||||
/**
|
||||
* OSK parameters
|
||||
*/
|
||||
typedef struct _SceUtilityOskParams
|
||||
{
|
||||
pspUtilityDialogCommon base;
|
||||
int datacount; /** Number of input fields */
|
||||
u32 SceUtilityOskDataPtr; /** Pointer to the start of the data for the input fields */
|
||||
int state; /** The local OSK state, one of ::SceUtilityOskState */
|
||||
int unk_60;/** Unknown. Pass 0 */
|
||||
|
||||
} SceUtilityOskParams;
|
||||
|
||||
SceUtilityOskParams oskParams;
|
||||
SceUtilityOskData oskData;
|
||||
std::string oskDesc;
|
||||
std::string oskIntext;
|
||||
std::string oskOuttext;
|
||||
|
||||
int oskParamsAddr;
|
||||
|
||||
|
||||
PSPOskDialog::PSPOskDialog() : PSPDialog() {
|
||||
|
||||
}
|
||||
|
||||
PSPOskDialog::~PSPOskDialog() {
|
||||
}
|
||||
|
||||
|
||||
// Same as get string but read out 16bit
|
||||
void PSPOskDialog::HackyGetStringWide(std::string& _string, const u32 em_address)
|
||||
{
|
||||
char stringBuffer[2048];
|
||||
char *string = stringBuffer;
|
||||
char c;
|
||||
u32 addr = em_address;
|
||||
while ((c = (Memory::Read_U16(addr))))
|
||||
{
|
||||
*string++ = c;
|
||||
addr+=2;
|
||||
}
|
||||
*string++ = '\0';
|
||||
_string = stringBuffer;
|
||||
}
|
||||
|
||||
|
||||
int PSPOskDialog::Init(u32 oskPtr)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_INITIALIZE;
|
||||
|
||||
memset(&oskParams, 0, sizeof(oskParams));
|
||||
memset(&oskData, 0, sizeof(oskData));
|
||||
oskParamsAddr = oskPtr;
|
||||
if (Memory::IsValidAddress(oskPtr))
|
||||
{
|
||||
Memory::ReadStruct(oskPtr, &oskParams);
|
||||
Memory::ReadStruct(oskParams.SceUtilityOskDataPtr, &oskData);
|
||||
HackyGetStringWide(oskDesc, oskData.descPtr);
|
||||
HackyGetStringWide(oskIntext, oskData.intextPtr);
|
||||
HackyGetStringWide(oskOuttext, oskData.outtextPtr);
|
||||
Memory::WriteStruct(oskParams.SceUtilityOskDataPtr, &oskData);
|
||||
Memory::WriteStruct(oskPtr, &oskParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PSPOskDialog::Update()
|
||||
{
|
||||
buttons = __CtrlPeekButtons();
|
||||
//__UtilityUpdate();
|
||||
if (status == SCE_UTILITY_STATUS_INITIALIZE)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_RUNNING;
|
||||
}
|
||||
else if (status == SCE_UTILITY_STATUS_RUNNING)
|
||||
{
|
||||
StartDraw();
|
||||
|
||||
DisplayMessage(oskDesc);
|
||||
PPGeDrawImage(I_CROSS, 200, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Ignore", 230, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
if (IsButtonPressed(CTRL_CROSS))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
}
|
||||
EndDraw();
|
||||
}
|
||||
else if (status == SCE_UTILITY_STATUS_FINISHED)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_SHUTDOWN;
|
||||
}
|
||||
// just fake the return values to be "000000" as this will work for most cases e.g. when restricted to entering just numbers
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr);
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr+2);
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr+4);
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr+6);
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr+8);
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr+10);
|
||||
Memory::Write_U16(0x0030,oskData.outtextPtr+12);
|
||||
oskData.outtextlength = 6;
|
||||
oskParams.base.result= 0;
|
||||
oskData.result = PSP_UTILITY_OSK_RESULT_CHANGED;
|
||||
Memory::WriteStruct(oskParams.SceUtilityOskDataPtr, &oskData);
|
||||
Memory::WriteStruct(oskParamsAddr, &oskParams);
|
||||
}
|
32
Core/Dialog/PSPOskDialog.h
Normal file
32
Core/Dialog/PSPOskDialog.h
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 "PSPDialog.h"
|
||||
#include "../Core/MemMap.h"
|
||||
class PSPOskDialog: public PSPDialog {
|
||||
public:
|
||||
PSPOskDialog();
|
||||
virtual ~PSPOskDialog();
|
||||
|
||||
virtual int Init(u32 oskPtr);
|
||||
virtual void Update();
|
||||
private:
|
||||
void HackyGetStringWide(std::string& _string, const u32 em_address);
|
||||
};
|
||||
|
48
Core/Dialog/PSPPlaceholderDialog.cpp
Normal file
48
Core/Dialog/PSPPlaceholderDialog.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
// 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 "PSPPlaceholderDialog.h"
|
||||
|
||||
PSPPlaceholderDialog::PSPPlaceholderDialog() : PSPDialog() {
|
||||
|
||||
}
|
||||
|
||||
PSPPlaceholderDialog::~PSPPlaceholderDialog() {
|
||||
}
|
||||
|
||||
|
||||
void PSPPlaceholderDialog::Init()
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_INITIALIZE;
|
||||
}
|
||||
|
||||
void PSPPlaceholderDialog::Update()
|
||||
{
|
||||
//__UtilityUpdate();
|
||||
if (status == SCE_UTILITY_STATUS_INITIALIZE)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_RUNNING;
|
||||
}
|
||||
else if (status == SCE_UTILITY_STATUS_RUNNING)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
}
|
||||
else if (status == SCE_UTILITY_STATUS_FINISHED)
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_SHUTDOWN;
|
||||
}
|
||||
}
|
30
Core/Dialog/PSPPlaceholderDialog.h
Normal file
30
Core/Dialog/PSPPlaceholderDialog.h
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 "PSPDialog.h"
|
||||
|
||||
class PSPPlaceholderDialog: public PSPDialog {
|
||||
public:
|
||||
PSPPlaceholderDialog();
|
||||
virtual ~PSPPlaceholderDialog();
|
||||
|
||||
virtual void Init();
|
||||
virtual void Update();
|
||||
};
|
||||
|
676
Core/Dialog/PSPSaveDialog.cpp
Normal file
676
Core/Dialog/PSPSaveDialog.cpp
Normal file
@ -0,0 +1,676 @@
|
||||
// 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 "PSPSaveDialog.h"
|
||||
#include "../Util/PPGeDraw.h"
|
||||
#include "../HLE/sceCtrl.h"
|
||||
#include "../Core/MemMap.h"
|
||||
|
||||
PSPSaveDialog::PSPSaveDialog()
|
||||
: PSPDialog()
|
||||
, currentSelectedSave(0)
|
||||
, display(DS_NONE)
|
||||
{
|
||||
param.SetPspParam(0);
|
||||
}
|
||||
|
||||
PSPSaveDialog::~PSPSaveDialog() {
|
||||
}
|
||||
|
||||
void PSPSaveDialog::Init(int paramAddr)
|
||||
{
|
||||
param.SetPspParam((SceUtilitySavedataParam*)Memory::GetPointer(paramAddr));
|
||||
|
||||
DEBUG_LOG(HLE,"sceUtilitySavedataInitStart(%08x)", paramAddr);
|
||||
DEBUG_LOG(HLE,"Mode: %i", param.GetPspParam()->mode);
|
||||
|
||||
switch(param.GetPspParam()->mode)
|
||||
{
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LOAD:
|
||||
DEBUG_LOG(HLE, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
|
||||
display = DS_NONE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD:
|
||||
DEBUG_LOG(HLE, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
|
||||
if(param.GetFilenameCount() == 0)
|
||||
display = DS_LOAD_NODATA;
|
||||
else
|
||||
display = DS_LOAD_LIST_CHOICE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SAVE:
|
||||
DEBUG_LOG(HLE, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
|
||||
display = DS_NONE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LISTSAVE:
|
||||
DEBUG_LOG(HLE, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
|
||||
display = DS_SAVE_LIST_CHOICE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE:
|
||||
DEBUG_LOG(HLE, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
|
||||
if(param.GetFilenameCount() == 0)
|
||||
display = DS_DELETE_NODATA;
|
||||
else
|
||||
display = DS_DELETE_LIST_CHOICE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SIZES:
|
||||
display = DS_NONE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
|
||||
display = DS_NONE;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_DELETE: // This run on PSP display a list of all save on the PSP. Weird. (Not really, it's to let you free up space)
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(HLE, "Load/Save function %d not coded. Title: %s Save: %s File: %s", param.GetPspParam()->mode, param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
|
||||
param.GetPspParam()->result = 0;
|
||||
display = DS_NONE;
|
||||
return; // Return 0 should allow the game to continue, but missing function must be implemented and returning the right value or the game can block.
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
status = SCE_UTILITY_STATUS_INITIALIZE;
|
||||
|
||||
currentSelectedSave = 0;
|
||||
lastButtons = __CtrlPeekButtons();
|
||||
|
||||
/*INFO_LOG(HLE,"Dump Param :");
|
||||
INFO_LOG(HLE,"size : %d",param.GetPspParam()->size);
|
||||
INFO_LOG(HLE,"language : %d",param.GetPspParam()->language);
|
||||
INFO_LOG(HLE,"buttonSwap : %d",param.GetPspParam()->buttonSwap);
|
||||
INFO_LOG(HLE,"result : %d",param.GetPspParam()->result);
|
||||
INFO_LOG(HLE,"mode : %d",param.GetPspParam()->mode);
|
||||
INFO_LOG(HLE,"bind : %d",param.GetPspParam()->bind);
|
||||
INFO_LOG(HLE,"overwriteMode : %d",param.GetPspParam()->overwriteMode);
|
||||
INFO_LOG(HLE,"gameName : %s",param.GetGameName(param.GetPspParam()).c_str());
|
||||
INFO_LOG(HLE,"saveName : %s",param.GetPspParam()->saveName);
|
||||
INFO_LOG(HLE,"saveNameList : %08x",*((unsigned int*)¶m.GetPspParam()->saveNameList));
|
||||
INFO_LOG(HLE,"fileName : %s",param.GetPspParam()->fileName);
|
||||
INFO_LOG(HLE,"dataBuf : %08x",*((unsigned int*)¶m.GetPspParam()->dataBuf));
|
||||
INFO_LOG(HLE,"dataBufSize : %u",param.GetPspParam()->dataBufSize);
|
||||
INFO_LOG(HLE,"dataSize : %u",param.GetPspParam()->dataSize);
|
||||
|
||||
INFO_LOG(HLE,"sfo title : %s",param.GetPspParam()->sfoParam.title);
|
||||
INFO_LOG(HLE,"sfo savedataTitle : %s",param.GetPspParam()->sfoParam.savedataTitle);
|
||||
INFO_LOG(HLE,"sfo detail : %s",param.GetPspParam()->sfoParam.detail);
|
||||
|
||||
INFO_LOG(HLE,"icon0 data : %08x",*((unsigned int*)¶m.GetPspParam()->icon0FileData.buf));
|
||||
INFO_LOG(HLE,"icon0 size : %u",param.GetPspParam()->icon0FileData.bufSize);
|
||||
|
||||
INFO_LOG(HLE,"icon1 data : %08x",*((unsigned int*)¶m.GetPspParam()->icon1FileData.buf));
|
||||
INFO_LOG(HLE,"icon1 size : %u",param.GetPspParam()->icon1FileData.bufSize);
|
||||
|
||||
INFO_LOG(HLE,"pic1 data : %08x",*((unsigned int*)¶m.GetPspParam()->pic1FileData.buf));
|
||||
INFO_LOG(HLE,"pic1 size : %u",param.GetPspParam()->pic1FileData.bufSize);
|
||||
|
||||
INFO_LOG(HLE,"snd0 data : %08x",*((unsigned int*)¶m.GetPspParam()->snd0FileData.buf));
|
||||
INFO_LOG(HLE,"snd0 size : %u",param.GetPspParam()->snd0FileData.bufSize);*/
|
||||
|
||||
}
|
||||
|
||||
void PSPSaveDialog::DisplaySaveList(bool canMove)
|
||||
{
|
||||
int displayCount = 0;
|
||||
for(int i = 0; i < param.GetFilenameCount(); i++)
|
||||
{
|
||||
int textureColor = 0xFFFFFFFF;
|
||||
|
||||
if(param.GetFileInfo(i).size == 0)
|
||||
{
|
||||
textureColor = 0xFF777777;
|
||||
}
|
||||
|
||||
// Calc save image position on screen
|
||||
int w = 150;
|
||||
int h = 80;
|
||||
int x = 20;
|
||||
if(displayCount != currentSelectedSave)
|
||||
{
|
||||
w = 80;
|
||||
h = 40;
|
||||
x = 50;
|
||||
}
|
||||
int y = 80;
|
||||
if(displayCount < currentSelectedSave)
|
||||
y -= 50 * (currentSelectedSave - displayCount);
|
||||
else if(displayCount > currentSelectedSave)
|
||||
{
|
||||
y += 90 + 50 * (displayCount - currentSelectedSave - 1);
|
||||
}
|
||||
|
||||
int tw = 256;
|
||||
int th = 256;
|
||||
if(param.GetFileInfo(i).textureData != 0)
|
||||
{
|
||||
tw = param.GetFileInfo(i).textureWidth;
|
||||
th = param.GetFileInfo(i).textureHeight;
|
||||
PPGeSetTexture(param.GetFileInfo(i).textureData, param.GetFileInfo(i).textureWidth, param.GetFileInfo(i).textureHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
PPGeDisableTexture();
|
||||
}
|
||||
PPGeDrawImage(x, y, w, h, 0, 0 ,1 ,1 ,tw, th, textureColor);
|
||||
PPGeSetDefaultTexture();
|
||||
displayCount++;
|
||||
}
|
||||
|
||||
if(canMove)
|
||||
{
|
||||
if (IsButtonPressed(CTRL_UP) && currentSelectedSave > 0)
|
||||
{
|
||||
currentSelectedSave--;
|
||||
}
|
||||
else if (IsButtonPressed(CTRL_DOWN) && currentSelectedSave < (param.GetFilenameCount()-1))
|
||||
{
|
||||
currentSelectedSave++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PSPSaveDialog::DisplaySaveIcon()
|
||||
{
|
||||
int textureColor = 0xFFFFFFFF;
|
||||
|
||||
if(param.GetFileInfo(currentSelectedSave).size == 0)
|
||||
{
|
||||
textureColor = 0xFF777777;
|
||||
}
|
||||
|
||||
// Calc save image position on screen
|
||||
int w = 150;
|
||||
int h = 80;
|
||||
int x = 20;
|
||||
int y = 80;
|
||||
|
||||
int tw = 256;
|
||||
int th = 256;
|
||||
if(param.GetFileInfo(currentSelectedSave).textureData != 0)
|
||||
{
|
||||
tw = param.GetFileInfo(currentSelectedSave).textureWidth;
|
||||
th = param.GetFileInfo(currentSelectedSave).textureHeight;
|
||||
PPGeSetTexture(param.GetFileInfo(currentSelectedSave).textureData, param.GetFileInfo(currentSelectedSave).textureWidth, param.GetFileInfo(currentSelectedSave).textureHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
PPGeDisableTexture();
|
||||
}
|
||||
PPGeDrawImage(x, y, w, h, 0, 0 ,1 ,1 ,tw, th, textureColor);
|
||||
if(param.GetFileInfo(currentSelectedSave).textureData != 0)
|
||||
{
|
||||
PPGeSetDefaultTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void PSPSaveDialog::DisplaySaveDataInfo1()
|
||||
{
|
||||
if(param.GetFileInfo(currentSelectedSave).size == 0)
|
||||
{
|
||||
PPGeDrawText("New Save", 200, 110, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
char txt[1024];
|
||||
sprintf(txt,"%s\n%02d/%02d/%d %02d:%02d %d KB\n%s\n%s"
|
||||
, param.GetFileInfo(currentSelectedSave).title
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mday
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_year + 1900
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_hour
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_min
|
||||
, param.GetFileInfo(currentSelectedSave).size / 1024
|
||||
, param.GetFileInfo(currentSelectedSave).saveTitle
|
||||
, param.GetFileInfo(currentSelectedSave).saveDetail
|
||||
);
|
||||
std::string saveinfoTxt = txt;
|
||||
PPGeDrawText(saveinfoTxt.c_str(), 200, 100, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
void PSPSaveDialog::DisplaySaveDataInfo2()
|
||||
{
|
||||
if(param.GetFileInfo(currentSelectedSave).size == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
char txt[1024];
|
||||
sprintf(txt,"%s\n%02d/%02d/%d %02d:%02d\n%d KB"
|
||||
, param.GetFileInfo(currentSelectedSave).saveTitle
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mday
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_year + 1900
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_hour
|
||||
, param.GetFileInfo(currentSelectedSave).modif_time.tm_min
|
||||
, param.GetFileInfo(currentSelectedSave).size / 1024
|
||||
);
|
||||
std::string saveinfoTxt = txt;
|
||||
PPGeDrawText(saveinfoTxt.c_str(), 10, 180, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
void PSPSaveDialog::DisplayConfirmationYesNo(std::string text)
|
||||
{
|
||||
PPGeDrawText(text.c_str(), 200, 90, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
|
||||
PPGeDrawText("Yes", 250, 150, PPGE_ALIGN_LEFT, 0.5f, (yesnoChoice == 1?0xFF0000FF:0xFFFFFFFF));
|
||||
PPGeDrawText("No", 350, 150, PPGE_ALIGN_LEFT, 0.5f, (yesnoChoice == 0?0xFF0000FF:0xFFFFFFFF));
|
||||
|
||||
if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0)
|
||||
{
|
||||
yesnoChoice = 1;
|
||||
}
|
||||
else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1)
|
||||
{
|
||||
yesnoChoice = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PSPSaveDialog::DisplayInfo(std::string text)
|
||||
{
|
||||
PPGeDrawText(text.c_str(), 200, 90, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
void PSPSaveDialog::DisplayTitle(std::string name)
|
||||
{
|
||||
PPGeDrawText(name.c_str(), 10, 10, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
void PSPSaveDialog::DisplayEnterBack()
|
||||
{
|
||||
PPGeDrawImage(okButtonImg, 200, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Enter", 230, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
PPGeDrawImage(cancelButtonImg, 290, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Back", 320, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
void PSPSaveDialog::DisplayBack()
|
||||
{
|
||||
PPGeDrawImage(cancelButtonImg, 250, 220, 20, 20, 0, 0xFFFFFFFF);
|
||||
PPGeDrawText("Back", 270, 220, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void PSPSaveDialog::Update()
|
||||
{
|
||||
switch (status) {
|
||||
case SCE_UTILITY_STATUS_FINISHED:
|
||||
status = SCE_UTILITY_STATUS_SHUTDOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != SCE_UTILITY_STATUS_RUNNING)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!param.GetPspParam()) {
|
||||
status = SCE_UTILITY_STATUS_SHUTDOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
buttons = __CtrlPeekButtons();
|
||||
|
||||
okButtonImg = I_CIRCLE;
|
||||
cancelButtonImg = I_CROSS;
|
||||
okButtonFlag = CTRL_CIRCLE;
|
||||
cancelButtonFlag = CTRL_CROSS;
|
||||
if(param.GetPspParam()->buttonSwap == 1)
|
||||
{
|
||||
okButtonImg = I_CROSS;
|
||||
cancelButtonImg = I_CIRCLE;
|
||||
okButtonFlag = CTRL_CROSS;
|
||||
cancelButtonFlag = CTRL_CIRCLE;
|
||||
}
|
||||
|
||||
switch(display)
|
||||
{
|
||||
case DS_SAVE_LIST_CHOICE:
|
||||
StartDraw();
|
||||
DisplayTitle("Save");
|
||||
|
||||
// TODO : use focus for selected save by default, and don't modify global selected save,use local var
|
||||
DisplaySaveList();
|
||||
DisplaySaveDataInfo1();
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
// Save exist, ask user confirm
|
||||
if(param.GetFileInfo(currentSelectedSave).size > 0)
|
||||
{
|
||||
yesnoChoice = 0;
|
||||
display = DS_SAVE_CONFIRM_OVERWRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = DS_SAVE_SAVING;
|
||||
if(param.Save(param.GetPspParam(),currentSelectedSave))
|
||||
{
|
||||
param.SetPspParam(param.GetPspParam()); // Optim : Just Update modified save
|
||||
display = DS_SAVE_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = DS_SAVE_LIST_CHOICE; // This will probably need error message ?
|
||||
}
|
||||
}
|
||||
}
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_SAVE_CONFIRM_OVERWRITE:
|
||||
StartDraw();
|
||||
DisplayTitle("Save");
|
||||
|
||||
DisplaySaveIcon();
|
||||
DisplaySaveDataInfo2();
|
||||
|
||||
DisplayConfirmationYesNo("Do you want to overwrite the data ?");
|
||||
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
display = DS_SAVE_LIST_CHOICE;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
if(yesnoChoice == 0)
|
||||
{
|
||||
display = DS_SAVE_LIST_CHOICE;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = DS_SAVE_SAVING;
|
||||
if(param.Save(param.GetPspParam(),currentSelectedSave))
|
||||
{
|
||||
param.SetPspParam(param.GetPspParam()); // Optim : Just Update modified save
|
||||
display = DS_SAVE_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = DS_SAVE_LIST_CHOICE; // This will probably need error message ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_SAVE_SAVING:
|
||||
StartDraw();
|
||||
DisplayTitle("Save");
|
||||
|
||||
DisplaySaveIcon();
|
||||
DisplaySaveDataInfo2();
|
||||
|
||||
DisplayInfo("Saving\nPlease Wait...");
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_SAVE_DONE:
|
||||
StartDraw();
|
||||
DisplayTitle("Save");
|
||||
|
||||
DisplaySaveIcon();
|
||||
DisplaySaveDataInfo2();
|
||||
DisplayBack();
|
||||
|
||||
DisplayInfo("Save completed");
|
||||
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_DIALOG_RESULT_SUCCESS;
|
||||
// Set the save to use for autosave and autoload
|
||||
param.SetSelectedSave(param.GetFileInfo(currentSelectedSave).idx);
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
|
||||
case DS_LOAD_LIST_CHOICE:
|
||||
StartDraw();
|
||||
DisplayTitle("Load");
|
||||
DisplaySaveList();
|
||||
DisplaySaveDataInfo1();
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
display = DS_LOAD_LOADING;
|
||||
if(param.Load(param.GetPspParam(),currentSelectedSave))
|
||||
{
|
||||
display = DS_LOAD_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_LOAD_LOADING:
|
||||
StartDraw();
|
||||
DisplayTitle("Load");
|
||||
|
||||
DisplaySaveIcon();
|
||||
DisplaySaveDataInfo2();
|
||||
|
||||
DisplayInfo("Loading\nPlease Wait...");
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_LOAD_DONE:
|
||||
StartDraw();
|
||||
DisplayTitle("Load");
|
||||
|
||||
DisplaySaveIcon();
|
||||
DisplaySaveDataInfo2();
|
||||
DisplayBack();
|
||||
|
||||
DisplayInfo("Load completed");
|
||||
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_DIALOG_RESULT_SUCCESS;
|
||||
// Set the save to use for autosave and autoload
|
||||
param.SetSelectedSave(param.GetFileInfo(currentSelectedSave).idx);
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_LOAD_NODATA:
|
||||
StartDraw();
|
||||
DisplayTitle("Load");
|
||||
|
||||
DisplayBack();
|
||||
|
||||
DisplayInfo("There is no data");
|
||||
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA;
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
|
||||
case DS_DELETE_LIST_CHOICE:
|
||||
StartDraw();
|
||||
DisplayTitle("Delete");
|
||||
DisplaySaveList();
|
||||
DisplaySaveDataInfo1();
|
||||
|
||||
// TODO : Dialogs should take control over input and not send them to the game while displaying
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
yesnoChoice = 0;
|
||||
display = DS_DELETE_CONFIRM;
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_DELETE_CONFIRM:
|
||||
StartDraw();
|
||||
DisplayTitle("Delete");
|
||||
|
||||
DisplaySaveIcon();
|
||||
DisplaySaveDataInfo2();
|
||||
|
||||
DisplayConfirmationYesNo("The data will be deleted.\nAre you sure you want to continue?");
|
||||
|
||||
DisplayEnterBack();
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
display = DS_DELETE_LIST_CHOICE;
|
||||
}
|
||||
else if (IsButtonPressed(okButtonFlag))
|
||||
{
|
||||
if(yesnoChoice == 0)
|
||||
{
|
||||
display = DS_DELETE_LIST_CHOICE;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = DS_DELETE_DELETING;
|
||||
if(param.Delete(param.GetPspParam(),currentSelectedSave))
|
||||
{
|
||||
param.SetPspParam(param.GetPspParam()); // Optim : Just Update modified save
|
||||
display = DS_DELETE_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = DS_DELETE_LIST_CHOICE; // This will probably need error message ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_DELETE_DELETING:
|
||||
StartDraw();
|
||||
DisplayTitle("Delete");
|
||||
|
||||
DisplayInfo("Deleting\nPlease Wait...");
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_DELETE_DONE:
|
||||
StartDraw();
|
||||
DisplayTitle("Delete");
|
||||
|
||||
DisplayBack();
|
||||
|
||||
DisplayInfo("Delete completed");
|
||||
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
if(param.GetFilenameCount() == 0)
|
||||
display = DS_DELETE_NODATA;
|
||||
else
|
||||
display = DS_DELETE_LIST_CHOICE;
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
case DS_DELETE_NODATA:
|
||||
StartDraw();
|
||||
DisplayTitle("Delete");
|
||||
|
||||
DisplayBack();
|
||||
|
||||
DisplayInfo("There is no data");
|
||||
|
||||
if (IsButtonPressed(cancelButtonFlag))
|
||||
{
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA;
|
||||
}
|
||||
|
||||
EndDraw();
|
||||
break;
|
||||
|
||||
case DS_NONE: // For action which display nothing
|
||||
{
|
||||
switch(param.GetPspParam()->mode)
|
||||
{
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LOAD: // Only load and exit
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD:
|
||||
if(param.Load(param.GetPspParam(),param.GetSelectedSave()))
|
||||
param.GetPspParam()->result = 0;
|
||||
else
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA;
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SAVE: // Only save and exit
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE:
|
||||
if(param.Save(param.GetPspParam(),param.GetSelectedSave()))
|
||||
param.GetPspParam()->result = 0;
|
||||
else
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE;
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
break;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SIZES:
|
||||
param.GetSizes(param.GetPspParam());
|
||||
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA;
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
|
||||
param.GetList(param.GetPspParam());
|
||||
param.GetPspParam()->result = 0;
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
default:
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
lastButtons = buttons;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PSPSaveDialog::Shutdown()
|
||||
{
|
||||
PSPDialog::Shutdown();
|
||||
param.SetPspParam(0);
|
||||
}
|
||||
|
114
Core/Dialog/PSPSaveDialog.h
Normal file
114
Core/Dialog/PSPSaveDialog.h
Normal file
@ -0,0 +1,114 @@
|
||||
// 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 "PSPDialog.h"
|
||||
#include "SavedataParam.h"
|
||||
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_TYPE (0x80110300)
|
||||
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_MS (0x80110301)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_EJECT_MS (0x80110302)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_ACCESS_ERROR (0x80110305)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN (0x80110306)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA (0x80110307)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_PARAM (0x80110308)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_LOAD_INTERNAL (0x8011030b)
|
||||
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_NO_MS (0x80110381)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_EJECT_MS (0x80110382)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE (0x80110383)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_PROTECTED (0x80110384)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_ACCESS_ERROR (0x80110385)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_PARAM (0x80110388)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_NO_UMD (0x80110389)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_WRONG_UMD (0x8011038a)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SAVE_INTERNAL (0x8011038b)
|
||||
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_MS (0x80110341)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_EJECT_MS (0x80110342)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_MS_PROTECTED (0x80110344)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_ACCESS_ERROR (0x80110345)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA (0x80110347)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_PARAM (0x80110348)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_DELETE_INTERNAL (0x8011034b)
|
||||
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_MS (0x801103C1)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_EJECT_MS (0x801103C2)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_ACCESS_ERROR (0x801103C5)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA (0x801103C7)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_PARAM (0x801103C8)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_UMD (0x801103C9)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_WRONG_UMD (0x801103Ca)
|
||||
#define SCE_UTILITY_SAVEDATA_ERROR_SIZES_INTERNAL (0x801103Cb)
|
||||
|
||||
class PSPSaveDialog: public PSPDialog {
|
||||
public:
|
||||
PSPSaveDialog();
|
||||
virtual ~PSPSaveDialog();
|
||||
|
||||
virtual void Init(int paramAddr);
|
||||
virtual void Update();
|
||||
void Shutdown();
|
||||
|
||||
private :
|
||||
|
||||
void DisplaySaveList(bool canMove = true);
|
||||
void DisplaySaveIcon();
|
||||
void DisplayTitle(std::string name);
|
||||
void DisplayEnterBack();
|
||||
void DisplayBack();
|
||||
void DisplaySaveDataInfo1();
|
||||
void DisplaySaveDataInfo2();
|
||||
void DisplayConfirmationYesNo(std::string text);
|
||||
void DisplayInfo(std::string text);
|
||||
|
||||
enum DisplayState
|
||||
{
|
||||
DS_NONE,
|
||||
|
||||
DS_SAVE_LIST_CHOICE,
|
||||
DS_SAVE_CONFIRM_OVERWRITE,
|
||||
DS_SAVE_SAVING,
|
||||
DS_SAVE_DONE,
|
||||
|
||||
DS_LOAD_LIST_CHOICE,
|
||||
DS_LOAD_LOADING,
|
||||
DS_LOAD_DONE,
|
||||
DS_LOAD_NODATA,
|
||||
|
||||
DS_DELETE_LIST_CHOICE,
|
||||
DS_DELETE_CONFIRM,
|
||||
DS_DELETE_DELETING,
|
||||
DS_DELETE_DONE,
|
||||
DS_DELETE_NODATA
|
||||
};
|
||||
|
||||
DisplayState display;
|
||||
|
||||
SavedataParam param;
|
||||
int currentSelectedSave;
|
||||
|
||||
int yesnoChoice;
|
||||
|
||||
int okButtonImg;
|
||||
int cancelButtonImg;
|
||||
int okButtonFlag;
|
||||
int cancelButtonFlag;
|
||||
};
|
||||
|
554
Core/Dialog/SavedataParam.cpp
Normal file
554
Core/Dialog/SavedataParam.cpp
Normal file
@ -0,0 +1,554 @@
|
||||
// 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 "SavedataParam.h"
|
||||
#include "../System.h"
|
||||
#include "image/png_load.h"
|
||||
#include "../HLE/sceKernelMemory.h"
|
||||
#include "../ELF/ParamSFO.h"
|
||||
|
||||
std::string icon0Name = "ICON0.PNG";
|
||||
std::string icon1Name = "ICON1.PMF";
|
||||
std::string pic1Name = "PIC1.PNG";
|
||||
std::string snd0Name = "SND0.AT3";
|
||||
std::string sfoName = "PARAM.SFO";
|
||||
|
||||
std::string savePath = "ms0:/PSP/SAVEDATA/";
|
||||
|
||||
SavedataParam::SavedataParam()
|
||||
: pspParam(0)
|
||||
, selectedSave(0)
|
||||
, saveNameListData(0)
|
||||
, saveDataList(0)
|
||||
, saveNameListDataCount(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SavedataParam::Init()
|
||||
{
|
||||
if(!pspFileSystem.GetFileInfo(savePath).exists)
|
||||
{
|
||||
pspFileSystem.MkDir(savePath);
|
||||
}
|
||||
}
|
||||
|
||||
std::string SavedataParam::GetSaveDir(SceUtilitySavedataParam* param, int saveId)
|
||||
{
|
||||
if (!param) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string dirPath = GetGameName(param)+GetSaveName(param);
|
||||
if(saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
|
||||
dirPath = std::string(GetGameName(param))+GetFilename(saveId);
|
||||
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
std::string SavedataParam::GetSaveFilePath(SceUtilitySavedataParam* param, int saveId)
|
||||
{
|
||||
if (!param) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return savePath + GetSaveDir(param,saveId);
|
||||
}
|
||||
|
||||
std::string SavedataParam::GetGameName(SceUtilitySavedataParam* param)
|
||||
{
|
||||
char gameName[14];
|
||||
memcpy(gameName,param->gameName,13);
|
||||
gameName[13] = 0;
|
||||
return gameName;
|
||||
}
|
||||
|
||||
std::string SavedataParam::GetSaveName(SceUtilitySavedataParam* param)
|
||||
{
|
||||
char saveName[21];
|
||||
memcpy(saveName,param->saveName,20);
|
||||
saveName[20] = 0;
|
||||
return saveName;
|
||||
}
|
||||
|
||||
std::string SavedataParam::GetFileName(SceUtilitySavedataParam* param)
|
||||
{
|
||||
char fileName[14];
|
||||
memcpy(fileName,param->fileName,13);
|
||||
fileName[13] = 0;
|
||||
return fileName;
|
||||
}
|
||||
|
||||
bool SavedataParam::Delete(SceUtilitySavedataParam* param, int saveId)
|
||||
{
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string dirPath = GetSaveFilePath(param,saveId);
|
||||
if(saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
|
||||
{
|
||||
if(saveDataList[saveId].size == 0) // don't delete no existing file
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pspFileSystem.RmDir(dirPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
|
||||
{
|
||||
if (!param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u8* data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->dataBuf));
|
||||
|
||||
std::string dirPath = GetSaveFilePath(param, saveId);
|
||||
|
||||
if(!pspFileSystem.GetFileInfo(dirPath).exists)
|
||||
pspFileSystem.MkDir(dirPath);
|
||||
|
||||
std::string filePath = dirPath+"/"+GetFileName(param);
|
||||
INFO_LOG(HLE,"Saving file with size %u in %s",param->dataBufSize,filePath.c_str());
|
||||
unsigned int handle = pspFileSystem.OpenFile(filePath,(FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
|
||||
if(handle == 0)
|
||||
{
|
||||
ERROR_LOG(HLE,"Error opening file %s",filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
if(!pspFileSystem.WriteFile(handle, data_, param->dataBufSize))
|
||||
{
|
||||
pspFileSystem.CloseFile(handle);
|
||||
ERROR_LOG(HLE,"Error writing file %s",filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pspFileSystem.CloseFile(handle);
|
||||
|
||||
// SAVE PARAM.SFO
|
||||
ParamSFOData sfoFile;
|
||||
sfoFile.SetValue("TITLE",param->sfoParam.title,128);
|
||||
sfoFile.SetValue("SAVEDATA_TITLE",param->sfoParam.savedataTitle,128);
|
||||
sfoFile.SetValue("SAVEDATA_DETAIL",param->sfoParam.detail,1024);
|
||||
sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4);
|
||||
sfoFile.SetValue("CATEGORY","MS",4);
|
||||
sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64);
|
||||
sfoFile.SetValue("SAVEDATA_FILE_LIST","",3168); // This need to be filed with the save filename and a hash
|
||||
sfoFile.SetValue("SAVEDATA_PARAMS","",128); // This need to be filled with a hash of the save file encrypted.
|
||||
u8* sfoData;
|
||||
size_t sfoSize;
|
||||
sfoFile.WriteSFO(&sfoData,&sfoSize);
|
||||
std::string sfopath = dirPath+"/"+sfoName;
|
||||
handle = pspFileSystem.OpenFile(sfopath,(FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
|
||||
if(handle)
|
||||
{
|
||||
pspFileSystem.WriteFile(handle, sfoData, sfoSize);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
}
|
||||
delete[] sfoData;
|
||||
|
||||
// SAVE ICON0
|
||||
if(param->icon0FileData.buf)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->icon0FileData.buf));
|
||||
std::string icon0path = dirPath+"/"+icon0Name;
|
||||
handle = pspFileSystem.OpenFile(icon0path,(FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
|
||||
if(handle)
|
||||
{
|
||||
pspFileSystem.WriteFile(handle, data_, param->icon0FileData.bufSize);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
}
|
||||
}
|
||||
// SAVE ICON1
|
||||
if(param->icon1FileData.buf)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->icon1FileData.buf));
|
||||
std::string icon1path = dirPath+"/"+icon1Name;
|
||||
handle = pspFileSystem.OpenFile(icon1path,(FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
|
||||
if(handle)
|
||||
{
|
||||
pspFileSystem.WriteFile(handle, data_, param->icon1FileData.bufSize);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
}
|
||||
}
|
||||
// SAVE PIC1
|
||||
if(param->pic1FileData.buf)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->pic1FileData.buf));
|
||||
std::string pic1path = dirPath+"/"+pic1Name;
|
||||
handle = pspFileSystem.OpenFile(pic1path,(FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
|
||||
if(handle)
|
||||
{
|
||||
pspFileSystem.WriteFile(handle, data_, param->pic1FileData.bufSize);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
}
|
||||
}
|
||||
|
||||
// Save SND
|
||||
if(param->snd0FileData.buf)
|
||||
{
|
||||
data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->snd0FileData.buf));
|
||||
std::string snd0path = dirPath+"/"+snd0Name;
|
||||
handle = pspFileSystem.OpenFile(snd0path,(FileAccess)(FILEACCESS_WRITE | FILEACCESS_CREATE));
|
||||
if(handle)
|
||||
{
|
||||
pspFileSystem.WriteFile(handle, data_, param->snd0FileData.bufSize);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SavedataParam::Load(SceUtilitySavedataParam* param, int saveId)
|
||||
{
|
||||
if (!param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u8* data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->dataBuf));
|
||||
|
||||
std::string dirPath = GetSaveFilePath(param, saveId);
|
||||
if(saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it
|
||||
{
|
||||
if(saveDataList[saveId].size == 0) // don't read no existing file
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string filePath = dirPath+"/"+GetFileName(param);
|
||||
INFO_LOG(HLE,"Loading file with size %u in %s",param->dataBufSize,filePath.c_str());
|
||||
u32 handle = pspFileSystem.OpenFile(filePath,FILEACCESS_READ);
|
||||
if(!handle)
|
||||
{
|
||||
ERROR_LOG(HLE,"Error opening file %s",filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
if(!pspFileSystem.ReadFile(handle, data_, param->dataBufSize))
|
||||
{
|
||||
pspFileSystem.CloseFile(handle);
|
||||
ERROR_LOG(HLE,"Error reading file %s",filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
pspFileSystem.CloseFile(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SavedataParam::GetSizes(SceUtilitySavedataParam* param)
|
||||
{
|
||||
if (!param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Memory::IsValidAddress(param->msFree))
|
||||
{
|
||||
Memory::Write_U32(32768,param->msFree);
|
||||
Memory::Write_U32(32768,param->msFree+4);
|
||||
Memory::Write_U32(1048576,param->msFree+8);
|
||||
Memory::Write_U8(0,param->msFree+12);
|
||||
}
|
||||
if(Memory::IsValidAddress(param->msData))
|
||||
{
|
||||
Memory::Write_U32(0,param->msData+36);
|
||||
Memory::Write_U32(0,param->msData+40);
|
||||
Memory::Write_U8(0,param->msData+44);
|
||||
Memory::Write_U32(0,param->msData+52);
|
||||
Memory::Write_U8(0,param->msData+56);
|
||||
}
|
||||
if(Memory::IsValidAddress(param->utilityData))
|
||||
{
|
||||
Memory::Write_U32(13,param->utilityData);
|
||||
Memory::Write_U32(416,param->utilityData+4);
|
||||
Memory::Write_U8(0,param->utilityData+8);
|
||||
Memory::Write_U32(416,param->utilityData+16);
|
||||
Memory::Write_U8(0,param->utilityData+20);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool SavedataParam::GetList(SceUtilitySavedataParam* param)
|
||||
{
|
||||
if (!param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Memory::IsValidAddress(param->idListAddr))
|
||||
{
|
||||
Memory::Write_U32(0,param->idListAddr+4);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SavedataParam::Clear()
|
||||
{
|
||||
if(saveDataList)
|
||||
{
|
||||
for(int i = 0; i < saveNameListDataCount; i++)
|
||||
{
|
||||
if(saveDataList[i].textureData != 0)
|
||||
kernelMemory.Free(saveDataList[i].textureData);
|
||||
saveDataList[i].textureData = 0;
|
||||
}
|
||||
|
||||
delete[] saveDataList;
|
||||
saveDataList = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SavedataParam::SetPspParam(SceUtilitySavedataParam* param)
|
||||
{
|
||||
pspParam = param;
|
||||
if(!pspParam)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
bool listEmptyFile = true;
|
||||
if(param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD ||
|
||||
param->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE)
|
||||
{
|
||||
listEmptyFile = false;
|
||||
}
|
||||
|
||||
if(param->saveNameList != 0)
|
||||
{
|
||||
saveNameListData = (char(*)[20])Memory::GetPointer(param->saveNameList);
|
||||
|
||||
// Get number of fileName in array
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
count++;
|
||||
} while(saveNameListData[count][0] != 0);
|
||||
|
||||
Clear();
|
||||
saveDataList = new SaveFileInfo[count];
|
||||
|
||||
// get and stock file info for each file
|
||||
int realCount = 0;
|
||||
for(int i = 0; i <count; i++)
|
||||
{
|
||||
DEBUG_LOG(HLE,"Name : %s",saveNameListData[i]);
|
||||
|
||||
std::string fileDataPath = savePath+GetGameName(param)+saveNameListData[i]+"/"+param->fileName;
|
||||
PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath);
|
||||
if(info.exists)
|
||||
{
|
||||
saveDataList[realCount].size = info.size;
|
||||
saveDataList[realCount].saveName = saveNameListData[i];
|
||||
saveDataList[realCount].idx = i;
|
||||
saveDataList[realCount].modif_time = info.mtime;
|
||||
|
||||
// Search save image icon0
|
||||
// TODO : If icon0 don't exist, need to use icon1 which is a moving icon. Also play sound
|
||||
std::string fileDataPath2 = savePath+GetGameName(param)+saveNameListData[i]+"/"+icon0Name;
|
||||
PSPFileInfo info2 = pspFileSystem.GetFileInfo(fileDataPath2);
|
||||
if(info2.exists)
|
||||
{
|
||||
u8* textureDataPNG = new u8[info2.size];
|
||||
int handle = pspFileSystem.OpenFile(fileDataPath2,FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(handle,textureDataPNG,info2.size);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
unsigned char* textureData;
|
||||
int w,h;
|
||||
pngLoadPtr(textureDataPNG, info2.size, &w, &h, &textureData, false);
|
||||
delete[] textureDataPNG;
|
||||
u32 texSize = w*h*4;
|
||||
u32 atlasPtr = kernelMemory.Alloc(texSize, true, "SaveData Icon");
|
||||
saveDataList[realCount].textureData = atlasPtr;
|
||||
Memory::Memcpy(atlasPtr, textureData, texSize);
|
||||
free(textureData);
|
||||
saveDataList[realCount].textureWidth = w;
|
||||
saveDataList[realCount].textureHeight = h;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveDataList[realCount].textureData = 0;
|
||||
}
|
||||
|
||||
// Load info in PARAM.SFO
|
||||
fileDataPath2 = savePath+GetGameName(param)+saveNameListData[i]+"/"+sfoName;
|
||||
info2 = pspFileSystem.GetFileInfo(fileDataPath2);
|
||||
if(info2.exists)
|
||||
{
|
||||
u8* sfoParam = new u8[info2.size];
|
||||
int handle = pspFileSystem.OpenFile(fileDataPath2,FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(handle,sfoParam,info2.size);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
ParamSFOData sfoFile;
|
||||
if(sfoFile.ReadSFO(sfoParam,info2.size))
|
||||
{
|
||||
std::string title = sfoFile.GetValueString("TITLE");
|
||||
memcpy(saveDataList[realCount].title,title.c_str(),title.size());
|
||||
saveDataList[realCount].title[title.size()] = 0;
|
||||
|
||||
std::string savetitle = sfoFile.GetValueString("SAVEDATA_TITLE");
|
||||
memcpy(saveDataList[realCount].saveTitle,savetitle.c_str(),savetitle.size());
|
||||
saveDataList[realCount].saveTitle[savetitle.size()] = 0;
|
||||
|
||||
std::string savedetail = sfoFile.GetValueString("SAVEDATA_DETAIL");
|
||||
memcpy(saveDataList[realCount].saveDetail,savedetail.c_str(),savedetail.size());
|
||||
saveDataList[realCount].saveDetail[savedetail.size()] = 0;
|
||||
}
|
||||
delete sfoParam;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"%s Exist",fileDataPath.c_str());
|
||||
realCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(listEmptyFile)
|
||||
{
|
||||
saveDataList[realCount].size = 0;
|
||||
saveDataList[realCount].saveName = saveNameListData[i];
|
||||
saveDataList[realCount].idx = i;
|
||||
saveDataList[realCount].textureData = 0;
|
||||
DEBUG_LOG(HLE,"Don't Exist");
|
||||
realCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
saveNameListDataCount = realCount;
|
||||
}
|
||||
else // Load info on only save
|
||||
{
|
||||
saveNameListData == 0;
|
||||
|
||||
Clear();
|
||||
saveDataList = new SaveFileInfo[1];
|
||||
|
||||
// get and stock file info for each file
|
||||
DEBUG_LOG(HLE,"Name : %s",GetSaveName(param).c_str());
|
||||
|
||||
std::string fileDataPath = savePath+GetGameName(param)+GetSaveName(param)+"/"+param->fileName;
|
||||
PSPFileInfo info = pspFileSystem.GetFileInfo(fileDataPath);
|
||||
if(info.exists)
|
||||
{
|
||||
saveDataList[0].size = info.size;
|
||||
saveDataList[0].saveName = GetSaveName(param);
|
||||
saveDataList[0].idx = 0;
|
||||
saveDataList[0].modif_time = info.mtime;
|
||||
|
||||
// Search save image icon0
|
||||
// TODO : If icon0 don't exist, need to use icon1 which is a moving icon. Also play sound
|
||||
std::string fileDataPath2 = savePath+GetGameName(param)+GetSaveName(param)+"/"+icon0Name;
|
||||
PSPFileInfo info2 = pspFileSystem.GetFileInfo(fileDataPath2);
|
||||
if(info2.exists)
|
||||
{
|
||||
u8* textureDataPNG = new u8[info2.size];
|
||||
int handle = pspFileSystem.OpenFile(fileDataPath2,FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(handle,textureDataPNG,info2.size);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
unsigned char* textureData;
|
||||
int w,h;
|
||||
pngLoadPtr(textureDataPNG, info2.size, &w, &h, &textureData, false);
|
||||
delete[] textureDataPNG;
|
||||
u32 texSize = w*h*4;
|
||||
u32 atlasPtr = kernelMemory.Alloc(texSize, true, "SaveData Icon");
|
||||
saveDataList[0].textureData = atlasPtr;
|
||||
Memory::Memcpy(atlasPtr, textureData, texSize);
|
||||
free(textureData);
|
||||
saveDataList[0].textureWidth = w;
|
||||
saveDataList[0].textureHeight = h;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveDataList[0].textureData = 0;
|
||||
}
|
||||
|
||||
// Load info in PARAM.SFO
|
||||
fileDataPath2 = savePath+GetGameName(param)+GetSaveName(param)+"/"+sfoName;
|
||||
info2 = pspFileSystem.GetFileInfo(fileDataPath2);
|
||||
if(info2.exists)
|
||||
{
|
||||
u8* sfoParam = new u8[info2.size];
|
||||
int handle = pspFileSystem.OpenFile(fileDataPath2,FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(handle,sfoParam,info2.size);
|
||||
pspFileSystem.CloseFile(handle);
|
||||
ParamSFOData sfoFile;
|
||||
if(sfoFile.ReadSFO(sfoParam,info2.size))
|
||||
{
|
||||
std::string title = sfoFile.GetValueString("TITLE");
|
||||
memcpy(saveDataList[0].title,title.c_str(),title.size());
|
||||
saveDataList[0].title[title.size()] = 0;
|
||||
|
||||
std::string savetitle = sfoFile.GetValueString("SAVEDATA_TITLE");
|
||||
memcpy(saveDataList[0].saveTitle,savetitle.c_str(),savetitle.size());
|
||||
saveDataList[0].saveTitle[savetitle.size()] = 0;
|
||||
|
||||
std::string savedetail = sfoFile.GetValueString("SAVEDATA_DETAIL");
|
||||
memcpy(saveDataList[0].saveDetail,savedetail.c_str(),savedetail.size());
|
||||
saveDataList[0].saveDetail[savedetail.size()] = 0;
|
||||
}
|
||||
delete sfoParam;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"%s Exist",fileDataPath.c_str());
|
||||
saveNameListDataCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(listEmptyFile)
|
||||
{
|
||||
saveDataList[0].size = 0;
|
||||
saveDataList[0].saveName = GetSaveName(param);
|
||||
saveDataList[0].idx = 0;
|
||||
saveDataList[0].textureData = 0;
|
||||
DEBUG_LOG(HLE,"Don't Exist");
|
||||
}
|
||||
saveNameListDataCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceUtilitySavedataParam* SavedataParam::GetPspParam()
|
||||
{
|
||||
return pspParam;
|
||||
}
|
||||
|
||||
int SavedataParam::GetFilenameCount()
|
||||
{
|
||||
return saveNameListDataCount;
|
||||
}
|
||||
|
||||
const SaveFileInfo& SavedataParam::GetFileInfo(int idx)
|
||||
{
|
||||
return saveDataList[idx];
|
||||
}
|
||||
std::string SavedataParam::GetFilename(int idx)
|
||||
{
|
||||
return saveDataList[idx].saveName;
|
||||
}
|
||||
|
||||
int SavedataParam::GetSelectedSave()
|
||||
{
|
||||
return selectedSave;
|
||||
}
|
||||
void SavedataParam::SetSelectedSave(int idx)
|
||||
{
|
||||
selectedSave = idx;
|
||||
}
|
||||
|
175
Core/Dialog/SavedataParam.h
Normal file
175
Core/Dialog/SavedataParam.h
Normal file
@ -0,0 +1,175 @@
|
||||
// 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 "../HLE/sceKernel.h"
|
||||
|
||||
|
||||
enum SceUtilitySavedataType
|
||||
{
|
||||
SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD = 0,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE = 1,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LOAD = 2,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_SAVE = 3,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD = 4,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LISTSAVE = 5,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 6,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_DELETE = 7,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LIST = 11
|
||||
} ;
|
||||
|
||||
// title, savedataTitle, detail: parts of the unencrypted SFO
|
||||
// data, it contains what the VSH and standard load screen shows
|
||||
struct PspUtilitySavedataSFOParam
|
||||
{
|
||||
char title[0x80];
|
||||
char savedataTitle[0x80];
|
||||
char detail[0x400];
|
||||
unsigned char parentalLevel;
|
||||
unsigned char unknown[3];
|
||||
};
|
||||
|
||||
struct PspUtilitySavedataFileData {
|
||||
int buf;
|
||||
SceSize bufSize; // Size of the buffer pointed to by buf
|
||||
SceSize size; // Actual file size to write / was read
|
||||
int unknown;
|
||||
};
|
||||
|
||||
// Structure to hold the parameters for the sceUtilitySavedataInitStart function.
|
||||
struct SceUtilitySavedataParam
|
||||
{
|
||||
SceSize size; // Size of the structure
|
||||
|
||||
int language;
|
||||
|
||||
int buttonSwap;
|
||||
|
||||
int unknown[4];
|
||||
int result;
|
||||
int unknown2[4];
|
||||
|
||||
int mode; // 0 to load, 1 to save
|
||||
int bind;
|
||||
|
||||
int overwriteMode; // use 0x10 ?
|
||||
|
||||
/** gameName: name used from the game for saves, equal for all saves */
|
||||
char gameName[13];
|
||||
char unused[3];
|
||||
/** saveName: name of the particular save, normally a number */
|
||||
char saveName[20];
|
||||
int saveNameList;
|
||||
/** fileName: name of the data file of the game for example DATA.BIN */
|
||||
char fileName[13];
|
||||
char unused2[3];
|
||||
|
||||
/** pointer to a buffer that will contain data file unencrypted data */
|
||||
int dataBuf; // Initially void*, but void* in 64bit system take 8 bytes.
|
||||
/** size of allocated space to dataBuf */
|
||||
SceSize dataBufSize;
|
||||
SceSize dataSize; // Size of the actual save data
|
||||
|
||||
PspUtilitySavedataSFOParam sfoParam;
|
||||
|
||||
PspUtilitySavedataFileData icon0FileData;
|
||||
PspUtilitySavedataFileData icon1FileData;
|
||||
PspUtilitySavedataFileData pic1FileData;
|
||||
PspUtilitySavedataFileData snd0FileData;
|
||||
|
||||
int newData;
|
||||
int focus;
|
||||
int abortStatus;
|
||||
|
||||
// Function SCE_UTILITY_SAVEDATA_TYPE_SIZES
|
||||
int msFree;
|
||||
int msData;
|
||||
int utilityData;
|
||||
|
||||
char key[16];
|
||||
|
||||
int secureVersion;
|
||||
int multiStatus;
|
||||
|
||||
// Function 11 LIST
|
||||
int idListAddr;
|
||||
|
||||
// Function 12 FILES
|
||||
int fileListAddr;
|
||||
|
||||
// Function 22 GETSIZES
|
||||
int sizeAddr;
|
||||
|
||||
};
|
||||
|
||||
struct SaveFileInfo
|
||||
{
|
||||
int size;
|
||||
std::string saveName;
|
||||
int idx;
|
||||
|
||||
char title[128];
|
||||
char saveTitle[128];
|
||||
char saveDetail[1024];
|
||||
|
||||
tm modif_time;
|
||||
|
||||
u32 textureData;
|
||||
int textureWidth;
|
||||
int textureHeight;
|
||||
};
|
||||
|
||||
class SavedataParam
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
std::string GetSaveFilePath(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
std::string GetSaveDir(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
bool Delete(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
bool Save(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
bool Load(SceUtilitySavedataParam* param, int saveId = -1);
|
||||
bool GetSizes(SceUtilitySavedataParam* param);
|
||||
bool GetList(SceUtilitySavedataParam* param);
|
||||
|
||||
std::string GetGameName(SceUtilitySavedataParam* param);
|
||||
std::string GetSaveName(SceUtilitySavedataParam* param);
|
||||
std::string GetFileName(SceUtilitySavedataParam* param);
|
||||
|
||||
SavedataParam();
|
||||
|
||||
void SetPspParam(SceUtilitySavedataParam* param);
|
||||
SceUtilitySavedataParam* GetPspParam();
|
||||
|
||||
int GetFilenameCount();
|
||||
const SaveFileInfo& GetFileInfo(int idx);
|
||||
std::string GetFilename(int idx);
|
||||
|
||||
int GetSelectedSave();
|
||||
void SetSelectedSave(int idx);
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
SceUtilitySavedataParam* pspParam;
|
||||
int selectedSave;
|
||||
char (*saveNameListData)[20];
|
||||
SaveFileInfo* saveDataList;
|
||||
int saveNameListDataCount;
|
||||
|
||||
};
|
@ -79,7 +79,7 @@ bool ElfReader::LoadInto(u32 loadAddress)
|
||||
entryPoint = header->e_entry;
|
||||
u32 totalStart = 0xFFFFFFFF;
|
||||
u32 totalEnd = 0;
|
||||
for (int i=0; i<header->e_phnum; i++) {
|
||||
for (int i = 0; i < header->e_phnum; i++) {
|
||||
Elf32_Phdr *p = &segments[i];
|
||||
if (p->p_type == PT_LOAD) {
|
||||
if (p->p_vaddr < totalStart)
|
||||
@ -127,12 +127,12 @@ bool ElfReader::LoadInto(u32 loadAddress)
|
||||
u32 srcSize = p->p_filesz;
|
||||
u32 dstSize = p->p_memsz;
|
||||
|
||||
memcpy(dst, src, srcSize);
|
||||
if (srcSize < dstSize)
|
||||
{
|
||||
//memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
|
||||
memset(dst + srcSize, 0, dstSize - srcSize); //zero out bss
|
||||
}
|
||||
|
||||
memcpy(dst, src, srcSize);
|
||||
DEBUG_LOG(LOADER,"Loadable Segment Copied to %08x, size %08x", writeAddr, (u32)p->p_memsz);
|
||||
}
|
||||
}
|
||||
|
217
Core/ELF/ParamSFO.cpp
Normal file
217
Core/ELF/ParamSFO.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
// 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../Globals.h"
|
||||
#include "ParamSFO.h"
|
||||
|
||||
struct Header
|
||||
{
|
||||
u32 magic; /* Always PSF */
|
||||
u32 version; /* Usually 1.1 */
|
||||
u32 key_table_start; /* Start position of key_table */
|
||||
u32 data_table_start; /* Start position of data_table */
|
||||
u32 index_table_entries; /* Number of entries in index_table*/
|
||||
};
|
||||
|
||||
struct IndexTable
|
||||
{
|
||||
u16 key_table_offset; /* Offset of the param_key from start of key_table */
|
||||
u16 param_fmt; /* Type of data of param_data in the data_table */
|
||||
u32 param_len; /* Used Bytes by param_data in the data_table */
|
||||
u32 param_max_len; /* Total bytes reserved for param_data in the data_table */
|
||||
u32 data_table_offset; /* Offset of the param_data from start of data_table */
|
||||
};
|
||||
|
||||
void ParamSFOData::SetValue(std::string key, unsigned int value, int max_size)
|
||||
{
|
||||
values[key].type = VT_INT;
|
||||
values[key].i_value = value;
|
||||
values[key].max_size = max_size;
|
||||
}
|
||||
void ParamSFOData::SetValue(std::string key, std::string value, int max_size)
|
||||
{
|
||||
if(key == "ACCOUNT_ID" ||
|
||||
key == "PADDING" ||
|
||||
key == "PARAMS" ||
|
||||
key == "PARAMS2" ||
|
||||
key == "SAVEDATA_FILE_LIST" ||
|
||||
key == "SAVEDATA_PARAMS")
|
||||
{
|
||||
values[key].type = VT_UTF8_SPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[key].type = VT_UTF8;
|
||||
}
|
||||
values[key].s_value = value;
|
||||
values[key].max_size = max_size;
|
||||
}
|
||||
|
||||
int ParamSFOData::GetValueInt(std::string key)
|
||||
{
|
||||
std::map<std::string,ValueData>::iterator it = values.find(key);
|
||||
if(it == values.end() || it->second.type != VT_INT)
|
||||
return 0;
|
||||
return it->second.i_value;
|
||||
}
|
||||
std::string ParamSFOData::GetValueString(std::string key)
|
||||
{
|
||||
std::map<std::string,ValueData>::iterator it = values.find(key);
|
||||
if(it == values.end() || (it->second.type != VT_UTF8 && it->second.type != VT_UTF8_SPE))
|
||||
return "";
|
||||
return it->second.s_value;
|
||||
}
|
||||
|
||||
// I'm so sorry Ced but this is highly endian unsafe :(
|
||||
bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size)
|
||||
{
|
||||
const Header *header = (const Header *)paramsfo;
|
||||
if (header->magic != 0x46535000)
|
||||
return false;
|
||||
if (header->version != 0x00000101)
|
||||
WARN_LOG(LOADER, "Unexpected SFO header version: %08x", header->version);
|
||||
|
||||
const IndexTable *indexTables = (const IndexTable *)(paramsfo + sizeof(Header));
|
||||
|
||||
const u8 *key_start = paramsfo + header->key_table_start;
|
||||
const u8 *data_start = paramsfo + header->data_table_start;
|
||||
|
||||
for (u32 i = 0; i < header->index_table_entries; i++)
|
||||
{
|
||||
const char *key = (const char *)(key_start + indexTables[i].key_table_offset);
|
||||
|
||||
switch (indexTables[i].param_fmt) {
|
||||
case 0x0404:
|
||||
{
|
||||
// Unsigned int
|
||||
const u32 *data = (const u32 *)(data_start + indexTables[i].data_table_offset);
|
||||
SetValue(key,*data,indexTables[i].param_max_len);
|
||||
DEBUG_LOG(LOADER, "%s %08x", key, *data);
|
||||
}
|
||||
break;
|
||||
case 0x0004:
|
||||
// Special format UTF-8
|
||||
{
|
||||
const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset);
|
||||
DEBUG_LOG(LOADER, "%s %s", key, utfdata);
|
||||
SetValue(key,std::string(utfdata,indexTables[i].param_len),indexTables[i].param_max_len);
|
||||
}
|
||||
break;
|
||||
case 0x0204:
|
||||
// Regular UTF-8
|
||||
{
|
||||
const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset);
|
||||
DEBUG_LOG(LOADER, "%s %s", key, utfdata);
|
||||
SetValue(key,std::string(utfdata,indexTables[i].param_len),indexTables[i].param_max_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
||||
{
|
||||
size_t total_size = 0;
|
||||
size_t key_size = 0;
|
||||
size_t data_size = 0;
|
||||
|
||||
Header header;
|
||||
header.magic = 0x46535000;
|
||||
header.version = 0x00000101;
|
||||
header.index_table_entries = 0;
|
||||
|
||||
total_size += sizeof(Header);
|
||||
|
||||
// Get size info
|
||||
for(std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
{
|
||||
key_size += it->first.size()+1;
|
||||
data_size += it->second.max_size;
|
||||
|
||||
header.index_table_entries++;
|
||||
}
|
||||
|
||||
// Padding
|
||||
while((key_size%4)) key_size++;
|
||||
|
||||
header.key_table_start = sizeof(Header) + header.index_table_entries * sizeof(IndexTable);
|
||||
header.data_table_start = header.key_table_start + key_size;
|
||||
|
||||
total_size += sizeof(IndexTable) * header.index_table_entries;
|
||||
total_size += key_size;
|
||||
total_size += data_size;
|
||||
*size = total_size;
|
||||
|
||||
u8* data = new u8[total_size];
|
||||
*paramsfo = data;
|
||||
memset(data,0,total_size);
|
||||
memcpy(data,&header,sizeof(Header));
|
||||
|
||||
// Now fill
|
||||
IndexTable *index_ptr = (IndexTable*)(data + sizeof(Header));
|
||||
u8* key_ptr = data + header.key_table_start;
|
||||
u8* data_ptr = data + header.data_table_start;
|
||||
|
||||
for(std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
{
|
||||
u16 offset = (u16)(key_ptr - (data+header.key_table_start));
|
||||
index_ptr->key_table_offset = offset;
|
||||
offset = (u16)(data_ptr - (data+header.data_table_start));
|
||||
index_ptr->data_table_offset = offset;
|
||||
index_ptr->param_max_len = it->second.max_size;
|
||||
if(it->second.type == VT_INT)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0404;
|
||||
index_ptr->param_len = 4;
|
||||
|
||||
*(int*)data_ptr = it->second.i_value;
|
||||
}
|
||||
else if(it->second.type == VT_UTF8_SPE)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0004;
|
||||
index_ptr->param_len = it->second.s_value.size()+1;
|
||||
|
||||
memcpy(data_ptr,it->second.s_value.c_str(),index_ptr->param_len);
|
||||
data_ptr[index_ptr->param_len] = 0;
|
||||
}
|
||||
else if(it->second.type == VT_UTF8)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0204;
|
||||
index_ptr->param_len = it->second.s_value.size()+1;
|
||||
|
||||
memcpy(data_ptr,it->second.s_value.c_str(),index_ptr->param_len);
|
||||
data_ptr[index_ptr->param_len] = 0;
|
||||
}
|
||||
|
||||
memcpy(key_ptr,it->first.c_str(),it->first.size());
|
||||
key_ptr[it->first.size()] = 0;
|
||||
|
||||
data_ptr += index_ptr->param_max_len;
|
||||
key_ptr += it->first.size()+1;
|
||||
index_ptr++;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
52
Core/ELF/ParamSFO.h
Normal file
52
Core/ELF/ParamSFO.h
Normal file
@ -0,0 +1,52 @@
|
||||
// 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 <map>
|
||||
|
||||
class ParamSFOData
|
||||
{
|
||||
public:
|
||||
void SetValue(std::string key, unsigned int value, int max_size);
|
||||
void SetValue(std::string key, std::string value, int max_size);
|
||||
|
||||
int GetValueInt(std::string key);
|
||||
std::string GetValueString(std::string key);
|
||||
|
||||
bool ReadSFO(const u8 *paramsfo, size_t size);
|
||||
bool WriteSFO(u8 **paramsfo, size_t *size);
|
||||
private:
|
||||
|
||||
enum ValueType
|
||||
{
|
||||
VT_INT,
|
||||
VT_UTF8,
|
||||
VT_UTF8_SPE
|
||||
};
|
||||
struct ValueData
|
||||
{
|
||||
ValueType type;
|
||||
int max_size;
|
||||
std::string s_value;
|
||||
int i_value;
|
||||
};
|
||||
|
||||
std::map<std::string,ValueData> values;
|
||||
};
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath)
|
||||
{
|
||||
File::CreateFullPath(basePath);
|
||||
hAlloc = _hAlloc;
|
||||
}
|
||||
|
||||
@ -35,17 +36,16 @@ std::string DirectoryFileSystem::GetLocalPath(std::string localpath)
|
||||
if (localpath.empty())
|
||||
return basePath;
|
||||
|
||||
if (localpath[0] == '/')
|
||||
localpath.erase(0,1);
|
||||
if (localpath[0] == '/')
|
||||
localpath.erase(0,1);
|
||||
//Convert slashes
|
||||
#ifdef _WIN32
|
||||
for (size_t i = 0; i < localpath.size(); i++)
|
||||
{
|
||||
if (localpath[i] == '/')
|
||||
localpath[i] = '\\';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return basePath + localpath;
|
||||
}
|
||||
|
||||
@ -53,21 +53,38 @@ std::string DirectoryFileSystem::GetLocalPath(std::string localpath)
|
||||
bool DirectoryFileSystem::MkDir(const std::string &dirname)
|
||||
{
|
||||
std::string fullName = GetLocalPath(dirname);
|
||||
#ifdef _WIN32
|
||||
return CreateDirectory(fullName.c_str(), NULL) == TRUE;
|
||||
#else
|
||||
mkdir(fullName.c_str(), 0777);
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return File::CreateFullPath(fullName);
|
||||
|
||||
}
|
||||
|
||||
bool DirectoryFileSystem::RmDir(const std::string &dirname)
|
||||
{
|
||||
std::string fullName = GetLocalPath(dirname);
|
||||
#ifdef _WIN32
|
||||
/*#ifdef _WIN32
|
||||
return RemoveDirectory(fullName.c_str()) == TRUE;
|
||||
#else
|
||||
return 0 == rmdir(fullName.c_str());
|
||||
return 0 == rmdir(fullName.c_str());
|
||||
#endif*/
|
||||
return File::DeleteDirRecursively(fullName);
|
||||
}
|
||||
|
||||
bool DirectoryFileSystem::RenameFile(const std::string &from, const std::string &to)
|
||||
{
|
||||
std::string fullFrom = GetLocalPath(from);
|
||||
std::string fullTo = to;
|
||||
// TO filename may not include path. Intention is that it uses FROM's path
|
||||
if (to.find("/") != std::string::npos) {
|
||||
int offset = from.find_last_of("/");
|
||||
if (offset >= 0) {
|
||||
fullTo = from.substr(0, offset + 1) + to;
|
||||
}
|
||||
}
|
||||
fullTo = GetLocalPath(fullTo);
|
||||
#ifdef _WIN32
|
||||
return MoveFile(fullFrom.c_str(), fullTo.c_str()) == TRUE;
|
||||
#else
|
||||
return 0 == rename(fullFrom.c_str(), fullTo.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -77,7 +94,7 @@ bool DirectoryFileSystem::DeleteFile(const std::string &filename)
|
||||
#ifdef _WIN32
|
||||
return DeleteFile(fullName.c_str()) == TRUE;
|
||||
#else
|
||||
return 0 == unlink(fullName.c_str());
|
||||
return 0 == unlink(fullName.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -243,7 +260,7 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename)
|
||||
x.name = filename;
|
||||
|
||||
|
||||
std::string fullName = GetLocalPath(filename);
|
||||
std::string fullName = GetLocalPath(filename);
|
||||
if (!File::Exists(fullName)) {
|
||||
return x;
|
||||
}
|
||||
@ -257,9 +274,10 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename)
|
||||
|
||||
x.size = data.nFileSizeLow | ((u64)data.nFileSizeHigh<<32);
|
||||
#else
|
||||
x.size = File::GetSize(fullName);
|
||||
//TODO
|
||||
x.size = File::GetSize(fullName);
|
||||
//TODO
|
||||
#endif
|
||||
x.mtime = File::GetModifTime(fullName);
|
||||
|
||||
return x;
|
||||
}
|
||||
@ -289,7 +307,10 @@ std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path)
|
||||
else
|
||||
entry.type = FILETYPE_NORMAL;
|
||||
|
||||
entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);
|
||||
if (!strcmp(findData.cFileName, "..") )// TODO: is this just for .. or all sub directories? Need to add a directory to the test to find out. Also why so different than the old test results?
|
||||
entry.size = 4096;
|
||||
else
|
||||
entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);
|
||||
entry.name = findData.cFileName;
|
||||
|
||||
myVector.push_back(entry);
|
||||
|
@ -36,7 +36,7 @@ class DirectoryFileSystem : public IFileSystem
|
||||
#ifdef _WIN32
|
||||
HANDLE hFile;
|
||||
#else
|
||||
FILE *hFile;
|
||||
FILE *hFile;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -61,6 +61,7 @@ public:
|
||||
bool OwnsHandle(u32 handle);
|
||||
bool MkDir(const std::string &dirname);
|
||||
bool RmDir(const std::string &dirname);
|
||||
bool RenameFile(const std::string &from, const std::string &to);
|
||||
bool DeleteFile(const std::string &filename);
|
||||
};
|
||||
|
||||
|
||||
|
@ -62,6 +62,8 @@ struct PSPFileInfo
|
||||
bool exists;
|
||||
FileType type;
|
||||
|
||||
tm mtime;
|
||||
|
||||
bool isOnSectorSystem;
|
||||
u32 startSector;
|
||||
u32 numSectors;
|
||||
@ -83,6 +85,7 @@ public:
|
||||
virtual bool OwnsHandle(u32 handle) = 0;
|
||||
virtual bool MkDir(const std::string &dirname) = 0;
|
||||
virtual bool RmDir(const std::string &dirname) = 0;
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) = 0;
|
||||
virtual bool DeleteFile(const std::string &filename) = 0;
|
||||
};
|
||||
|
||||
@ -100,6 +103,7 @@ public:
|
||||
bool OwnsHandle(u32 handle) {return false;}
|
||||
virtual bool MkDir(const std::string &dirname) {return false;}
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
};
|
||||
|
||||
|
@ -207,8 +207,9 @@ nextblock:
|
||||
e->isDirectory = !isFile;
|
||||
e->flags = dir.flags;
|
||||
e->isBlockSectorMode = false;
|
||||
|
||||
DEBUG_LOG(FILESYS, "%s: %s %08x %08x %i", e->isDirectory?"D":"F", name, dir.firstDataSectorLE, e->startingPosition, e->startingPosition);
|
||||
|
||||
// Let's not excessively spam the log - I commented this line out.
|
||||
// DEBUG_LOG(FILESYS, "%s: %s %08x %08x %i", e->isDirectory?"D":"F", name, dir.firstDataSectorLE, e->startingPosition, e->startingPosition);
|
||||
|
||||
if (e->isDirectory && !relative)
|
||||
{
|
||||
@ -414,7 +415,7 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
|
||||
posInSector = 0;
|
||||
secNum++;
|
||||
}
|
||||
e.seekPos += size;
|
||||
e.seekPos += (unsigned int)size;
|
||||
return totalRead;
|
||||
}
|
||||
else
|
||||
@ -449,7 +450,7 @@ size_t ISOFileSystem::SeekFile(u32 handle, s32 position, FileMove type)
|
||||
if (e.isRawSector)
|
||||
e.seekPos = e.openSize;
|
||||
else
|
||||
e.seekPos = e.file->size + position;
|
||||
e.seekPos = (unsigned int)(e.file->size + position);
|
||||
break;
|
||||
}
|
||||
return (size_t)e.seekPos;
|
||||
|
@ -82,5 +82,6 @@ public:
|
||||
|
||||
virtual bool MkDir(const std::string &dirname) {return false;}
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
};
|
||||
|
@ -18,6 +18,159 @@
|
||||
#include <set>
|
||||
#include "MetaFileSystem.h"
|
||||
|
||||
bool applyPathStringToComponentsVector(std::vector<std::string> &vector, const std::string &pathString)
|
||||
{
|
||||
size_t len = pathString.length();
|
||||
size_t start = 0;
|
||||
|
||||
while (start < len)
|
||||
{
|
||||
size_t i = pathString.find('/', start);
|
||||
if (i == std::string::npos)
|
||||
i = len;
|
||||
|
||||
if (i > start)
|
||||
{
|
||||
std::string component = pathString.substr(start, i - start);
|
||||
if (component != ".")
|
||||
{
|
||||
if (component == "..")
|
||||
{
|
||||
if (vector.size() != 0)
|
||||
{
|
||||
vector.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
// what does the real PSP do for "/../filename"?
|
||||
WARN_LOG(HLE, "RealPath: .. as first path component: \"%s\"", pathString.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vector.push_back(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start = i + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes relative paths to absolute, removes ".", "..", and trailing "/"
|
||||
* babel (and possibly other games) use "/directoryThatDoesNotExist/../directoryThatExists/filename"
|
||||
*/
|
||||
bool RealPath(const std::string ¤tDirectory, const std::string &inPath, std::string &outPath)
|
||||
{
|
||||
size_t inLen = inPath.length();
|
||||
if (inLen == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "RealPath: inPath is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t inColon = inPath.find(':');
|
||||
if (inColon + 1 == inLen)
|
||||
{
|
||||
WARN_LOG(HLE, "RealPath: inPath is all prefix and no path: \"%s\"", inPath.c_str());
|
||||
|
||||
outPath = inPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string curDirPrefix;
|
||||
size_t curDirColon = std::string::npos, curDirLen = currentDirectory.length();
|
||||
if (curDirLen != 0)
|
||||
{
|
||||
curDirColon = currentDirectory.find(':');
|
||||
|
||||
if (curDirColon == std::string::npos)
|
||||
{
|
||||
DEBUG_LOG(HLE, "RealPath: currentDirectory has no prefix: \"%s\"", currentDirectory.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curDirColon + 1 == curDirLen)
|
||||
DEBUG_LOG(HLE, "RealPath: currentDirectory is all prefix and no path: \"%s\"", currentDirectory.c_str());
|
||||
|
||||
curDirPrefix = currentDirectory.substr(0, curDirColon + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string inPrefix, inAfter;
|
||||
|
||||
if (inColon == std::string::npos)
|
||||
{
|
||||
inPrefix = curDirPrefix;
|
||||
inAfter = inPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
inPrefix = inPath.substr(0, inColon + 1);
|
||||
inAfter = inPath.substr(inColon + 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> cmpnts; // path components
|
||||
size_t capacityGuess = inPath.length();
|
||||
|
||||
if ((inAfter[0] != '/'))
|
||||
{
|
||||
if (curDirLen == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "RealPath: inPath \"%s\" is relative, but current directory is empty", inPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (curDirColon == std::string::npos || curDirPrefix.length() == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" has no prefix", inPath.c_str(), currentDirectory.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inPrefix != curDirPrefix)
|
||||
WARN_LOG(HLE, "RealPath: inPath \"%s\" is relative, but specifies a different prefix than current directory \"%s\"", inPath.c_str(), currentDirectory.c_str());
|
||||
|
||||
if (curDirColon + 1 == curDirLen)
|
||||
{
|
||||
ERROR_LOG(HLE, "RealPath: inPath \"%s\" is relative, but current directory \"%s\" is all prefix and no path. Using \"/\" as path for current directory.", inPath.c_str(), currentDirectory.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string curDirAfter = currentDirectory.substr(curDirColon + 1);
|
||||
if (! applyPathStringToComponentsVector(cmpnts, curDirAfter) )
|
||||
{
|
||||
ERROR_LOG(HLE,"RealPath: currentDirectory is not a valid path: \"%s\"", currentDirectory.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
capacityGuess += currentDirectory.length();
|
||||
}
|
||||
|
||||
if (! applyPathStringToComponentsVector(cmpnts, inAfter) )
|
||||
{
|
||||
DEBUG_LOG(HLE, "RealPath: inPath is not a valid path: \"%s\"", inPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
outPath.clear();
|
||||
outPath.reserve(capacityGuess);
|
||||
|
||||
outPath.append(inPrefix);
|
||||
|
||||
size_t numCmpnts = cmpnts.size();
|
||||
for (size_t i = 0; i < numCmpnts; i++)
|
||||
{
|
||||
outPath.append(1, '/');
|
||||
outPath.append(cmpnts[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle)
|
||||
{
|
||||
for (size_t i = 0; i < fileSystems.size(); i++)
|
||||
@ -31,21 +184,29 @@ IFileSystem *MetaFileSystem::GetHandleOwner(u32 handle)
|
||||
|
||||
bool MetaFileSystem::MapFilePath(std::string inpath, std::string &outpath, IFileSystem **system)
|
||||
{
|
||||
// host0 HACK
|
||||
// need to figure out what to do about xxx:./... paths - is there a current dir per drive?
|
||||
if (!inpath.compare(0, 8, "host0:./"))
|
||||
inpath = currentDirectory + inpath.substr(7);
|
||||
//TODO: implement current directory per thread (NOT per drive)
|
||||
|
||||
//DEBUG_LOG(HLE, "MapFilePath: starting with \"%s\"", inpath.c_str());
|
||||
|
||||
for (size_t i = 0; i < fileSystems.size(); i++)
|
||||
if ( RealPath(currentDirectory, inpath, inpath) )
|
||||
{
|
||||
int prefLen = fileSystems[i].prefix.size();
|
||||
if (fileSystems[i].prefix == inpath.substr(0,prefLen))
|
||||
for (size_t i = 0; i < fileSystems.size(); i++)
|
||||
{
|
||||
outpath = inpath.substr(prefLen);
|
||||
*system = fileSystems[i].system;
|
||||
return true;
|
||||
size_t prefLen = fileSystems[i].prefix.size();
|
||||
if (fileSystems[i].prefix == inpath.substr(0, prefLen))
|
||||
{
|
||||
outpath = inpath.substr(prefLen);
|
||||
*system = fileSystems[i].system;
|
||||
|
||||
DEBUG_LOG(HLE, "MapFilePath: mapped to prefix: \"%s\", path: \"%s\"", fileSystems[i].prefix.c_str(), outpath.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "MapFilePath: failed, returning false");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -80,11 +241,6 @@ void MetaFileSystem::UnmountAll()
|
||||
u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access)
|
||||
{
|
||||
std::string of;
|
||||
if (filename.find(':') == std::string::npos)
|
||||
{
|
||||
filename = currentDirectory + "/" + filename;
|
||||
DEBUG_LOG(HLE,"OpenFile: Expanded path to %s", filename.c_str());
|
||||
}
|
||||
IFileSystem *system;
|
||||
if (MapFilePath(filename, of, &system))
|
||||
{
|
||||
@ -99,11 +255,6 @@ u32 MetaFileSystem::OpenFile(std::string filename, FileAccess access)
|
||||
PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename)
|
||||
{
|
||||
std::string of;
|
||||
if (filename.find(':') == std::string::npos)
|
||||
{
|
||||
filename = currentDirectory + "/" + filename;
|
||||
DEBUG_LOG(HLE,"GetFileInfo: Expanded path to %s", filename.c_str());
|
||||
}
|
||||
IFileSystem *system;
|
||||
if (MapFilePath(filename, of, &system))
|
||||
{
|
||||
@ -116,14 +267,19 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Not sure where this should live. Seems a bit wrong putting it in common
|
||||
bool stringEndsWith (std::string const &fullString, std::string const &ending)
|
||||
{
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PSPFileInfo> MetaFileSystem::GetDirListing(std::string path)
|
||||
{
|
||||
std::string of;
|
||||
if (path.find(':') == std::string::npos)
|
||||
{
|
||||
path = currentDirectory + "/" + path;
|
||||
DEBUG_LOG(HLE,"GetFileInfo: Expanded path to %s", path.c_str());
|
||||
}
|
||||
IFileSystem *system;
|
||||
if (MapFilePath(path, of, &system))
|
||||
{
|
||||
@ -164,6 +320,21 @@ bool MetaFileSystem::RmDir(const std::string &dirname)
|
||||
}
|
||||
}
|
||||
|
||||
bool MetaFileSystem::RenameFile(const std::string &from, const std::string &to)
|
||||
{
|
||||
std::string of;
|
||||
std::string rf;
|
||||
IFileSystem *system;
|
||||
if (MapFilePath(from, of, &system) && MapFilePath(to, rf, &system))
|
||||
{
|
||||
return system->RenameFile(of, rf);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MetaFileSystem::DeleteFile(const std::string &filename)
|
||||
{
|
||||
std::string of;
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
|
||||
virtual bool MkDir(const std::string &dirname);
|
||||
virtual bool RmDir(const std::string &dirname);
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to);
|
||||
virtual bool DeleteFile(const std::string &filename);
|
||||
|
||||
// TODO: void IoCtl(...)
|
||||
|
@ -21,171 +21,422 @@
|
||||
|
||||
// For easy parameter parsing and return value processing.
|
||||
|
||||
// 64bit wrappers
|
||||
|
||||
template<u64 func()> void WrapU64_V() {
|
||||
u64 retval = func();
|
||||
currentMIPS->r[2] = retval & 0xFFFFFFFF;
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
template<int func(u32, u64)> void WrapI_UU64() {
|
||||
u64 param_one = currentMIPS->r[6];
|
||||
param_one |= (u64)(currentMIPS->r[7]) << 32;
|
||||
int retval = func(PARAM(0), param_one);
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, u64)> void WrapI_UUU64() {
|
||||
u64 param_two = currentMIPS->r[6];
|
||||
param_two |= (u64)(currentMIPS->r[7]) << 32;
|
||||
int retval = func(PARAM(0), PARAM(1), param_two);
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, s64, int)> void WrapU_II64I() {
|
||||
s64 param_one = currentMIPS->r[6];
|
||||
param_one |= (s64)(currentMIPS->r[7]) << 32;
|
||||
u32 retval = func(PARAM(0), param_one, PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<s64 func(int, s64, int)> void WrapI64_II64I() {
|
||||
s64 param_one = currentMIPS->r[6];
|
||||
param_one |= (s64)(currentMIPS->r[7]) << 32;
|
||||
s64 retval = func(PARAM(0), param_one, PARAM(4));
|
||||
currentMIPS->r[2] = (retval >> 0) & 0xFFFFFFFF;
|
||||
currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
//32bit wrappers
|
||||
template<void func()> void WrapV_V() {
|
||||
func();
|
||||
func();
|
||||
}
|
||||
|
||||
template<u32 func()> void WrapU_V() {
|
||||
RETURN(func());
|
||||
RETURN(func());
|
||||
}
|
||||
|
||||
template<u32 func(int, void *, int)> void WrapU_IVI() {
|
||||
u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<float func()> void WrapF_V() {
|
||||
RETURNF(func());
|
||||
RETURNF(func());
|
||||
}
|
||||
|
||||
template<u32 func(u32)> void WrapU_U() {
|
||||
u32 retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32)> void WrapI_U() {
|
||||
int retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func()> void WrapI_V() {
|
||||
int retval = func();
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int)> void WrapU_I() {
|
||||
u32 retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int)> void WrapI_I() {
|
||||
int retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32)> void WrapV_U() {
|
||||
func(PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(int)> void WrapV_I() {
|
||||
func(PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(u32, u32)> void WrapV_UU() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(int, int)> void WrapV_II() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32)> void WrapU_UU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int)> void WrapU_UI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32)> void WrapI_U() {
|
||||
int retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, int)> void WrapI_UI() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, u32, int)> void WrapU_IUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32)> void WrapI_UU() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, u32)> void WrapI_UUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, u32, int, int, int,int )> void WrapI_UUUIIII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, u32, u32)> void WrapI_UUUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
template<int func()> void WrapI_V() {
|
||||
int retval = func();
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int)> void WrapU_I() {
|
||||
u32 retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int func(int)> void WrapI_I() {
|
||||
int retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32)> void WrapV_U() {
|
||||
func(PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(int)> void WrapV_I() {
|
||||
func(PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(u32, u32)> void WrapV_UU() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(int, int)> void WrapV_II() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(u32, const char *)> void WrapV_UC() {
|
||||
func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
}
|
||||
|
||||
template<int func(u32, const char *)> void WrapI_UC() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32)> void WrapU_UU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, int, u32, int, int)> void WrapV_UIUII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int)> void WrapU_UII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, int, int, int)> void WrapV_UIII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
||||
template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
}
|
||||
|
||||
template<void func(u32, int, int)> void WrapV_UII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<u32 func(int, u32)> void WrapU_IU() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32)> void WrapI_IU() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, int)> void WrapI_UUI() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int)> void WrapI_II() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, int)> void WrapI_III() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, u32)> void WrapI_IIU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(int, u32)> void WrapV_IU() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(u32, int)> void WrapV_UI() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<u32 func(const char *)> void WrapU_C() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)),
|
||||
Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)),
|
||||
PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32)> void WrapI_CU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN(retval);
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32)> void WrapI_CUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, u32)> void WrapU_CU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN((u32)retval);
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN((u32) retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, const char *)> void WrapU_UC() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, u32, u32)> void WrapU_CUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN((u32)retval);
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN((u32) retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, int, int)> void WrapU_III() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, u32, u32)> void WrapU_IUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32)> void WrapU_UUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(int, u32, u32)> void WrapV_IUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<void func(int, int, u32)> void WrapV_IIU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<void func(u32, int, u32)> void WrapV_UIU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<int func(u32, int, u32)> void WrapI_UIU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
}
|
||||
|
||||
template<void func(u32, u32, u32)> void WrapV_UUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<void func(u32, u32, u32, u32)> void WrapV_UUUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
||||
template<void func(const char *, u32, int, u32)> void WrapV_CUIU() {
|
||||
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, int, u32)> void WrapI_CUIU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() {
|
||||
func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
|
||||
PARAM(4));
|
||||
}
|
||||
|
||||
template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2),
|
||||
PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() {
|
||||
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
|
||||
PARAM(4));
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int, int)> void WrapU_UIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
}
|
||||
|
||||
template<u32 func(const char *, const char *)> void WrapU_CC() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)),
|
||||
Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(const char *, int)> void WrapV_CI() {
|
||||
func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
}
|
||||
|
||||
template<u32 func(const char *, int)> void WrapU_CI() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, int, u32, int, u32)> void WrapU_CIUIU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, int, u32, int, u32, int)> void WrapU_CIUIUI() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4),
|
||||
PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, u32, u32)> void WrapI_IUUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, u32)> void WrapI_IUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() {
|
||||
|
@ -25,10 +25,27 @@
|
||||
#include "sceIo.h"
|
||||
#include "sceAudio.h"
|
||||
#include "sceKernelMemory.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "../MIPS/MIPSCodeUtils.h"
|
||||
|
||||
enum
|
||||
{
|
||||
// Do nothing after the syscall.
|
||||
HLE_AFTER_NOTHING = 0x00,
|
||||
// Reschedule immediately after the syscall.
|
||||
HLE_AFTER_RESCHED = 0x01,
|
||||
// Call current thread's callbacks after the syscall.
|
||||
HLE_AFTER_CURRENT_CALLBACKS = 0x02,
|
||||
// Check all threads' callbacks after the syscall.
|
||||
HLE_AFTER_ALL_CALLBACKS = 0x04,
|
||||
// Reschedule and process current thread's callbacks after the syscall.
|
||||
HLE_AFTER_RESCHED_CALLBACKS = 0x08,
|
||||
};
|
||||
|
||||
static std::vector<HLEModule> moduleDB;
|
||||
static std::vector<Syscall> unresolvedSyscalls;
|
||||
static int hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
static char hleAfterSyscallReschedReason[512];
|
||||
|
||||
void HLEInit()
|
||||
{
|
||||
@ -177,6 +194,59 @@ const char *GetFuncName(int moduleIndex, int func)
|
||||
return "[unknown]";
|
||||
}
|
||||
|
||||
void hleCheckAllCallbacks()
|
||||
{
|
||||
hleAfterSyscall |= HLE_AFTER_ALL_CALLBACKS;
|
||||
}
|
||||
|
||||
void hleCheckCurrentCallbacks()
|
||||
{
|
||||
hleAfterSyscall |= HLE_AFTER_CURRENT_CALLBACKS;
|
||||
}
|
||||
|
||||
void hleReSchedule(const char *reason)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, reason != 0, "hleReSchedule: Expecting a valid reason.");
|
||||
_dbg_assert_msg_(HLE, strlen(reason) < 256, "hleReSchedule: Not too long reason.");
|
||||
|
||||
hleAfterSyscall |= HLE_AFTER_RESCHED;
|
||||
|
||||
if (!reason)
|
||||
strcpy(hleAfterSyscallReschedReason, "Invalid reason");
|
||||
// You can't seriously need a reason that long, can you?
|
||||
else if (strlen(reason) >= sizeof(hleAfterSyscallReschedReason))
|
||||
{
|
||||
memcpy(hleAfterSyscallReschedReason, reason, sizeof(hleAfterSyscallReschedReason) - 1);
|
||||
hleAfterSyscallReschedReason[sizeof(hleAfterSyscallReschedReason) - 1] = 0;
|
||||
}
|
||||
else
|
||||
strcpy(hleAfterSyscallReschedReason, reason);
|
||||
}
|
||||
|
||||
void hleReSchedule(bool callbacks, const char *reason)
|
||||
{
|
||||
hleReSchedule(reason);
|
||||
if (callbacks)
|
||||
hleAfterSyscall |= HLE_AFTER_RESCHED_CALLBACKS;
|
||||
}
|
||||
|
||||
inline void hleFinishSyscall()
|
||||
{
|
||||
if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0)
|
||||
__KernelForceCallbacks();
|
||||
|
||||
// Rescheduling will also do HLE_AFTER_ALL_CALLBACKS.
|
||||
if ((hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) != 0)
|
||||
__KernelReSchedule(true, hleAfterSyscallReschedReason);
|
||||
else if ((hleAfterSyscall & HLE_AFTER_RESCHED) != 0)
|
||||
__KernelReSchedule(hleAfterSyscallReschedReason);
|
||||
else if ((hleAfterSyscall & HLE_AFTER_ALL_CALLBACKS) != 0)
|
||||
__KernelCheckCallbacks();
|
||||
|
||||
hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
hleAfterSyscallReschedReason[0] = 0;
|
||||
}
|
||||
|
||||
void CallSyscall(u32 op)
|
||||
{
|
||||
u32 callno = (op >> 6) & 0xFFFFF; //20 bits
|
||||
@ -192,6 +262,9 @@ void CallSyscall(u32 op)
|
||||
if (func)
|
||||
{
|
||||
func();
|
||||
|
||||
if (hleAfterSyscall != HLE_AFTER_NOTHING)
|
||||
hleFinishSyscall();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -73,6 +73,14 @@ int GetModuleIndex(const char *modulename);
|
||||
|
||||
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable);
|
||||
|
||||
// Run the current thread's callbacks after the syscall finishes.
|
||||
void hleCheckCurrentCallbacks();
|
||||
// Check and potentially run all thread's callbacks after the syscall finishes.
|
||||
void hleCheckAllCallbacks();
|
||||
// Reschedule after the syscall finishes.
|
||||
void hleReSchedule(const char *reason);
|
||||
// Reschedule and go into a callback processing state after the syscall finishes.
|
||||
void hleReSchedule(bool callbacks, const char *reason);
|
||||
|
||||
void HLEInit();
|
||||
void HLEShutdown();
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "sceIo.h"
|
||||
#include "sceHprm.h"
|
||||
#include "scePower.h"
|
||||
#include "sceFont.h"
|
||||
#include "sceNet.h"
|
||||
#include "sceMpeg.h"
|
||||
#include "sceImpose.h"
|
||||
@ -35,6 +36,8 @@
|
||||
#include "sceSas.h"
|
||||
#include "sceUmd.h"
|
||||
#include "sceDmac.h"
|
||||
#include "sceRtc.h"
|
||||
#include "sceOpenPSID.h"
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelEventFlag.h"
|
||||
#include "sceKernelMemory.h"
|
||||
@ -45,6 +48,11 @@
|
||||
#include "sceKernelTime.h"
|
||||
#include "sceAudio.h"
|
||||
#include "sceUtility.h"
|
||||
#include "sceParseUri.h"
|
||||
#include "sceSsl.h"
|
||||
#include "sceParseHttp.h"
|
||||
#include "scesupPreAcc.h"
|
||||
#include "sceVaudio.h"
|
||||
|
||||
#define N(s) s
|
||||
|
||||
@ -57,15 +65,15 @@
|
||||
//zlibdec
|
||||
const HLEFunction FakeSysCalls[] =
|
||||
{
|
||||
{NID_THREADRETURN, __KernelReturnFromThread, "__KernelReturnFromThread"},
|
||||
{NID_CALLBACKRETURN, __KernelReturnFromMipsCall, "__KernelReturnFromMipsCall"},
|
||||
{NID_THREADRETURN, __KernelReturnFromThread, "__KernelReturnFromThread"},
|
||||
{NID_CALLBACKRETURN, __KernelReturnFromMipsCall, "__KernelReturnFromMipsCall"},
|
||||
{NID_INTERRUPTRETURN, __KernelReturnFromInterrupt, "__KernelReturnFromInterrupt"},
|
||||
{NID_IDLE, _sceKernelIdle, "_sceKernelIdle"},
|
||||
{NID_IDLE, __KernelIdle, "_sceKernelIdle"},
|
||||
};
|
||||
|
||||
const HLEFunction UtilsForUser[] =
|
||||
{
|
||||
{0x91E4F6A7, sceKernelLibcClock, "sceKernelLibcClock"},
|
||||
{0x91E4F6A7, WrapU_V<sceKernelLibcClock>, "sceKernelLibcClock"},
|
||||
{0x27CC57F0, sceKernelLibcTime, "sceKernelLibcTime"},
|
||||
{0x71EC4271, sceKernelLibcGettimeofday, "sceKernelLibcGettimeofday"},
|
||||
{0xBFA98062, 0, "sceKernelDcacheInvalidateRange"},
|
||||
@ -85,6 +93,7 @@ const HLEFunction UtilsForUser[] =
|
||||
{0xB435DEC5, sceKernelDcacheWritebackInvalidateAll, "sceKernelDcacheWritebackInvalidateAll"},
|
||||
{0x3EE30821, sceKernelDcacheWritebackRange, "sceKernelDcacheWritebackRange"},
|
||||
{0x34B9FA9E, sceKernelDcacheWritebackInvalidateRange, "sceKernelDcacheWritebackInvalidateRange"},
|
||||
{0xC2DF770E, 0, "sceKernelIcacheInvalidateRange"},
|
||||
{0x80001C4C, 0, "sceKernelDcacheProbe"},
|
||||
{0x16641D70, 0, "sceKernelDcacheReadTag"},
|
||||
{0x4FD31C9D, 0, "sceKernelIcacheProbe"},
|
||||
@ -93,93 +102,53 @@ const HLEFunction UtilsForUser[] =
|
||||
};
|
||||
|
||||
|
||||
const HLEFunction sceRtc[] =
|
||||
{
|
||||
{0xC41C2853, sceRtcGetTickResolution, "sceRtcGetTickResolution"},
|
||||
{0x3f7ad767, sceRtcGetCurrentTick, "sceRtcGetCurrentTick"},
|
||||
{0x011F03C1, 0, "sceRtcGetAccumulativeTime"},
|
||||
{0x029CA3B3, 0, "sceRtcGetAccumlativeTime"},
|
||||
{0x4cfa57b0, 0, "sceRtcGetCurrentClock"},
|
||||
{0xE7C27D1B, sceRtcGetCurrentClockLocalTime, "sceRtcGetCurrentClockLocalTime"},
|
||||
{0x34885E0D, 0, "sceRtcConvertUtcToLocalTime"},
|
||||
{0x779242A2, 0, "sceRtcConvertLocalTimeToUTC"},
|
||||
{0x42307A17, 0, "sceRtcIsLeapYear"},
|
||||
{0x05ef322c, &WrapU_UU<sceRtcGetDaysInMonth>, "sceRtcGetDaysInMonth"},
|
||||
{0x57726bc1, &WrapU_UUU<sceRtcGetDayOfWeek>, "sceRtcGetDayOfWeek"},
|
||||
{0x4B1B5E82, 0, "sceRtcCheckValid"},
|
||||
{0x3a807cc8, 0, "sceRtcSetTime_t"},
|
||||
{0x27c4594c, 0, "sceRtcGetTime_t"},
|
||||
{0xF006F264, 0, "sceRtcSetDosTime"},
|
||||
{0x36075567, 0, "sceRtcGetDosTime"},
|
||||
{0x7ACE4C04, 0, "sceRtcSetWin32FileTime"},
|
||||
{0xCF561893, 0, "sceRtcGetWin32FileTime"},
|
||||
{0x7ED29E40, 0, "sceRtcSetTick"},
|
||||
{0x6FF40ACC, sceRtcGetTick, "sceRtcGetTick"},
|
||||
{0x9ED0AE87, 0, "sceRtcCompareTick"},
|
||||
{0x44F45E05, 0, "sceRtcTickAddTicks"},
|
||||
{0x26D25A5D, 0, "sceRtcTickAddMicroseconds"},
|
||||
{0xF2A4AFE5, 0, "sceRtcTickAddSeconds"},
|
||||
{0xE6605BCA, 0, "sceRtcTickAddMinutes"},
|
||||
{0x26D7A24A, 0, "sceRtcTickAddHours"},
|
||||
{0xE51B4B7A, 0, "sceRtcTickAddDays"},
|
||||
{0xCF3A2CA8, 0, "sceRtcTickAddWeeks"},
|
||||
{0xDBF74F1B, 0, "sceRtcTickAddMonths"},
|
||||
{0x42842C77, 0, "sceRtcTickAddYears"},
|
||||
{0xC663B3B9, 0, "sceRtcFormatRFC2822"},
|
||||
{0x7DE6711B, 0, "sceRtcFormatRFC2822LocalTime"},
|
||||
{0x0498FB3C, 0, "sceRtcFormatRFC3339"},
|
||||
{0x27F98543, 0, "sceRtcFormatRFC3339LocalTime"},
|
||||
{0xDFBC5F16, 0, "sceRtcParseDateTime"},
|
||||
{0x28E1E988, 0, "sceRtcParseRFC3339"},
|
||||
};
|
||||
|
||||
const HLEFunction IoFileMgrForKernel[] =
|
||||
{
|
||||
{0xa905b705, 0, "sceIoCloseAll"},
|
||||
{0x411106BA, 0, "sceIoGetThreadCwd"},
|
||||
{0xCB0A151F, 0, "sceIoChangeThreadCwd"},
|
||||
{0x8E982A74, 0, "sceIoAddDrv"},
|
||||
{0xC7F35804, 0, "sceIoDelDrv"},
|
||||
{0x3C54E908, 0, "sceIoReopen"},
|
||||
{0xa905b705, 0, "sceIoCloseAll"},
|
||||
{0x411106BA, 0, "sceIoGetThreadCwd"},
|
||||
{0xCB0A151F, 0, "sceIoChangeThreadCwd"},
|
||||
{0x8E982A74, 0, "sceIoAddDrv"},
|
||||
{0xC7F35804, 0, "sceIoDelDrv"},
|
||||
{0x3C54E908, 0, "sceIoReopen"},
|
||||
};
|
||||
const HLEFunction StdioForKernel[] =
|
||||
{
|
||||
{0x98220F3E, 0, "sceKernelStdoutReopen"},
|
||||
{0xFB5380C5, 0, "sceKernelStderrReopen"},
|
||||
{0x2CCF071A, 0, "fdprintf"},
|
||||
{0x98220F3E, 0, "sceKernelStdoutReopen"},
|
||||
{0xFB5380C5, 0, "sceKernelStderrReopen"},
|
||||
{0x2CCF071A, 0, "fdprintf"},
|
||||
};
|
||||
const HLEFunction LoadCoreForKernel[] =
|
||||
{
|
||||
{0xACE23476, 0, "sceKernelCheckPspConfig"},
|
||||
{0x7BE1421C, 0, "sceKernelCheckExecFile"},
|
||||
{0xBF983EF2, 0, "sceKernelProbeExecutableObject"},
|
||||
{0x7068E6BA, 0, "sceKernelLoadExecutableObject"},
|
||||
{0xB4D6FECC, 0, "sceKernelApplyElfRelSection"},
|
||||
{0x54AB2675, 0, "LoadCoreForKernel_54AB2675"},
|
||||
{0x2952F5AC, 0, "sceKernelDcacheWBinvAll"},
|
||||
{0xD8779AC6, sceKernelIcacheClearAll, "sceKernelIcacheClearAll"},
|
||||
{0x99A695F0, 0, "sceKernelRegisterLibrary"},
|
||||
{0x5873A31F, 0, "sceKernelRegisterLibraryForUser"},
|
||||
{0x0B464512, 0, "sceKernelReleaseLibrary"},
|
||||
{0x9BAF90F6, 0, "sceKernelCanReleaseLibrary"},
|
||||
{0x0E760DBA, 0, "sceKernelLinkLibraryEntries"},
|
||||
{0x0DE1F600, 0, "sceKernelLinkLibraryEntriesForUser"},
|
||||
{0xDA1B09AA, 0, "sceKernelUnLinkLibraryEntries"},
|
||||
{0xC99DD47A, 0, "sceKernelQueryLoadCoreCB"},
|
||||
{0x616FCCCD, 0, "sceKernelSetBootCallbackLevel"},
|
||||
{0xF32A2940, 0, "sceKernelModuleFromUID"},
|
||||
{0xCD0F3BAC, 0, "sceKernelCreateModule"},
|
||||
{0x6B2371C2, 0, "sceKernelDeleteModule"},
|
||||
{0x7320D964, 0, "sceKernelModuleAssign"},
|
||||
{0x44B292AB, 0, "sceKernelAllocModule"},
|
||||
{0xBD61D4D5, 0, "sceKernelFreeModule"},
|
||||
{0xAE7C6E76, 0, "sceKernelRegisterModule"},
|
||||
{0x74CF001A, 0, "sceKernelReleaseModule"},
|
||||
{0xFB8AE27D, 0, "sceKernelFindModuleByAddress"},
|
||||
{0xCCE4A157, 0, "sceKernelFindModuleByUID"},
|
||||
{0x82CE54ED, 0, "sceKernelModuleCount"},
|
||||
{0xC0584F0C, 0, "sceKernelGetModuleList"},
|
||||
{0xCF8A41B1, sceKernelFindModuleByName,"sceKernelFindModuleByName"},
|
||||
{0xACE23476, 0, "sceKernelCheckPspConfig"},
|
||||
{0x7BE1421C, 0, "sceKernelCheckExecFile"},
|
||||
{0xBF983EF2, 0, "sceKernelProbeExecutableObject"},
|
||||
{0x7068E6BA, 0, "sceKernelLoadExecutableObject"},
|
||||
{0xB4D6FECC, 0, "sceKernelApplyElfRelSection"},
|
||||
{0x54AB2675, 0, "LoadCoreForKernel_54AB2675"},
|
||||
{0x2952F5AC, 0, "sceKernelDcacheWBinvAll"},
|
||||
{0xD8779AC6, sceKernelIcacheClearAll, "sceKernelIcacheClearAll"},
|
||||
{0x99A695F0, 0, "sceKernelRegisterLibrary"},
|
||||
{0x5873A31F, 0, "sceKernelRegisterLibraryForUser"},
|
||||
{0x0B464512, 0, "sceKernelReleaseLibrary"},
|
||||
{0x9BAF90F6, 0, "sceKernelCanReleaseLibrary"},
|
||||
{0x0E760DBA, 0, "sceKernelLinkLibraryEntries"},
|
||||
{0x0DE1F600, 0, "sceKernelLinkLibraryEntriesForUser"},
|
||||
{0xDA1B09AA, 0, "sceKernelUnLinkLibraryEntries"},
|
||||
{0xC99DD47A, 0, "sceKernelQueryLoadCoreCB"},
|
||||
{0x616FCCCD, 0, "sceKernelSetBootCallbackLevel"},
|
||||
{0xF32A2940, 0, "sceKernelModuleFromUID"},
|
||||
{0xCD0F3BAC, 0, "sceKernelCreateModule"},
|
||||
{0x6B2371C2, 0, "sceKernelDeleteModule"},
|
||||
{0x7320D964, 0, "sceKernelModuleAssign"},
|
||||
{0x44B292AB, 0, "sceKernelAllocModule"},
|
||||
{0xBD61D4D5, 0, "sceKernelFreeModule"},
|
||||
{0xAE7C6E76, 0, "sceKernelRegisterModule"},
|
||||
{0x74CF001A, 0, "sceKernelReleaseModule"},
|
||||
{0xFB8AE27D, 0, "sceKernelFindModuleByAddress"},
|
||||
{0xCCE4A157, 0, "sceKernelFindModuleByUID"},
|
||||
{0x82CE54ED, 0, "sceKernelModuleCount"},
|
||||
{0xC0584F0C, 0, "sceKernelGetModuleList"},
|
||||
{0xCF8A41B1, sceKernelFindModuleByName,"sceKernelFindModuleByName"},
|
||||
};
|
||||
|
||||
|
||||
@ -228,40 +197,6 @@ const HLEFunction sceUsb[] =
|
||||
{0x5be0e002, 0, "sceUsbWaitState"},
|
||||
{0x1c360735, 0, "sceUsbWaitCancel"},
|
||||
};
|
||||
|
||||
|
||||
const HLEFunction sceLibFont[] =
|
||||
{
|
||||
{0x67f17ed7, 0, "sceFontNewLib"},
|
||||
{0x574b6fbc, 0, "sceFontDoneLib"},
|
||||
{0x48293280, 0, "sceFontSetResolution"},
|
||||
{0x27f6e642, 0, "sceFontGetNumFontList"},
|
||||
{0xbc75d85b, 0, "sceFontGetFontList"},
|
||||
{0x099ef33c, 0, "sceFontFindOptimumFont"},
|
||||
{0x681e61a7, 0, "sceFontFindFont"},
|
||||
{0x2f67356a, 0, "sceFontCalcMemorySize"},
|
||||
{0x5333322d, 0, "sceFontGetFontInfoByIndexNumber"},
|
||||
{0xa834319d, 0, "sceFontOpen"},
|
||||
{0x57fcb733, 0, "sceFontOpenUserFile"},
|
||||
{0xbb8e7fe6, 0, "sceFontOpenUserMemory"},
|
||||
{0x3aea8cb6, 0, "sceFontClose"},
|
||||
{0x0da7535e, 0, "sceFontGetFontInfo"},
|
||||
{0xdcc80c2f, 0, "sceFontGetCharInfo"},
|
||||
{0x5c3e4a9e, 0, "sceFontGetCharImageRect"},
|
||||
{0x980f4895, 0, "sceFontGetCharGlyphImage"},
|
||||
{0xca1e6945, 0, "sceFontGetCharGlyphImage_Clip"},
|
||||
{0x74b21701, 0, "sceFontPixelToPointH"},
|
||||
{0xf8f0752e, 0, "sceFontPixelToPointV"},
|
||||
{0x472694cd, 0, "sceFontPointToPixelH"},
|
||||
{0x3c4b7e82, 0, "sceFontPointToPixelV"},
|
||||
{0xee232411, 0, "sceFontSetAltCharacterCode"},
|
||||
{0xaa3de7b5, 0, "sceFontGetShadowInfo"},
|
||||
{0x48b06520, 0, "sceFontGetShadowImageRect"},
|
||||
{0x568be516, 0, "sceFontGetShadowGlyphImage"},
|
||||
{0x5dcf6858, 0, "sceFontGetShadowGlyphImage_Clip"},
|
||||
{0x02d7f94b, 0, "sceFontFlush"},
|
||||
|
||||
};
|
||||
|
||||
const HLEFunction sceUsbstor[] =
|
||||
{
|
||||
@ -278,21 +213,11 @@ const HLEFunction sceUsbstorBoot[] =
|
||||
{0xA55C9E16, 0, "sceUsbstorBootUnregisterNotify"},
|
||||
};
|
||||
|
||||
|
||||
const HLEFunction sceOpenPSID[] =
|
||||
{
|
||||
{0xc69bebce, 0, "sceOpenPSID_c69bebce"},
|
||||
};
|
||||
|
||||
|
||||
const HLEModule moduleList[] =
|
||||
{
|
||||
{"FakeSysCalls", SZ(FakeSysCalls), FakeSysCalls},
|
||||
{"sceOpenPSID", SZ(sceOpenPSID), sceOpenPSID},
|
||||
{"UtilsForUser",SZ(UtilsForUser),UtilsForUser},
|
||||
{"KDebugForKernel",SZ(KDebugForKernel),KDebugForKernel},
|
||||
{"sceParseUri"},
|
||||
{"sceRtc",SZ(sceRtc),sceRtc},
|
||||
{"sceSAScore"},
|
||||
{"sceUsbstor",SZ(sceUsbstor),sceUsbstor},
|
||||
{"sceUsbstorBoot",SZ(sceUsbstorBoot),sceUsbstorBoot},
|
||||
@ -300,13 +225,8 @@ const HLEModule moduleList[] =
|
||||
{"SceBase64_Library"},
|
||||
{"sceCert_Loader"},
|
||||
{"SceFont_Library"},
|
||||
{"sceLibFont",SZ(sceLibFont),sceLibFont},
|
||||
{"sceNetApctl"},
|
||||
{"sceOpenPSID"},
|
||||
{"sceParseHttp"},
|
||||
{"sceSsl"},
|
||||
{"sceSIRCS_IrDA_Driver"},
|
||||
{"sceRtc"},
|
||||
{"Pspnet_Scan"},
|
||||
{"Pspnet_Show_MacAddr"},
|
||||
{"pspeDebug", SZ(pspeDebug), pspeDebug},
|
||||
@ -318,39 +238,47 @@ const HLEModule moduleList[] =
|
||||
static const int numModules = sizeof(moduleList)/sizeof(HLEModule);
|
||||
|
||||
void RegisterAllModules() {
|
||||
Register_Kernel_Library();
|
||||
Register_ThreadManForUser();
|
||||
Register_LoadExecForUser();
|
||||
Register_SysMemUserForUser();
|
||||
Register_InterruptManager();
|
||||
Register_IoFileMgrForUser();
|
||||
Register_ModuleMgrForUser();
|
||||
Register_StdioForUser();
|
||||
Register_Kernel_Library();
|
||||
Register_ThreadManForUser();
|
||||
Register_LoadExecForUser();
|
||||
Register_SysMemUserForUser();
|
||||
Register_InterruptManager();
|
||||
Register_IoFileMgrForUser();
|
||||
Register_ModuleMgrForUser();
|
||||
Register_StdioForUser();
|
||||
|
||||
Register_sceHprm();
|
||||
Register_sceCtrl();
|
||||
Register_sceDisplay();
|
||||
Register_sceAudio();
|
||||
Register_sceSasCore();
|
||||
Register_sceNet();
|
||||
Register_sceWlanDrv();
|
||||
Register_sceMpeg();
|
||||
Register_sceMp3();
|
||||
Register_sceHttp();
|
||||
Register_scePower();
|
||||
Register_sceHprm();
|
||||
Register_sceCtrl();
|
||||
Register_sceDisplay();
|
||||
Register_sceAudio();
|
||||
Register_sceSasCore();
|
||||
Register_sceFont();
|
||||
Register_sceNet();
|
||||
Register_sceRtc();
|
||||
Register_sceWlanDrv();
|
||||
Register_sceMpeg();
|
||||
Register_sceMp3();
|
||||
Register_sceHttp();
|
||||
Register_scePower();
|
||||
Register_sceImpose();
|
||||
Register_sceSuspendForUser();
|
||||
Register_sceGe_user();
|
||||
Register_sceUmdUser();
|
||||
Register_sceDmac();
|
||||
Register_sceUtility();
|
||||
Register_sceAtrac3plus();
|
||||
Register_scePsmf();
|
||||
Register_scePsmfPlayer();
|
||||
Register_sceSuspendForUser();
|
||||
Register_sceGe_user();
|
||||
Register_sceUmdUser();
|
||||
Register_sceDmac();
|
||||
Register_sceUtility();
|
||||
Register_sceAtrac3plus();
|
||||
Register_scePsmf();
|
||||
Register_scePsmfPlayer();
|
||||
Register_sceOpenPSID();
|
||||
Register_sceParseUri();
|
||||
Register_sceSsl();
|
||||
Register_sceParseHttp();
|
||||
Register_scesupPreAcc();
|
||||
Register_sceVaudio();
|
||||
|
||||
for (int i = 0; i < numModules; i++)
|
||||
{
|
||||
RegisterModule(moduleList[i].name, moduleList[i].numFunctions, moduleList[i].funcTable);
|
||||
}
|
||||
for (int i = 0; i < numModules; i++)
|
||||
{
|
||||
RegisterModule(moduleList[i].name, moduleList[i].numFunctions, moduleList[i].funcTable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,9 @@
|
||||
#include "../CoreTiming.h"
|
||||
#include "../MemMap.h"
|
||||
#include "../Host.h"
|
||||
#include "../Config.h"
|
||||
#include "FixedSizeQueue.h"
|
||||
#include "Common/Thread.h"
|
||||
|
||||
// While buffers == MAX_BUFFERS, block on blocking write
|
||||
// non-blocking writes will return busy, I guess
|
||||
@ -34,46 +37,51 @@
|
||||
std::recursive_mutex section;
|
||||
|
||||
int eventAudioUpdate = -1;
|
||||
int eventHostAudioUpdate = -1;
|
||||
int mixFrequency = 48000;
|
||||
const int hwSampleRate = 48000;
|
||||
const int hwBlockSize = 480;
|
||||
const int hostAttemptBlockSize = 64;
|
||||
const int audioIntervalUs = (int)(1000000ULL * hwBlockSize / hwSampleRate);
|
||||
const int audioHostIntervalUs = (int)(1000000ULL * hostAttemptBlockSize / hwSampleRate);
|
||||
|
||||
// High and low watermarks, basically.
|
||||
const int chanQueueMaxSizeFactor = 12;
|
||||
const int chanQueueMinSizeFactor = 1;
|
||||
|
||||
FixedSizeQueue<s16, hwBlockSize * 8> outAudioQueue;
|
||||
|
||||
const int audioIntervalMs = 20;
|
||||
|
||||
void hleAudioUpdate(u64 userdata, int cyclesLate)
|
||||
{
|
||||
host->UpdateSound();
|
||||
__AudioUpdate();
|
||||
|
||||
CoreTiming::ScheduleEvent(msToCycles(audioIntervalMs), eventAudioUpdate, 0);
|
||||
CoreTiming::ScheduleEvent(usToCycles(audioIntervalUs), eventAudioUpdate, 0);
|
||||
}
|
||||
|
||||
void hleHostAudioUpdate(u64 userdata, int cyclesLate)
|
||||
{
|
||||
host->UpdateSound();
|
||||
CoreTiming::ScheduleEvent(usToCycles(audioHostIntervalUs), eventHostAudioUpdate, 0);
|
||||
}
|
||||
|
||||
void __AudioInit()
|
||||
{
|
||||
eventAudioUpdate = CoreTiming::RegisterEvent("AudioUpdate", &hleAudioUpdate);
|
||||
mixFrequency = 48000;
|
||||
|
||||
CoreTiming::ScheduleEvent(msToCycles(1), eventAudioUpdate, 0);
|
||||
eventAudioUpdate = CoreTiming::RegisterEvent("AudioUpdate", &hleAudioUpdate);
|
||||
eventHostAudioUpdate = CoreTiming::RegisterEvent("AudioUpdateHost", &hleHostAudioUpdate);
|
||||
|
||||
CoreTiming::ScheduleEvent(usToCycles(audioIntervalUs), eventAudioUpdate, 0);
|
||||
CoreTiming::ScheduleEvent(usToCycles(audioHostIntervalUs), eventHostAudioUpdate, 0);
|
||||
for (int i = 0; i < 8; i++)
|
||||
chans[i].clear();
|
||||
}
|
||||
|
||||
void __AudioShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void __AudioUpdate()
|
||||
{
|
||||
// DEBUG_LOG(HLE, "Updating audio");
|
||||
section.lock();
|
||||
for (int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
if (chans[i].triggered)
|
||||
{
|
||||
chans[i].triggered = false;
|
||||
|
||||
// Instead of looping through all threads, which this does, we should keep track of which threads are waiting and just
|
||||
// resume them.
|
||||
__KernelTriggerWait(WAITTYPE_AUDIOCHANNEL, (SceUID)i, true);
|
||||
}
|
||||
}
|
||||
section.unlock();
|
||||
for (int i = 0; i < 8; i++)
|
||||
chans[i].clear();
|
||||
}
|
||||
|
||||
u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking)
|
||||
@ -81,15 +89,18 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking)
|
||||
section.lock();
|
||||
if (chan.sampleAddress == 0)
|
||||
return SCE_ERROR_AUDIO_NOT_OUTPUT;
|
||||
if (chan.sampleQueue.size() > chan.sampleCount*2) {
|
||||
if (chan.sampleQueue.size() > chan.sampleCount*2*chanQueueMaxSizeFactor) {
|
||||
// Block!
|
||||
if (blocking) {
|
||||
chan.waitingThread = __KernelGetCurThread();
|
||||
// WARNING: This changes currentThread so must grab waitingThread before (line above).
|
||||
__KernelWaitCurThread(WAITTYPE_AUDIOCHANNEL, (SceUID)chanNum, 0, 0, false);
|
||||
section.unlock();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
chan.waitingThread = 0;
|
||||
return SCE_ERROR_AUDIO_CHANNEL_BUSY;
|
||||
}
|
||||
}
|
||||
@ -114,49 +125,110 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int __AudioMix(short *outstereo, int numSamples)
|
||||
// Mix samples from the various audio channels into a single sample queue.
|
||||
// This single sample queue is where __AudioMix should read from. If the sample queue is full, we should
|
||||
// just sleep the main emulator thread a little.
|
||||
void __AudioUpdate()
|
||||
{
|
||||
memset(outstereo, 0, numSamples*sizeof(short)*2);
|
||||
// Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied
|
||||
// to the CPU. Much better to throttle the frame rate on frame display and just throw away audio
|
||||
// if the buffer somehow gets full.
|
||||
|
||||
// Disable Audio for now.
|
||||
// return numSamples;
|
||||
|
||||
section.lock();
|
||||
|
||||
int numActiveChans = 0;
|
||||
|
||||
for (int j = 0; j < MAX_CHANNEL; j++)
|
||||
{
|
||||
numActiveChans += chans[j].running ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!numActiveChans)
|
||||
{
|
||||
section.unlock();
|
||||
return numSamples;
|
||||
}
|
||||
s32 mixBuffer[hwBlockSize * 2];
|
||||
memset(mixBuffer, 0, sizeof(mixBuffer));
|
||||
|
||||
for (int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
for (int s = 0; s < numSamples; s++)
|
||||
if (!chans[i].reserved)
|
||||
continue;
|
||||
if (!chans[i].sampleQueue.size()) {
|
||||
// DEBUG_LOG(HLE, "No queued samples, skipping channel %i", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int s = 0; s < hwBlockSize; s++)
|
||||
{
|
||||
if (chans[i].sampleQueue.size() >= 2)
|
||||
{
|
||||
s16 sample1 = chans[i].sampleQueue.front();
|
||||
s16 sampleL = chans[i].sampleQueue.front();
|
||||
s16 sampleR = chans[i].sampleQueue.front();
|
||||
chans[i].sampleQueue.pop();
|
||||
s16 sample2 = chans[i].sampleQueue.front();
|
||||
chans[i].sampleQueue.pop();
|
||||
|
||||
outstereo[s*2] += sample1 / 4;//(sample * chans[i].vol1) >> 8;
|
||||
outstereo[s*2+1] += sample2 / 4;//.(sample * chans[i].vol2) >> 8;
|
||||
mixBuffer[s * 2] += sampleL;
|
||||
mixBuffer[s * 2 + 1] += sampleR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "channel %i buffer underrun at %i of %i", i, s, hwBlockSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (chans[i].sampleQueue.size() < chans[i].sampleCount)
|
||||
|
||||
if (chans[i].sampleQueue.size() < chans[i].sampleCount * 2 * chanQueueMinSizeFactor)
|
||||
{
|
||||
chans[i].triggered = true;
|
||||
// Ask the thread to send more samples until next time, queue is being drained.
|
||||
if (chans[i].waitingThread) {
|
||||
SceUID waitingThread = chans[i].waitingThread;
|
||||
chans[i].waitingThread = 0;
|
||||
// DEBUG_LOG(HLE, "Woke thread %i for some buffer filling", waitingThread);
|
||||
__KernelResumeThreadFromWait(waitingThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.lock();
|
||||
|
||||
if (g_Config.bEnableSound && outAudioQueue.room() >= hwBlockSize * 2) {
|
||||
// Push the mixed samples onto the output audio queue.
|
||||
for (int i = 0; i < hwBlockSize; i++) {
|
||||
s32 sampleL = mixBuffer[i * 2] >> 2; // TODO - what factor?
|
||||
s32 sampleR = mixBuffer[i * 2 + 1] >> 2;
|
||||
|
||||
outAudioQueue.push((s16)sampleL);
|
||||
outAudioQueue.push((s16)sampleR);
|
||||
}
|
||||
}
|
||||
|
||||
section.unlock();
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
void __AudioSetOutputFrequency(int freq)
|
||||
{
|
||||
WARN_LOG(HLE, "Switching audio frequency to %i", freq);
|
||||
mixFrequency = freq;
|
||||
}
|
||||
|
||||
// numFrames is number of stereo frames.
|
||||
int __AudioMix(short *outstereo, int numFrames)
|
||||
{
|
||||
// TODO: if mixFrequency != the actual output frequency, resample!
|
||||
|
||||
section.lock();
|
||||
int underrun = -1;
|
||||
s16 sampleL = 0;
|
||||
s16 sampleR = 0;
|
||||
bool anythingToPlay = false;
|
||||
for (int i = 0; i < numFrames; i++) {
|
||||
if (outAudioQueue.size() >= 2)
|
||||
{
|
||||
sampleL = outAudioQueue.front();
|
||||
outAudioQueue.pop();
|
||||
sampleR = outAudioQueue.front();
|
||||
outAudioQueue.pop();
|
||||
outstereo[i * 2] = sampleL;
|
||||
outstereo[i * 2 + 1] = sampleR;
|
||||
anythingToPlay = true;
|
||||
} else {
|
||||
if (underrun == -1) underrun = i;
|
||||
outstereo[i * 2] = sampleL; // repeat last sample, can reduce clicking
|
||||
outstereo[i * 2 + 1] = sampleR; // repeat last sample, can reduce clicking
|
||||
}
|
||||
}
|
||||
if (anythingToPlay && underrun >= 0) {
|
||||
DEBUG_LOG(HLE, "audio out buffer UNDERRUN at %i of %i", underrun, numFrames);
|
||||
} else {
|
||||
// DEBUG_LOG(HLE, "No underrun, mixed %i samples fine", numFrames);
|
||||
}
|
||||
section.unlock();
|
||||
return numFrames;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
void __AudioInit();
|
||||
void __AudioUpdate();
|
||||
void __AudioShutdown();
|
||||
void __AudioSetOutputFrequency(int freq);
|
||||
|
||||
// May return SCE_ERROR_AUDIO_CHANNEL_BUSY if buffer too large
|
||||
u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking);
|
||||
|
@ -28,19 +28,14 @@
|
||||
#define ATRAC_ERROR_API_FAIL 0x80630002
|
||||
#define ATRAC_ERROR_ALL_DATA_DECODED 0x80630024
|
||||
|
||||
void sceAtracAddStreamData()
|
||||
int sceAtracAddStreamData(int atracID, u32 bytesToAdd)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracAddStreamData(%i, %i)", PARAM(0), PARAM(1));
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracAddStreamData(%i, %i)", atracID, bytesToAdd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracDecodeData()
|
||||
int sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr)
|
||||
{
|
||||
u32 atracID = PARAM(0);
|
||||
u32 outAddr = PARAM(1);
|
||||
u32 numSamplesAddr = PARAM(2);
|
||||
u32 finishFlagAddr = PARAM(3);
|
||||
u32 remainAddr = PARAM(4);
|
||||
ERROR_LOG(HLE, "FAKE sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr);
|
||||
|
||||
Memory::Write_U16(0, outAddr); // Write a single 16-bit stereo
|
||||
@ -50,7 +45,7 @@ void sceAtracDecodeData()
|
||||
Memory::Write_U32(1, finishFlagAddr); // Lie that decoding is finished
|
||||
Memory::Write_U32(0, remainAddr); // Lie that decoding is finished
|
||||
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracEndEntry()
|
||||
@ -71,10 +66,10 @@ void sceAtracGetBufferInfoForReseting()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceAtracGetBitrate()
|
||||
int sceAtracGetBitrate(int atracID, u32 outBitrateAddr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracGetBitrate");
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracGetChannel()
|
||||
@ -101,64 +96,51 @@ void sceAtracGetMaxSample()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceAtracGetNextDecodePosition()
|
||||
int sceAtracGetNextDecodePosition(int atracID, u32 outposAddr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracGetNextDecodePosition(%i, %08x)", PARAM(0), PARAM(1));
|
||||
u32 *outPos = (u32*)Memory::GetPointer(PARAM(1));
|
||||
*outPos = 1;
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr);
|
||||
Memory::Write_U32(1, outposAddr); // outpos
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracGetNextSample()
|
||||
int sceAtracGetNextSample(int atracID, u32 outNAddr)
|
||||
{
|
||||
u32 atracID = PARAM(0);
|
||||
u32 outN = PARAM(1);
|
||||
ERROR_LOG(HLE, "FAKE sceAtracGetNextSample(%i, %08x)", atracID, outN);
|
||||
Memory::Write_U32(0, outN);
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "FAKE sceAtracGetNextSample(%i, %08x)", atracID, outNAddr);
|
||||
Memory::Write_U32(0, outNAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracGetRemainFrame()
|
||||
int sceAtracGetRemainFrame(int atracID, u32 outposAddr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAtracGetRemainFrame(%i, %08x)",PARAM(0),PARAM(1));
|
||||
u32 *outPos = (u32*)Memory::GetPointer(PARAM(1));
|
||||
*outPos = 12;
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "sceAtracGetRemainFrame(%i, %08x)", atracID, outposAddr);
|
||||
Memory::Write_U32(12, outposAddr); // outpos
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracGetSecondBufferInfo()
|
||||
int sceAtracGetSecondBufferInfo(int atracID, u32 outposAddr, u32 outBytesAddr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)",PARAM(0),PARAM(1),PARAM(2));
|
||||
u32 *outPos = (u32*)Memory::GetPointer(PARAM(1));
|
||||
u32 *outBytes = (u32*)Memory::GetPointer(PARAM(2));
|
||||
*outPos = 0;
|
||||
*outBytes = 0x10000;
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)", atracID, outposAddr, outBytesAddr);
|
||||
Memory::Write_U32(0, outposAddr); // outpos
|
||||
Memory::Write_U32(0x10000, outBytesAddr); // outBytes
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracGetSoundSample()
|
||||
int sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSampleAddr, u32 outLoopEndSampleAddr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracGetSoundSample(%i, %08x, %08x, %08x)",PARAM(0),PARAM(1),PARAM(2),PARAM(3));
|
||||
u32 *outEndSample = (u32*)Memory::GetPointer(PARAM(1));
|
||||
u32 *outLoopStartSample = (u32*)Memory::GetPointer(PARAM(2));
|
||||
u32 *outLoopEndSample = (u32*)Memory::GetPointer(PARAM(2));
|
||||
*outEndSample = 0x10000;
|
||||
*outLoopStartSample = -1;
|
||||
*outLoopEndSample = -1;
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr);
|
||||
Memory::Write_U32(0x10000, outEndSampleAddr); // outEndSample
|
||||
Memory::Write_U32(-1, outLoopStartSampleAddr); // outLoopStartSample
|
||||
Memory::Write_U32(-1, outLoopEndSampleAddr); // outLoopEndSample
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracGetStreamDataInfo()
|
||||
int sceAtracGetStreamDataInfo(int atracID, u32 writePointerAddr, u32 availableBytesAddr, u32 readOffsetAddr)
|
||||
{
|
||||
u32 atracID = PARAM(0);
|
||||
u32 writePointerAddr = PARAM(1);
|
||||
u32 availableBytesAddr = PARAM(2);
|
||||
u32 readOffsetAddr = PARAM(3);
|
||||
ERROR_LOG(HLE, "FAKE sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writePointerAddr, availableBytesAddr, readOffsetAddr);
|
||||
Memory::Write_U32(0, readOffsetAddr);
|
||||
Memory::Write_U32(0, availableBytesAddr);
|
||||
Memory::Write_U32(0, writePointerAddr);
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAtracReleaseAtracID()
|
||||
@ -215,37 +197,42 @@ void sceAtracSetLoopNum()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
int sceAtracReinit()
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceAtracReinit(..)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const HLEFunction sceAtrac3plus[] =
|
||||
{
|
||||
{0x7db31251,sceAtracAddStreamData,"sceAtracAddStreamData"},
|
||||
{0x6a8c3cd5,sceAtracDecodeData,"sceAtracDecodeData"},
|
||||
{0x7db31251,WrapI_IU<sceAtracAddStreamData>,"sceAtracAddStreamData"},
|
||||
{0x6a8c3cd5,WrapI_IUUUU<sceAtracDecodeData>,"sceAtracDecodeData"},
|
||||
{0xd5c28cc0,sceAtracEndEntry,"sceAtracEndEntry"},
|
||||
{0x780f88d1,sceAtracGetAtracID,"sceAtracGetAtracID"},
|
||||
{0xca3ca3d2,sceAtracGetBufferInfoForReseting,"sceAtracGetBufferInfoForReseting"},
|
||||
{0xa554a158,sceAtracGetBitrate,"sceAtracGetBitrate"},
|
||||
{0xa554a158,WrapI_IU<sceAtracGetBitrate>,"sceAtracGetBitrate"},
|
||||
{0x31668baa,sceAtracGetChannel,"sceAtracGetChannel"},
|
||||
{0xfaa4f89b,sceAtracGetLoopStatus,"sceAtracGetLoopStatus"},
|
||||
{0xe88f759b,sceAtracGetInternalErrorInfo,"sceAtracGetInternalErrorInfo"},
|
||||
{0xd6a5f2f7,sceAtracGetMaxSample,"sceAtracGetMaxSample"},
|
||||
{0xe23e3a35,sceAtracGetNextDecodePosition,"sceAtracGetNextDecodePosition"},
|
||||
{0x36faabfb,sceAtracGetNextSample,"sceAtracGetNextSample"},
|
||||
{0x9ae849a7,sceAtracGetRemainFrame,"sceAtracGetRemainFrame"},
|
||||
{0x83e85ea0,sceAtracGetSecondBufferInfo,"sceAtracGetSecondBufferInfo"},
|
||||
{0xa2bba8be,sceAtracGetSoundSample,"sceAtracGetSoundSample"},
|
||||
{0x5d268707,sceAtracGetStreamDataInfo,"sceAtracGetStreamDataInfo"},
|
||||
{0xe23e3a35,WrapI_IU<sceAtracGetNextDecodePosition>,"sceAtracGetNextDecodePosition"},
|
||||
{0x36faabfb,WrapI_IU<sceAtracGetNextSample>,"sceAtracGetNextSample"},
|
||||
{0x9ae849a7,WrapI_IU<sceAtracGetRemainFrame>,"sceAtracGetRemainFrame"},
|
||||
{0x83e85ea0,WrapI_IUU<sceAtracGetSecondBufferInfo>,"sceAtracGetSecondBufferInfo"},
|
||||
{0xa2bba8be,WrapI_IUUU<sceAtracGetSoundSample>,"sceAtracGetSoundSample"},
|
||||
{0x5d268707,WrapI_IUUU<sceAtracGetStreamDataInfo>,"sceAtracGetStreamDataInfo"},
|
||||
{0x61eb33f5,sceAtracReleaseAtracID,"sceAtracReleaseAtracID"},
|
||||
{0x644e5607,sceAtracResetPlayPosition,"sceAtracResetPlayPosition"},
|
||||
{0x3f6e26b5,sceAtracSetHalfwayBuffer,"sceAtracSetHalfwayBuffer"},
|
||||
{0x83bf7afd,sceAtracSetSecondBuffer,"sceAtracSetSecondBuffer"},
|
||||
{0x0E2A73AB,sceAtracSetData,"sceAtracSetData"}, //?
|
||||
{0x7a20e7af,sceAtracSetDataAndGetID,"sceAtracSetDataAndGetID"},
|
||||
{0x0eb8dc38,sceAtracSetHalfwayBufferAndGetID,"sceAtracSetHalfwayBufferAndGetID"},
|
||||
{0xd1f59fdb,sceAtracStartEntry,"sceAtracStartEntry"},
|
||||
{0x868120b5,sceAtracSetLoopNum,"sceAtracSetLoopNum"},
|
||||
{0x132f1eca,0,"sceAtracReinit"},
|
||||
{0x132f1eca,WrapI_V<sceAtracReinit>,"sceAtracReinit"},
|
||||
{0xeca32a99,0,"sceAtracIsSecondBufferNeeded"},
|
||||
{0x0fae370e,0,"sceAtracSetHalfwayBufferAndGetID"},
|
||||
{0x0fae370e,sceAtracSetHalfwayBufferAndGetID,"sceAtracSetHalfwayBufferAndGetID"},
|
||||
{0x2DD3E298,0,"sceAtrac3plus_2DD3E298"},
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
@ -35,99 +35,121 @@ AudioChannel chans[8];
|
||||
|
||||
// Not sure about the range of volume, I often see 0x800 so that might be either
|
||||
// max or 50%?
|
||||
void sceAudioOutputPannedBlocking(u32 chan, u32 volume1, u32 volume2, u32 samplePtr)
|
||||
{
|
||||
if (samplePtr == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAudioOutputPannedBlocking - Sample pointer null");
|
||||
RETURN(0);
|
||||
}
|
||||
else if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - BAD CHANNEL: %08x", chan);
|
||||
RETURN(SCE_ERROR_AUDIO_INVALID_CHANNEL);
|
||||
|
||||
u32 sceAudioOutputBlocking(u32 chan, u32 vol, u32 samplePtr) {
|
||||
if (samplePtr == 0) {
|
||||
ERROR_LOG(HLE, "sceAudioOutputBlocking - Sample pointer null");
|
||||
return 0;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - CHANNEL NOT RESERVED");
|
||||
RETURN(SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceAudioOutputPannedBlocking(%d,%d,%d, %08x )", chan, volume1, volume2, samplePtr);
|
||||
chans[chan].running = true;
|
||||
chans[chan].leftVolume = volume1;
|
||||
chans[chan].rightVolume = volume2;
|
||||
if (chan < 0 || chan >= MAX_CHANNEL) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputBlocking() - BAD CHANNEL");
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
} else if (!chans[chan].reserved) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputBlocking() - channel not reserved");
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
} else {
|
||||
DEBUG_LOG(HLE, "sceAudioOutputBlocking(%d, %d, %08x )",chan,vol,samplePtr);
|
||||
chans[chan].leftVolume = vol;
|
||||
chans[chan].rightVolume = vol;
|
||||
chans[chan].sampleAddress = samplePtr;
|
||||
RETURN(0);
|
||||
__AudioEnqueue(chans[chan], chan, true);
|
||||
return __AudioEnqueue(chans[chan], chan, true);
|
||||
}
|
||||
}
|
||||
|
||||
void sceAudioGetChannelRestLen()
|
||||
u32 sceAudioOutputPannedBlocking(u32 chan, u32 volume1, u32 volume2, u32 samplePtr) {
|
||||
if (samplePtr == 0) {
|
||||
ERROR_LOG(HLE, "sceAudioOutputPannedBlocking - Sample pointer null");
|
||||
return 0;
|
||||
} else if (chan < 0 || chan >= MAX_CHANNEL) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - BAD CHANNEL");
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
} else if (!chans[chan].reserved) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - CHANNEL NOT RESERVED");
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
} else {
|
||||
DEBUG_LOG(HLE, "sceAudioOutputPannedBlocking(%d,%d,%d, %08x )", chan, volume1, volume2, samplePtr);
|
||||
chans[chan].leftVolume = volume1;
|
||||
chans[chan].rightVolume = volume2;
|
||||
chans[chan].sampleAddress = samplePtr;
|
||||
return __AudioEnqueue(chans[chan], chan, true);
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceAudioOutput(u32 chan, u32 vol, u32 samplePtr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceAudioGetChannelRestLen(%i)", PARAM(0));
|
||||
// Remaining samples in that channel buffer.
|
||||
RETURN(0);
|
||||
if (chan < 0 || chan >= MAX_CHANNEL) {
|
||||
ERROR_LOG(HLE,"sceAudioOutput() - BAD CHANNEL");
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutput(%d, %d, %08x) - channel not reserved", chan, vol, samplePtr);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
chans[chan].leftVolume = vol;
|
||||
chans[chan].rightVolume = vol;
|
||||
chans[chan].sampleAddress = samplePtr;
|
||||
u32 retval = __AudioEnqueue(chans[chan], chan, false);
|
||||
DEBUG_LOG(HLE, "%08x=sceAudioOutputPanned(%d, %d, %08x)", retval, chan, vol, samplePtr);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceAudioOutputPanned(u32 chan, u32 leftVol, u32 rightVol, u32 samplePtr)
|
||||
{
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputPanned() - BAD CHANNEL");
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputPanned(%d, %d, %d, %08x) - channel not reserved", chan,leftVol,rightVol,samplePtr);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
chans[chan].running = true;
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputPanned() - BAD CHANNEL");
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputPanned(%d, %d, %d, %08x) - channel not reserved", chan, leftVol, rightVol, samplePtr);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
chans[chan].leftVolume = leftVol;
|
||||
chans[chan].rightVolume = rightVol;
|
||||
chans[chan].sampleAddress = samplePtr;
|
||||
u32 retval = __AudioEnqueue(chans[chan], chan, false);
|
||||
DEBUG_LOG(HLE,"%08x=sceAudioOutputPanned(%d, %d, %d, %08x)",retval,chan,leftVol,rightVol,samplePtr);
|
||||
return retval;
|
||||
u32 retval = __AudioEnqueue(chans[chan], chan, false);
|
||||
DEBUG_LOG(HLE, "%08x=sceAudioOutputPanned(%d, %d, %d, %08x)", retval, chan, leftVol, rightVol, samplePtr);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
void sceAudioOutputBlocking(u32 chan, u32 vol, u32 samplePtr)
|
||||
int sceAudioGetChannelRestLen(u32 chan)
|
||||
{
|
||||
if (samplePtr == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAudioOutputBlocking - Sample pointer null");
|
||||
RETURN(0);
|
||||
}
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputBlocking() - BAD CHANNEL");
|
||||
RETURN(SCE_ERROR_AUDIO_INVALID_CHANNEL);
|
||||
ERROR_LOG(HLE, "sceAudioGetChannelRestLen(%i) - BAD CHANNEL", chan);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutputBlocking() - channel not reserved");
|
||||
RETURN(SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED);
|
||||
}
|
||||
else
|
||||
|
||||
int sz = (int)chans[chan].sampleQueue.size() / 2;
|
||||
DEBUG_LOG(HLE,"UNTESTED %i = sceAudioGetChannelRestLen(%i)", sz, chan);
|
||||
return sz;
|
||||
}
|
||||
|
||||
int sceAudioGetChannelRestLength(u32 chan)
|
||||
{
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceAudioOutputPanned(%d, %d, %08x )",chan,vol,samplePtr);
|
||||
chans[chan].running = true;
|
||||
chans[chan].leftVolume = vol;
|
||||
chans[chan].rightVolume = vol;
|
||||
chans[chan].sampleAddress = samplePtr;
|
||||
RETURN(0);
|
||||
__AudioEnqueue(chans[chan], chan, true);
|
||||
ERROR_LOG(HLE, "sceAudioGetChannelRestLength(%i) - BAD CHANNEL", chan);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
int sz = (int)chans[chan].sampleQueue.size() / 2;
|
||||
DEBUG_LOG(HLE,"UNTESTED %i = sceAudioGetChannelRestLen(%i)", sz, chan);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static int GetFreeChannel()
|
||||
{
|
||||
for (int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
{
|
||||
if (!chans[i].reserved)
|
||||
{
|
||||
return i;
|
||||
@ -145,20 +167,26 @@ u32 sceAudioChReserve(u32 channel, u32 sampleCount, u32 format) //.Allocate soun
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChReserve failed");
|
||||
return SCE_ERROR_AUDIO_NO_CHANNELS_AVAILABLE;
|
||||
return SCE_ERROR_AUDIO_NO_CHANNELS_AVAILABLE;
|
||||
}
|
||||
|
||||
if (format != PSP_AUDIO_FORMAT_MONO && format != PSP_AUDIO_FORMAT_STEREO)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAudioChReserve(channel = %d, sampleCount = %d, format = %d): invalid format", channel, sampleCount, format);
|
||||
return SCE_ERROR_AUDIO_INVALID_FORMAT;
|
||||
}
|
||||
if (channel < 0 || channel >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE ,"sceAudioChReserve(channel = %d, sampleCount = %d, format = %d) - BAD CHANNEL", channel, sampleCount, format);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (format != PSP_AUDIO_FORMAT_MONO && format != PSP_AUDIO_FORMAT_STEREO)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAudioChReserve(channel = %d, sampleCount = %d, format = %d): invalid format", channel, sampleCount, format);
|
||||
return SCE_ERROR_AUDIO_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
if (chans[channel].reserved)
|
||||
{
|
||||
{
|
||||
WARN_LOG(HLE, "WARNING: Reserving already reserved channel. Error?");
|
||||
}
|
||||
DEBUG_LOG(HLE,"%i = sceAudioChReserve(%i, %i, %i)", channel, PARAM(0), sampleCount, format);
|
||||
DEBUG_LOG(HLE, "%i = sceAudioChReserve(%i, %i, %i)", channel, sampleCount, format);
|
||||
|
||||
chans[channel].sampleCount = sampleCount;
|
||||
chans[channel].reserved = true;
|
||||
@ -167,169 +195,197 @@ u32 sceAudioChReserve(u32 channel, u32 sampleCount, u32 format) //.Allocate soun
|
||||
|
||||
u32 sceAudioChRelease(u32 chan)
|
||||
{
|
||||
if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChRelease(%i): channel not reserved", chan);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
chans[chan].triggered = false;
|
||||
chans[chan].running = false;
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceAudioChRelease(%i) - BAD CHANNEL", chan);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
|
||||
if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChRelease(%i): channel not reserved", chan);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
chans[chan].reserved = false;
|
||||
|
||||
DEBUG_LOG(HLE,"sceAudioChRelease(%i)", chan);
|
||||
DEBUG_LOG(HLE, "sceAudioChRelease(%i)", chan);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 sceAudioSetChannelDataLen(u32 chan, u32 len)
|
||||
{
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - BAD CHANNEL", chan, len);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - channel not reserved", chan, len);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i)", chan, len);
|
||||
chans[chan].sampleCount = len;
|
||||
return 0;
|
||||
}
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - BAD CHANNEL", chan, len);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - channel not reserved", chan, len);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceAudioSetChannelDataLen(%i, %i)", chan, len);
|
||||
//chans[chan].dataLen = len;
|
||||
chans[chan].sampleCount = len;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceAudioChangeChannelConfig(u32 chan, u32 format)
|
||||
{
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - invalid channel number", chan, format);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - channel not reserved", chan, format);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i)", chan, format);
|
||||
chans[chan].format = format;
|
||||
return 0;
|
||||
}
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - invalid channel number", chan, format);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - channel not reserved", chan, format);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceAudioChangeChannelConfig(%i, %i)", chan, format);
|
||||
chans[chan].format = format;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceAudioChangeChannelVolume(u32 chan, u32 lvolume, u32 rvolume)
|
||||
{
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - invalid channel number", chan, lvolume, rvolume);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - channel not reserved", chan, lvolume, rvolume);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i)", chan, lvolume, rvolume);
|
||||
chans[chan].leftVolume = lvolume;
|
||||
chans[chan].rightVolume = rvolume;
|
||||
return 0;
|
||||
}
|
||||
if (chan < 0 || chan >= MAX_CHANNEL)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - invalid channel number", chan, lvolume, rvolume);
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
}
|
||||
else if (!chans[chan].reserved)
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - channel not reserved", chan, lvolume, rvolume);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceAudioChangeChannelVolume(%i, %i, %i)", chan, lvolume, rvolume);
|
||||
chans[chan].leftVolume = lvolume;
|
||||
chans[chan].rightVolume = rvolume;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sceAudioInit()
|
||||
u32 sceAudioInit()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceAudioInit");
|
||||
RETURN(0);
|
||||
DEBUG_LOG(HLE,"sceAudioInit()");
|
||||
// Don't need to do anything
|
||||
return 0;
|
||||
}
|
||||
u32 sceAudioEnd()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceAudioEnd()");
|
||||
// Don't need to do anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAudioOutput2Reserve()
|
||||
u32 sceAudioOutput2Reserve(u32 sampleCount)
|
||||
{
|
||||
int sampleCount = PARAM(0);
|
||||
ERROR_LOG(HLE,"sceAudioOutput2Reserve(%i)", sampleCount);
|
||||
ERROR_LOG(HLE,"sceAudioOutput2Reserve(%i)", sampleCount);
|
||||
chans[0].sampleCount = sampleCount;
|
||||
chans[0].reserved = true;
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAudioOutput2OutputBlocking()
|
||||
u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr)
|
||||
{
|
||||
int vol = PARAM(0);
|
||||
u32 dataPtr = PARAM(1);
|
||||
|
||||
WARN_LOG(HLE,"FAKE sceAudioOutput2OutputBlocking(%i, %08x)", vol, dataPtr);
|
||||
chans[0].running = true;
|
||||
DEBUG_LOG(HLE,"FAKE sceAudioOutput2OutputBlocking(%i, %08x)", vol, dataPtr);
|
||||
chans[0].leftVolume = vol;
|
||||
chans[0].rightVolume = vol;
|
||||
chans[0].sampleAddress = dataPtr;
|
||||
RETURN(chans[0].sampleCount);
|
||||
__AudioEnqueue(chans[0], 0, true);
|
||||
return __AudioEnqueue(chans[0], 0, true);
|
||||
}
|
||||
|
||||
void sceAudioOutput2ChangeLength()
|
||||
u32 sceAudioOutput2ChangeLength(u32 sampleCount)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceAudioOutput2ChangeLength");
|
||||
RETURN(0);
|
||||
WARN_LOG(HLE,"sceAudioOutput2ChangeLength(%i)", sampleCount);
|
||||
chans[0].sampleCount = sampleCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceAudioOutput2GetRestSample()
|
||||
u32 sceAudioOutput2GetRestSample()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceAudioOutput2GetRestSample");
|
||||
RETURN(0);
|
||||
WARN_LOG(HLE,"UNTESTED sceAudioOutput2GetRestSample()");
|
||||
return chans[0].sampleQueue.size() * 2;
|
||||
}
|
||||
|
||||
void sceAudioOutput2Release()
|
||||
u32 sceAudioOutput2Release()
|
||||
{
|
||||
ERROR_LOG(HLE,"sceAudioOutput2Release()");
|
||||
WARN_LOG(HLE,"sceAudioOutput2Release()");
|
||||
chans[0].reserved = false;
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceAudioSetFrequency(u32 freq) {
|
||||
if (freq == 44100 || freq == 48000) {
|
||||
INFO_LOG(HLE, "sceAudioSetFrequency(%i)", freq);
|
||||
__AudioSetOutputFrequency(freq);
|
||||
return 0;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "sceAudioSetFrequency(%i) - invalid frequency (must be 44.1 or 48 khz)", freq);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const HLEFunction sceAudio[] =
|
||||
{
|
||||
{0x01562ba3, sceAudioOutput2Reserve, "sceAudioOutput2Reserve"}, // N+, Super Stardust Portable uses these
|
||||
{0x2d53f36e, sceAudioOutput2OutputBlocking, "sceAudioOutput2OutputBlocking"},
|
||||
{0x63f2889c, sceAudioOutput2ChangeLength, "sceAudioOutput2ChangeLength"},
|
||||
{0x647cef33, sceAudioOutput2GetRestSample, "sceAudioOutput2GetRestSample"},
|
||||
{0x43196845, sceAudioOutput2Release, "sceAudioOutput2Release"},
|
||||
// Newer simplified single channel audio output. Presumably for games that use Atrac3
|
||||
// directly from Sas instead of playing it on a separate audio channel.
|
||||
{0x01562ba3, WrapU_U<sceAudioOutput2Reserve>, "sceAudioOutput2Reserve"},
|
||||
{0x2d53f36e, WrapU_UU<sceAudioOutput2OutputBlocking>, "sceAudioOutput2OutputBlocking"},
|
||||
{0x63f2889c, WrapU_U<sceAudioOutput2ChangeLength>, "sceAudioOutput2ChangeLength"},
|
||||
{0x647cef33, WrapU_V<sceAudioOutput2GetRestSample>, "sceAudioOutput2GetRestSample"},
|
||||
{0x43196845, WrapU_V<sceAudioOutput2Release>, "sceAudioOutput2Release"},
|
||||
|
||||
{0x210567F7, 0, "sceAudioEnd"},
|
||||
{0x38553111, 0, "sceAudioSRCChReserve"},
|
||||
{0x5C37C0AE, 0, "sceAudioSRCChRelease"},
|
||||
{0x80F1F7E0, sceAudioInit, "sceAudioInit"},
|
||||
{0x927AC32B, 0, "sceAudioSetVolumeOffset"},
|
||||
{0xA2BEAA6C, 0, "sceAudioSetFrequency"},
|
||||
{0xA633048E, 0, "sceAudioPollInputEnd"},
|
||||
{0xB011922F, 0, "sceAudioGetChannelRestLength"},
|
||||
{0xB61595C0, 0, "sceAudioLoopbackTest"},
|
||||
{0xE0727056, 0, "sceAudioSRCOutputBlocking"},
|
||||
{0xE926D3FB, 0, "sceAudioInputInitEx"},
|
||||
{0x8c1009b2, 0, "sceAudioOutput"},
|
||||
{0x136CAF51, WrapV_UUU<sceAudioOutputBlocking>, "sceAudioOutputBlocking"},
|
||||
{0xE2D56B2D, WrapU_UUUU<sceAudioOutputPanned>, "sceAudioOutputPanned"},
|
||||
{0x13F592BC, WrapV_UUUU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking
|
||||
{0x5EC81C55, WrapU_UUU<sceAudioChReserve>, "sceAudioChReserve"}, //(u32, u32 samplecount, u32) Initialize channel and allocate buffer long, long samplecount, long);//init buffer? returns handle, minus if error
|
||||
{0x6FC46853, WrapU_U<sceAudioChRelease>, "sceAudioChRelease"}, //(long handle)Terminate channel and deallocate buffer //free buffer?
|
||||
{0xE9D97901, sceAudioGetChannelRestLen, "sceAudioGetChannelRestLen"},
|
||||
{0xCB2E439E, WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen"}, //(u32, u32)
|
||||
{0x95FD0C2D, WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig"},
|
||||
{0xB7E1D8E7, WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume"},
|
||||
{0x41efade7, 0, "sceAudioOneshotOutput"},
|
||||
{0x086e5895, 0, "sceAudioInputBlocking"},
|
||||
{0x6d4bec68, 0, "sceAudioInput"},
|
||||
{0xa708c6a6, 0, "sceAudioGetInputLength"},
|
||||
{0x87b2e651, 0, "sceAudioWaitInputEnd"},
|
||||
{0x7de61688, 0, "sceAudioInputInit"},
|
||||
{0xb011922f, 0, "sceAudioGetChannelRestLength"},
|
||||
{0x80F1F7E0, WrapU_V<sceAudioInit>, "sceAudioInit"},
|
||||
{0x210567F7, WrapU_V<sceAudioEnd>, "sceAudioEnd"},
|
||||
|
||||
{0xA2BEAA6C, WrapU_U<sceAudioSetFrequency>, "sceAudioSetFrequency"},
|
||||
{0x927AC32B, 0, "sceAudioSetVolumeOffset"},
|
||||
|
||||
// The oldest and standard audio interface. Supports 8 channels, most games use 1-2.
|
||||
{0x8c1009b2, WrapU_UUU<sceAudioOutput>, "sceAudioOutput"},
|
||||
{0x136CAF51, WrapU_UUU<sceAudioOutputBlocking>, "sceAudioOutputBlocking"},
|
||||
{0xE2D56B2D, WrapU_UUUU<sceAudioOutputPanned>, "sceAudioOutputPanned"},
|
||||
{0x13F592BC, WrapU_UUUU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking
|
||||
{0x5EC81C55, WrapU_UUU<sceAudioChReserve>, "sceAudioChReserve"}, //(u32, u32 samplecount, u32) Initialize channel and allocate buffer long, long samplecount, long);//init buffer? returns handle, minus if error
|
||||
{0x6FC46853, WrapU_U<sceAudioChRelease>, "sceAudioChRelease"}, //(long handle)Terminate channel and deallocate buffer //free buffer?
|
||||
{0xE9D97901, WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLen"},
|
||||
{0xB011922F, WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLength"}, // Is there a difference between this and sceAudioGetChannelRestLen?
|
||||
{0xCB2E439E, WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen"}, //(u32, u32)
|
||||
{0x95FD0C2D, WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig"},
|
||||
{0xB7E1D8E7, WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume"},
|
||||
|
||||
// I guess these are like the others but do sample rate conversion?
|
||||
{0x38553111, 0, "sceAudioSRCChReserve"},
|
||||
{0x5C37C0AE, 0, "sceAudioSRCChRelease"},
|
||||
{0xE0727056, 0, "sceAudioSRCOutputBlocking"},
|
||||
|
||||
// Never seen these used
|
||||
{0x41efade7, 0, "sceAudioOneshotOutput"},
|
||||
{0xB61595C0, 0, "sceAudioLoopbackTest"},
|
||||
|
||||
// Microphone interface
|
||||
{0x7de61688, 0, "sceAudioInputInit"},
|
||||
{0xE926D3FB, 0, "sceAudioInputInitEx"},
|
||||
{0x6d4bec68, 0, "sceAudioInput"},
|
||||
{0x086e5895, 0, "sceAudioInputBlocking"},
|
||||
{0xa708c6a6, 0, "sceAudioGetInputLength"},
|
||||
{0xA633048E, 0, "sceAudioPollInputEnd"},
|
||||
{0x87b2e651, 0, "sceAudioWaitInputEnd"},
|
||||
};
|
||||
|
||||
|
||||
|
||||
void Register_sceAudio()
|
||||
{
|
||||
RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio);
|
||||
RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <queue>
|
||||
|
||||
#include "CommonTypes.h"
|
||||
#include "sceKernel.h"
|
||||
#include "FixedSizeQueue.h"
|
||||
|
||||
enum PspAudioFormats { PSP_AUDIO_FORMAT_STEREO = 0, PSP_AUDIO_FORMAT_MONO = 0x10 };
|
||||
@ -39,7 +40,9 @@ enum PspAudioFrequencies { PSP_AUDIO_FREQ_44K = 44100, PSP_AUDIO_FREQ_48K = 48
|
||||
|
||||
struct AudioChannel
|
||||
{
|
||||
AudioChannel() {clear();}
|
||||
AudioChannel() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// PSP side
|
||||
|
||||
@ -48,31 +51,33 @@ struct AudioChannel
|
||||
// last sample address
|
||||
u32 sampleAddress;
|
||||
u32 sampleCount; // Number of samples written in each OutputBlocking
|
||||
|
||||
int running;
|
||||
int triggered;
|
||||
int dataLen; // Probably internal queue size. Not currently used.
|
||||
|
||||
int leftVolume;
|
||||
int rightVolume;
|
||||
|
||||
int format;
|
||||
|
||||
SceUID waitingThread;
|
||||
|
||||
// PC side - should probably split out
|
||||
|
||||
// We copy samples as they are written into this simple ring buffer.
|
||||
// Might try something more efficient later.
|
||||
FixedSizeQueue<s16, 16384> sampleQueue;
|
||||
|
||||
FixedSizeQueue<s16, 32768> sampleQueue;
|
||||
|
||||
void clear() {
|
||||
reserved = false;
|
||||
running = false;
|
||||
waitingThread = 0;
|
||||
leftVolume = 0;
|
||||
rightVolume = 0;
|
||||
format = 0;
|
||||
sampleAddress = 0;
|
||||
sampleCount = 0;
|
||||
sampleQueue.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern AudioChannel chans[8];
|
||||
|
||||
void Register_sceAudio();
|
||||
|
@ -17,8 +17,12 @@
|
||||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../CoreTiming.h"
|
||||
#include "StdMutex.h"
|
||||
#include "sceCtrl.h"
|
||||
#include "sceDisplay.h"
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
|
||||
/* Index for the two analog directions */
|
||||
#define CTRL_ANALOG_X 0
|
||||
@ -27,6 +31,16 @@
|
||||
#define CTRL_MODE_DIGITAL 0
|
||||
#define CTRL_MODE_ANALOG 1
|
||||
|
||||
const int PSP_CTRL_ERROR_INVALID_MODE = 0x80000107;
|
||||
const int PSP_CTRL_ERROR_INVALID_NUM_BUFFERS = 0x80000104;
|
||||
|
||||
const int NUM_CTRL_BUFFERS = 64;
|
||||
|
||||
enum
|
||||
{
|
||||
CTRL_WAIT_POSITIVE = 1,
|
||||
CTRL_WAIT_NEGATIVE = 2,
|
||||
};
|
||||
|
||||
// Returned control data
|
||||
struct _ctrl_data
|
||||
@ -37,7 +51,6 @@ struct _ctrl_data
|
||||
u8 unused[6];
|
||||
};
|
||||
|
||||
static u32 oldButtons;
|
||||
struct CtrlLatch {
|
||||
u32 btnMake;
|
||||
u32 btnBreak;
|
||||
@ -46,37 +59,70 @@ struct CtrlLatch {
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// STATE BEGIN
|
||||
static bool ctrlInited = false;
|
||||
static bool analogEnabled = false;
|
||||
static int ctrlLatchBufs = 0;
|
||||
static u32 ctrlOldButtons = 0;
|
||||
|
||||
static _ctrl_data ctrl;
|
||||
static _ctrl_data ctrlBufs[NUM_CTRL_BUFFERS];
|
||||
static _ctrl_data ctrlCurrent;
|
||||
static int ctrlBuf = 0;
|
||||
static int ctrlBufRead = 0;
|
||||
static CtrlLatch latch;
|
||||
|
||||
static std::vector<SceUID> waitingThreads;
|
||||
static std::recursive_mutex ctrlMutex;
|
||||
|
||||
// STATE END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void SampleControls() {
|
||||
static int frame = 0;
|
||||
_ctrl_data &data = ctrl;
|
||||
data.frame=1;//frame;
|
||||
frame++;
|
||||
void __CtrlUpdateLatch()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
|
||||
u32 changed = ctrlCurrent.buttons ^ ctrlOldButtons;
|
||||
latch.btnMake |= ctrlCurrent.buttons & changed;
|
||||
latch.btnBreak |= ctrlOldButtons & changed;
|
||||
latch.btnPress |= ctrlCurrent.buttons;
|
||||
latch.btnRelease |= (ctrlOldButtons & ~ctrlCurrent.buttons) & changed;
|
||||
ctrlLatchBufs++;
|
||||
|
||||
ctrlOldButtons = ctrlCurrent.buttons;
|
||||
|
||||
// Copy in the current data to the current buffer.
|
||||
memcpy(&ctrlBufs[ctrlBuf], &ctrlCurrent, sizeof(_ctrl_data));
|
||||
|
||||
ctrlBufs[ctrlBuf].frame = (u32) (CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz());
|
||||
if (!analogEnabled)
|
||||
{
|
||||
ctrlBufs[ctrlBuf].analog[0] = 128;
|
||||
ctrlBufs[ctrlBuf].analog[1] = 128;
|
||||
}
|
||||
|
||||
ctrlBuf = (ctrlBuf + 1) % NUM_CTRL_BUFFERS;
|
||||
|
||||
// If we wrapped around, push the read head forward.
|
||||
// TODO: Is this right?
|
||||
if (ctrlBufRead == ctrlBuf)
|
||||
ctrlBufRead = (ctrlBufRead + 1) % NUM_CTRL_BUFFERS;
|
||||
}
|
||||
|
||||
int __CtrlResetLatch()
|
||||
{
|
||||
int oldBufs = ctrlLatchBufs;
|
||||
memset(&latch, 0, sizeof(CtrlLatch));
|
||||
ctrlLatchBufs = 0;
|
||||
return oldBufs;
|
||||
}
|
||||
|
||||
void UpdateLatch() {
|
||||
u32 changed = ctrl.buttons ^ oldButtons;
|
||||
latch.btnMake = ctrl.buttons & changed;
|
||||
latch.btnBreak = oldButtons & changed;
|
||||
latch.btnPress = ctrl.buttons;
|
||||
latch.btnRelease = (oldButtons & ~ctrl.buttons) & changed;
|
||||
|
||||
oldButtons = ctrl.buttons;
|
||||
u32 __CtrlPeekButtons()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
|
||||
return ctrlCurrent.buttons;
|
||||
}
|
||||
|
||||
// Functions so that the rest of the emulator can control what the sceCtrl interface should return
|
||||
@ -84,116 +130,274 @@ void UpdateLatch() {
|
||||
|
||||
void __CtrlButtonDown(u32 buttonBit)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
ctrl.buttons |= buttonBit;
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
ctrlCurrent.buttons |= buttonBit;
|
||||
}
|
||||
|
||||
void __CtrlButtonUp(u32 buttonBit)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
ctrl.buttons &= ~buttonBit;
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
ctrlCurrent.buttons &= ~buttonBit;
|
||||
}
|
||||
|
||||
void __CtrlSetAnalog(float x, float y)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
// TODO: Circle!
|
||||
if (x > 1.0f) x = 1.0f;
|
||||
if (y > 1.0f) y = 1.0f;
|
||||
if (x < -1.0f) x = -1.0f;
|
||||
if (y > -1.0f) y = -1.0f;
|
||||
ctrl.analog[0] = (u8)(x * 127.f + 128.f);
|
||||
ctrl.analog[1] = (u8)(y * 127.f + 128.f);
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
// TODO: Circle!
|
||||
if (x > 1.0f) x = 1.0f;
|
||||
if (y > 1.0f) y = 1.0f;
|
||||
if (x < -1.0f) x = -1.0f;
|
||||
if (y < -1.0f) y = -1.0f;
|
||||
ctrlCurrent.analog[0] = (u8)(x * 127.f + 128.f);
|
||||
ctrlCurrent.analog[1] = (u8)(y * 127.f + 128.f);
|
||||
}
|
||||
|
||||
int __CtrlReadSingleBuffer(u32 ctrlDataPtr, bool negative)
|
||||
{
|
||||
_ctrl_data data;
|
||||
if (Memory::IsValidAddress(ctrlDataPtr))
|
||||
{
|
||||
memcpy(&data, &ctrlBufs[ctrlBufRead], sizeof(_ctrl_data));
|
||||
ctrlBufRead = (ctrlBufRead + 1) % NUM_CTRL_BUFFERS;
|
||||
|
||||
if (negative)
|
||||
data.buttons = ~data.buttons;
|
||||
|
||||
Memory::WriteStruct(ctrlDataPtr, &data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __CtrlReadBuffer(u32 ctrlDataPtr, u32 nBufs, bool negative, bool peek)
|
||||
{
|
||||
if (nBufs > NUM_CTRL_BUFFERS)
|
||||
return PSP_CTRL_ERROR_INVALID_NUM_BUFFERS;
|
||||
|
||||
int resetRead = ctrlBufRead;
|
||||
|
||||
u32 availBufs;
|
||||
// Peeks always work, they just go go from now X buffers.
|
||||
if (peek)
|
||||
availBufs = nBufs;
|
||||
else
|
||||
{
|
||||
availBufs = (ctrlBuf - ctrlBufRead + NUM_CTRL_BUFFERS) % NUM_CTRL_BUFFERS;
|
||||
if (availBufs > nBufs)
|
||||
availBufs = nBufs;
|
||||
}
|
||||
ctrlBufRead = (ctrlBuf - availBufs + NUM_CTRL_BUFFERS) % NUM_CTRL_BUFFERS;
|
||||
|
||||
int done = 0;
|
||||
for (u32 i = 0; i < availBufs; ++i)
|
||||
{
|
||||
done += __CtrlReadSingleBuffer(ctrlDataPtr, negative);
|
||||
ctrlDataPtr += sizeof(_ctrl_data);
|
||||
}
|
||||
|
||||
if (peek)
|
||||
ctrlBufRead = resetRead;
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
void __CtrlVblank()
|
||||
{
|
||||
// When in vblank sampling mode, this samples the ctrl data into the buffers and updates the latch.
|
||||
__CtrlUpdateLatch();
|
||||
|
||||
// Wake up a single thread that was waiting for the buffer.
|
||||
retry:
|
||||
if (!waitingThreads.empty() && ctrlBuf != ctrlBufRead)
|
||||
{
|
||||
SceUID threadID = waitingThreads[0];
|
||||
waitingThreads.erase(waitingThreads.begin());
|
||||
|
||||
u32 error;
|
||||
SceUID wVal = __KernelGetWaitID(threadID, WAITTYPE_CTRL, error);
|
||||
// Make sure it didn't get woken or something.
|
||||
if (wVal == 0)
|
||||
goto retry;
|
||||
|
||||
u32 ctrlDataPtr = __KernelGetWaitValue(threadID, error);
|
||||
int retVal = __CtrlReadSingleBuffer(ctrlDataPtr, wVal == CTRL_WAIT_NEGATIVE);
|
||||
__KernelResumeThreadFromWait(threadID, retVal);
|
||||
}
|
||||
}
|
||||
|
||||
void __CtrlInit()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
|
||||
if (!ctrlInited)
|
||||
{
|
||||
__DisplayListenVblank(__CtrlVblank);
|
||||
ctrlInited = true;
|
||||
}
|
||||
|
||||
ctrlBuf = 1;
|
||||
ctrlBufRead = 0;
|
||||
ctrlOldButtons = 0;
|
||||
ctrlLatchBufs = 0;
|
||||
|
||||
memset(&latch, 0, sizeof(latch));
|
||||
// Start with everything released.
|
||||
latch.btnRelease = 0xffffffff;
|
||||
|
||||
memset(&ctrlCurrent, 0, sizeof(ctrlCurrent));
|
||||
ctrlCurrent.analog[0] = 128;
|
||||
ctrlCurrent.analog[1] = 128;
|
||||
|
||||
for (int i = 0; i < NUM_CTRL_BUFFERS; i++)
|
||||
memcpy(&ctrlBufs[i], &ctrlCurrent, sizeof(_ctrl_data));
|
||||
}
|
||||
|
||||
void sceCtrlInit()
|
||||
{
|
||||
ctrlInited = true;
|
||||
memset(&ctrl, 0, sizeof(ctrl));
|
||||
ctrl.analog[0] = 128;
|
||||
ctrl.analog[1] = 128;
|
||||
__CtrlInit();
|
||||
|
||||
DEBUG_LOG(HLE,"sceCtrlInit");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
u32 sceCtrlSetSamplingCycle(u32 cycle)
|
||||
{
|
||||
if (cycle == 0)
|
||||
{
|
||||
// TODO: Change to vblank when we support something else.
|
||||
DEBUG_LOG(HLE, "sceCtrlSetSamplingCycle(%u)", cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceCtrlSetSamplingCycle(%u)", cycle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceCtrlGetSamplingCycle(u32 cyclePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceCtrlSetSamplingCycle(%08x)", cyclePtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceCtrlSetSamplingMode(u32 mode)
|
||||
{
|
||||
u32 retVal = 0;
|
||||
|
||||
DEBUG_LOG(HLE,"sceCtrlSetSamplingMode(%i)", mode);
|
||||
_assert_msg_(HLE, mode >= 0 && mode <= 1, "sceCtrlSetSamplingMode: mode outside expected range.");
|
||||
DEBUG_LOG(HLE, "sceCtrlSetSamplingMode(%i)", mode);
|
||||
if (mode > 1)
|
||||
return PSP_CTRL_ERROR_INVALID_MODE;
|
||||
|
||||
if (ctrlInited)
|
||||
{
|
||||
retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
|
||||
analogEnabled = mode == CTRL_MODE_ANALOG ? true : false;
|
||||
}
|
||||
retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
|
||||
analogEnabled = mode == CTRL_MODE_ANALOG ? true : false;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int sceCtrlGetSamplingMode(u32 modePtr)
|
||||
{
|
||||
u32 retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
|
||||
|
||||
if (Memory::IsValidAddress(modePtr))
|
||||
Memory::Write_U32(retVal, modePtr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceCtrlSetIdleCancelThreshold()
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNIMPL sceCtrlSetIdleCancelThreshold");
|
||||
ERROR_LOG(HLE,"UNIMPL sceCtrlSetIdleCancelThreshold");
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
u32 sceCtrlReadBufferPositive(u32 ctrlDataPtr, u32 nBufs)
|
||||
void sceCtrlReadBufferPositive(u32 ctrlDataPtr, u32 nBufs)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceCtrlReadBufferPositive(%08x, %i)", ctrlDataPtr, nBufs);
|
||||
_assert_msg_(HLE, nBufs > 0, "sceCtrlReadBufferPositive: trying to read nothing?");
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
|
||||
// Let's just ignore if ctrl is inited or not; some games don't init it (Super Fruit Fall)
|
||||
//if (ctrlInited)
|
||||
//{
|
||||
SampleControls();
|
||||
memcpy(Memory::GetPointer(ctrlDataPtr), &ctrl, sizeof(_ctrl_data));
|
||||
//}
|
||||
return 1;
|
||||
int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, false, false);
|
||||
if (done != 0)
|
||||
{
|
||||
RETURN(done);
|
||||
DEBUG_LOG(HLE, "%d=sceCtrlReadBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitingThreads.push_back(__KernelGetCurThread());
|
||||
__KernelWaitCurThread(WAITTYPE_CTRL, CTRL_WAIT_POSITIVE, ctrlDataPtr, 0, false);
|
||||
DEBUG_LOG(HLE, "sceCtrlReadBufferPositive(%08x, %i) - waiting", ctrlDataPtr, nBufs);
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceCtrlPeekLatch(u32 latchDataPtr) {
|
||||
ERROR_LOG(HLE,"FAKE sceCtrlPeekLatch(%08x)", latchDataPtr);
|
||||
|
||||
if (Memory::IsValidAddress(latchDataPtr))
|
||||
Memory::WriteStruct(latchDataPtr, &latch);
|
||||
return 1;
|
||||
void sceCtrlReadBufferNegative(u32 ctrlDataPtr, u32 nBufs)
|
||||
{
|
||||
int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, true, false);
|
||||
if (done != 0)
|
||||
{
|
||||
RETURN(done);
|
||||
DEBUG_LOG(HLE, "%d=sceCtrlReadBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitingThreads.push_back(__KernelGetCurThread());
|
||||
__KernelWaitCurThread(WAITTYPE_CTRL, CTRL_WAIT_NEGATIVE, ctrlDataPtr, 0, false);
|
||||
DEBUG_LOG(HLE, "sceCtrlReadBufferNegative(%08x, %i) - waiting", ctrlDataPtr, nBufs);
|
||||
}
|
||||
}
|
||||
|
||||
u32 sceCtrlReadLatch(u32 latchDataPtr) {
|
||||
ERROR_LOG(HLE,"FAKE sceCtrlReadLatch(%08x)", latchDataPtr);
|
||||
int sceCtrlPeekBufferPositive(u32 ctrlDataPtr, u32 nBufs)
|
||||
{
|
||||
int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, false, true);
|
||||
DEBUG_LOG(HLE, "%d=sceCtrlPeekBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs);
|
||||
return done;
|
||||
}
|
||||
|
||||
// Hackery to do it here.
|
||||
SampleControls();
|
||||
UpdateLatch();
|
||||
int sceCtrlPeekBufferNegative(u32 ctrlDataPtr, u32 nBufs)
|
||||
{
|
||||
int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, true, true);
|
||||
DEBUG_LOG(HLE, "%d=sceCtrlPeekBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs);
|
||||
return done;
|
||||
}
|
||||
|
||||
u32 sceCtrlPeekLatch(u32 latchDataPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceCtrlPeekLatch(%08x)", latchDataPtr);
|
||||
|
||||
if (Memory::IsValidAddress(latchDataPtr))
|
||||
Memory::WriteStruct(latchDataPtr, &latch);
|
||||
|
||||
return 1;
|
||||
return ctrlLatchBufs;
|
||||
}
|
||||
|
||||
u32 sceCtrlReadLatch(u32 latchDataPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceCtrlReadLatch(%08x)", latchDataPtr);
|
||||
|
||||
if (Memory::IsValidAddress(latchDataPtr))
|
||||
Memory::WriteStruct(latchDataPtr, &latch);
|
||||
|
||||
return __CtrlResetLatch();
|
||||
}
|
||||
|
||||
static const HLEFunction sceCtrl[] =
|
||||
{
|
||||
{0x6a2774f3, sceCtrlInit, "sceCtrlInit"}, //(int unknown), init with 0
|
||||
{0x1f4011e6, &WrapU_U<sceCtrlSetSamplingMode>, "sceCtrlSetSamplingMode"}, //(int on);
|
||||
{0x1f803938, &WrapU_UU<sceCtrlReadBufferPositive>, "sceCtrlReadBufferPositive"}, //(ctrl_data_t* paddata, int unknown) // unknown should be 1
|
||||
{0x6A2774F3, 0, "sceCtrlSetSamplingCycle"}, //?
|
||||
{0x6A2774F3,sceCtrlInit,"sceCtrlSetSamplingCycle"},
|
||||
{0x02BAAD91,0,"sceCtrlGetSamplingCycle"},
|
||||
{0xDA6B76A1,0,"sceCtrlGetSamplingMode"},
|
||||
{0x3A622550,&WrapU_UU<sceCtrlReadBufferPositive>, "sceCtrlPeekBufferPositive"},
|
||||
{0xC152080A,0,"sceCtrlPeekBufferNegative"},
|
||||
{0x60B81F86,0,"sceCtrlReadBufferNegative"},
|
||||
{0xB1D0E5CD,&WrapU_U<sceCtrlPeekLatch>,"sceCtrlPeekLatch"},
|
||||
{0x0B588501,&WrapU_U<sceCtrlReadLatch>,"sceCtrlReadLatch"},
|
||||
{0x348D99D4,0,"sceCtrl_348D99D4"},
|
||||
{0xAF5960F3,0,"sceCtrl_AF5960F3"},
|
||||
{0xA68FD260,0,"sceCtrlClearRapidFire"},
|
||||
{0x6841BE1A,0,"sceCtrlSetRapidFire"},
|
||||
{0xa7144800,sceCtrlSetIdleCancelThreshold,"sceCtrlSetIdleCancelThreshold"},
|
||||
{0x687660fa,0,"sceCtrlGetIdleCancelThreshold"},
|
||||
{0x3E65A0EA, WrapV_V<sceCtrlInit>, "sceCtrlInit"}, //(int unknown), init with 0
|
||||
{0x1f4011e6, WrapU_U<sceCtrlSetSamplingMode>, "sceCtrlSetSamplingMode"}, //(int on);
|
||||
{0x6A2774F3, WrapU_U<sceCtrlSetSamplingCycle>, "sceCtrlSetSamplingCycle"},
|
||||
{0x02BAAD91, WrapI_U<sceCtrlGetSamplingCycle>,"sceCtrlGetSamplingCycle"},
|
||||
{0xDA6B76A1, WrapI_U<sceCtrlGetSamplingMode>, "sceCtrlGetSamplingMode"},
|
||||
{0x1f803938, WrapV_UU<sceCtrlReadBufferPositive>, "sceCtrlReadBufferPositive"}, //(ctrl_data_t* paddata, int unknown) // unknown should be 1
|
||||
{0x3A622550, WrapI_UU<sceCtrlPeekBufferPositive>, "sceCtrlPeekBufferPositive"},
|
||||
{0xC152080A, WrapI_UU<sceCtrlPeekBufferNegative>, "sceCtrlPeekBufferNegative"},
|
||||
{0x60B81F86, WrapV_UU<sceCtrlReadBufferNegative>, "sceCtrlReadBufferNegative"},
|
||||
{0xB1D0E5CD, WrapU_U<sceCtrlPeekLatch>, "sceCtrlPeekLatch"},
|
||||
{0x0B588501, WrapU_U<sceCtrlReadLatch>, "sceCtrlReadLatch"},
|
||||
{0x348D99D4, 0, "sceCtrl_348D99D4"},
|
||||
{0xAF5960F3, 0, "sceCtrl_AF5960F3"},
|
||||
{0xA68FD260, 0, "sceCtrlClearRapidFire"},
|
||||
{0x6841BE1A, 0, "sceCtrlSetRapidFire"},
|
||||
{0xa7144800, WrapV_V<sceCtrlSetIdleCancelThreshold>, "sceCtrlSetIdleCancelThreshold"},
|
||||
{0x687660fa, 0, "sceCtrlGetIdleCancelThreshold"},
|
||||
};
|
||||
|
||||
void Register_sceCtrl() {
|
||||
RegisterModule("sceCtrl",ARRAY_SIZE(sceCtrl),sceCtrl);
|
||||
void Register_sceCtrl()
|
||||
{
|
||||
RegisterModule("sceCtrl", ARRAY_SIZE(sceCtrl), sceCtrl);
|
||||
}
|
||||
|
@ -32,7 +32,12 @@ void Register_sceCtrl();
|
||||
#define CTRL_LTRIGGER 0x0100
|
||||
#define CTRL_RTRIGGER 0x0200
|
||||
|
||||
void __CtrlInit();
|
||||
|
||||
void __CtrlButtonDown(u32 buttonBit);
|
||||
void __CtrlButtonUp(u32 buttonBit);
|
||||
// -1 to 1, try to keep it in the circle
|
||||
void __CtrlSetAnalog(float x, float y);
|
||||
|
||||
// For use by internal UI like MsgDialog
|
||||
u32 __CtrlPeekButtons();
|
@ -15,28 +15,23 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#if defined(ANDROID) || defined(BLACKBERRY)
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#else
|
||||
#include <GL/glew.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
//#include "base/timeutil.h"
|
||||
// TODO: Move the relevant parts into common. Don't want the core
|
||||
// to be dependent on "native", I think. Or maybe should get rid of common
|
||||
// and move everything into native...
|
||||
#include "base/timeutil.h"
|
||||
|
||||
#include "Thread.h"
|
||||
#include "../Core/CoreTiming.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../HLE/HLE.h"
|
||||
#include "sceAudio.h"
|
||||
#include "../Host.h"
|
||||
#include "../Config.h"
|
||||
#include "../System.h"
|
||||
#include "../Core/Core.h"
|
||||
#include "sceDisplay.h"
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
@ -45,14 +40,17 @@
|
||||
// TODO: This file should not depend directly on GLES code.
|
||||
#include "../../GPU/GLES/Framebuffer.h"
|
||||
#include "../../GPU/GLES/ShaderManager.h"
|
||||
#include "../../GPU/GLES/TextureCache.h"
|
||||
#include "../../GPU/GPUState.h"
|
||||
#include "../../GPU/GPUInterface.h"
|
||||
// Internal drawing library
|
||||
#include "../Util/PPGeDraw.h"
|
||||
|
||||
extern ShaderManager shaderManager;
|
||||
|
||||
struct FrameBufferState
|
||||
{
|
||||
u32 topaddr;
|
||||
u8 *pspframebuf;
|
||||
PspDisplayPixelFormat pspFramebufFormat;
|
||||
int pspFramebufLinesize;
|
||||
};
|
||||
@ -69,14 +67,19 @@ static int hCount = 0;
|
||||
static int hCountTotal = 0; //unused
|
||||
static int vCount = 0;
|
||||
static int isVblank = 0;
|
||||
static bool hasSetMode = false;
|
||||
double lastFrameTime = 0;
|
||||
|
||||
// STATE END
|
||||
|
||||
|
||||
std::vector<VblankCallback> vblankListeners;
|
||||
|
||||
// The vblank period is 731.5 us (0.7315 ms)
|
||||
const double vblankMs = 0.7315;
|
||||
const double frameMs = 1000.0 / 60.0;
|
||||
|
||||
enum {
|
||||
PSP_DISPLAY_SETBUF_IMMEDIATE = 0,
|
||||
PSP_DISPLAY_SETBUF_IMMEDIATE = 0,
|
||||
PSP_DISPLAY_SETBUF_NEXTFRAME = 1
|
||||
};
|
||||
|
||||
@ -93,9 +96,10 @@ void hleLeaveVblank(u64 userdata, int cyclesLate);
|
||||
|
||||
void __DisplayInit()
|
||||
{
|
||||
gpuStats.reset();
|
||||
hasSetMode = false;
|
||||
framebufIsLatched = false;
|
||||
framebuf.topaddr = 0x04000000;
|
||||
framebuf.pspframebuf = Memory::GetPointer(0x04000000);
|
||||
framebuf.pspFramebufFormat = PSP_DISPLAY_PIXEL_FORMAT_8888;
|
||||
framebuf.pspFramebufLinesize = 480; // ??
|
||||
|
||||
@ -114,6 +118,20 @@ void __DisplayShutdown()
|
||||
ShutdownGfxState();
|
||||
}
|
||||
|
||||
void __DisplayListenVblank(VblankCallback callback)
|
||||
{
|
||||
vblankListeners.push_back(callback);
|
||||
}
|
||||
|
||||
void __DisplayFireVblank()
|
||||
{
|
||||
for (std::vector<VblankCallback>::iterator iter = vblankListeners.begin(), end = vblankListeners.end(); iter != end; ++iter)
|
||||
{
|
||||
VblankCallback cb = *iter;
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
void hleEnterVblank(u64 userdata, int cyclesLate)
|
||||
{
|
||||
int vbCount = userdata;
|
||||
@ -122,6 +140,9 @@ void hleEnterVblank(u64 userdata, int cyclesLate)
|
||||
|
||||
isVblank = 1;
|
||||
|
||||
// Fire the vblank listeners before we wake threads.
|
||||
__DisplayFireVblank();
|
||||
|
||||
// Wake up threads waiting for VBlank
|
||||
__KernelTriggerWait(WAITTYPE_VBLANK, 0, true);
|
||||
|
||||
@ -131,38 +152,91 @@ void hleEnterVblank(u64 userdata, int cyclesLate)
|
||||
CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount+1);
|
||||
|
||||
// TODO: Should this be done here or in hleLeaveVblank?
|
||||
if (framebufIsLatched)
|
||||
if (framebufIsLatched)
|
||||
{
|
||||
DEBUG_LOG(HLE, "Setting latched framebuffer %08x (prev: %08x)", latchedFramebuf.topaddr, framebuf.topaddr);
|
||||
framebuf = latchedFramebuf;
|
||||
framebufIsLatched = false;
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
|
||||
// Yeah, this has to be the right moment to end the frame. Should possibly blit the right buffer
|
||||
// depending on what's set in sceDisplaySetFramebuf, in order to support half-framerate games -
|
||||
// an initial hack could be to NOT end the frame if the buffer didn't change? that should work okay.
|
||||
// Draw screen overlays before blitting. Saves and restores the Ge context.
|
||||
|
||||
gpuStats.numFrames++;
|
||||
|
||||
// Yeah, this has to be the right moment to end the frame. Give the graphics backend opportunity
|
||||
// to blit the framebuffer, in order to support half-framerate games that otherwise wouldn't have
|
||||
// anything to draw here.
|
||||
gpu->CopyDisplayToOutput();
|
||||
|
||||
// Now we can subvert the Ge engine in order to draw custom overlays like stat counters etc.
|
||||
// Here we will be drawing to the non buffered front surface.
|
||||
if (g_Config.bShowDebugStats)
|
||||
{
|
||||
host->EndFrame();
|
||||
|
||||
host->BeginFrame();
|
||||
if (g_Config.bDisplayFramebuffer)
|
||||
{
|
||||
INFO_LOG(HLE, "Drawing the framebuffer");
|
||||
DisplayDrawer_DrawFramebuffer(framebuf.pspframebuf, framebuf.pspFramebufFormat, framebuf.pspFramebufLinesize);
|
||||
}
|
||||
|
||||
shaderManager.DirtyShader();
|
||||
shaderManager.DirtyUniform(DIRTY_ALL);
|
||||
gpu->UpdateStats();
|
||||
char stats[512];
|
||||
sprintf(stats,
|
||||
"Frames: %i\n"
|
||||
"Draw calls: %i\n"
|
||||
"Vertices Transformed: %i\n"
|
||||
"Textures active: %i\n"
|
||||
"Vertex shaders loaded: %i\n"
|
||||
"Fragment shaders loaded: %i\n"
|
||||
"Combined shaders loaded: %i\n",
|
||||
gpuStats.numFrames,
|
||||
gpuStats.numDrawCalls,
|
||||
gpuStats.numVertsTransformed,
|
||||
gpuStats.numTextures,
|
||||
gpuStats.numVertexShaders,
|
||||
gpuStats.numFragmentShaders,
|
||||
gpuStats.numShaders
|
||||
);
|
||||
|
||||
float zoom = 0.7f * sqrtf(g_Config.iWindowZoom);
|
||||
PPGeBegin();
|
||||
PPGeDrawText(stats, 2, 2, 0, zoom, 0x90000000);
|
||||
PPGeDrawText(stats, 0, 0, 0, zoom);
|
||||
PPGeEnd();
|
||||
|
||||
gpuStats.resetFrame();
|
||||
}
|
||||
|
||||
// TODO: Find a way to tell the CPU core to stop emulating here, when running on Android.
|
||||
|
||||
host->EndFrame();
|
||||
|
||||
#ifdef _WIN32
|
||||
static double lastFrameTime = 0.0;
|
||||
// Best place to throttle the frame rate on non vsynced platforms is probably here. Let's try it.
|
||||
time_update();
|
||||
if (lastFrameTime == 0.0)
|
||||
lastFrameTime = time_now_d();
|
||||
if (!GetAsyncKeyState(VK_TAB)) {
|
||||
while (time_now_d() < lastFrameTime + 1.0 / 60.0f) {
|
||||
Common::SleepCurrentThread(1);
|
||||
time_update();
|
||||
}
|
||||
lastFrameTime = time_now_d();
|
||||
}
|
||||
#endif
|
||||
|
||||
host->BeginFrame();
|
||||
gpu->BeginFrame();
|
||||
|
||||
shaderManager.DirtyShader();
|
||||
shaderManager.DirtyUniform(DIRTY_ALL);
|
||||
|
||||
// Tell the emu core that it's time to stop emulating
|
||||
// Win32 doesn't need this.
|
||||
#ifndef _WIN32
|
||||
coreState = CORE_NEXTFRAME;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void hleLeaveVblank(u64 userdata, int cyclesLate)
|
||||
{
|
||||
isVblank = 0;
|
||||
DEBUG_LOG(HLE,"Leave VBlank");
|
||||
DEBUG_LOG(HLE,"Leave VBlank %i", (int)userdata - 1);
|
||||
vCount++;
|
||||
hCount = 0;
|
||||
CoreTiming::ScheduleEvent(msToCycles(frameMs - vblankMs) - cyclesLate, enterVblankEvent, userdata);
|
||||
@ -179,9 +253,11 @@ u32 sceDisplaySetMode(u32 unknown, u32 xres, u32 yres)
|
||||
DEBUG_LOG(HLE,"sceDisplaySetMode(%d,%d,%d)",unknown,xres,yres);
|
||||
host->BeginFrame();
|
||||
|
||||
glClearColor(0,0,0,1);
|
||||
// glClearColor(1,0,1,1);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
if (!hasSetMode)
|
||||
{
|
||||
gpu->InitClear();
|
||||
hasSetMode = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -194,19 +270,7 @@ void sceDisplaySetFramebuf()
|
||||
int pixelformat = PARAM(2);
|
||||
int sync = PARAM(3);
|
||||
|
||||
FrameBufferState *fbstate = 0;
|
||||
if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE)
|
||||
{
|
||||
// Write immediately to the current framebuffer parameters
|
||||
fbstate = &framebuf;
|
||||
}
|
||||
else if (topaddr != 0)
|
||||
{
|
||||
// Delay the write until vblank
|
||||
fbstate = &latchedFramebuf;
|
||||
framebufIsLatched = true;
|
||||
}
|
||||
|
||||
FrameBufferState fbstate;
|
||||
DEBUG_LOG(HLE,"sceDisplaySetFramebuf(topaddr=%08x,linesize=%d,pixelsize=%d,sync=%d)",topaddr,linesize,pixelformat,sync);
|
||||
if (topaddr == 0)
|
||||
{
|
||||
@ -214,19 +278,41 @@ void sceDisplaySetFramebuf()
|
||||
}
|
||||
else
|
||||
{
|
||||
fbstate->topaddr = topaddr;
|
||||
fbstate->pspframebuf = Memory::GetPointer((0x44000000)|(topaddr & 0x1FFFFF)); // TODO - check
|
||||
fbstate->pspFramebufFormat = (PspDisplayPixelFormat)pixelformat;
|
||||
fbstate->pspFramebufLinesize = linesize;
|
||||
fbstate.topaddr = topaddr;
|
||||
fbstate.pspFramebufFormat = (PspDisplayPixelFormat)pixelformat;
|
||||
fbstate.pspFramebufLinesize = linesize;
|
||||
}
|
||||
|
||||
if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE)
|
||||
{
|
||||
// Write immediately to the current framebuffer parameters
|
||||
framebuf = fbstate;
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
else if (topaddr != 0)
|
||||
{
|
||||
// Delay the write until vblank
|
||||
latchedFramebuf = fbstate;
|
||||
framebufIsLatched = true;
|
||||
}
|
||||
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceDisplayGetFramebuf()
|
||||
u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelFormatPtr, int mode)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceDisplayGetFramebuf()");
|
||||
RETURN(framebuf.topaddr);
|
||||
const FrameBufferState &fbState = mode == 1 ? latchedFramebuf : framebuf;
|
||||
DEBUG_LOG(HLE,"sceDisplayGetFramebuf(*%08x = %08x, *%08x = %08x, *%08x = %08x, %i)",
|
||||
topaddrPtr, fbState.topaddr, linesizePtr, fbState.pspFramebufLinesize, pixelFormatPtr, fbState.pspFramebufFormat, mode);
|
||||
|
||||
if (Memory::IsValidAddress(topaddrPtr))
|
||||
Memory::Write_U32(fbState.topaddr, topaddrPtr);
|
||||
if (Memory::IsValidAddress(linesizePtr))
|
||||
Memory::Write_U32(fbState.pspFramebufLinesize, linesizePtr);
|
||||
if (Memory::IsValidAddress(pixelFormatPtr))
|
||||
Memory::Write_U32(fbState.pspFramebufFormat, pixelFormatPtr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceDisplayWaitVblankStart()
|
||||
@ -241,18 +327,28 @@ void sceDisplayWaitVblank()
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false);
|
||||
}
|
||||
|
||||
void sceDisplayWaitVblankStartMulti()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceDisplayWaitVblankStartMulti()");
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false);
|
||||
}
|
||||
|
||||
void sceDisplayWaitVblankCB()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceDisplayWaitVblankCB()");
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
|
||||
void sceDisplayWaitVblankStartCB()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB()");
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
|
||||
void sceDisplayWaitVblankStartMultiCB()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceDisplayWaitVblankStartMultiCB()");
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
|
||||
}
|
||||
|
||||
void sceDisplayGetVcount()
|
||||
@ -289,25 +385,24 @@ const HLEFunction sceDisplay[] =
|
||||
{
|
||||
{0x0E20F177,&WrapU_UUU<sceDisplaySetMode>, "sceDisplaySetMode"},
|
||||
{0x289D82FE,sceDisplaySetFramebuf, "sceDisplaySetFramebuf"},
|
||||
{0xEEDA2E54,&WrapU_UUUI<sceDisplayGetFramebuf>,"sceDisplayGetFrameBuf"},
|
||||
{0x36CDFADE,sceDisplayWaitVblank, "sceDisplayWaitVblank"},
|
||||
{0x984C27E7,sceDisplayWaitVblankStart, "sceDisplayWaitVblankStart"},
|
||||
{0x40f1469c,sceDisplayWaitVblankStartMulti, "sceDisplayWaitVblankStartMulti"},
|
||||
{0x8EB9EC49,sceDisplayWaitVblankCB, "sceDisplayWaitVblankCB"},
|
||||
{0x46F186C3,sceDisplayWaitVblankStartCB, "sceDisplayWaitVblankStartCB"},
|
||||
{0x77ed8b3a,0,"sceDisplayWaitVblankStartMultiCB"},
|
||||
|
||||
{0x77ed8b3a,sceDisplayWaitVblankStartMultiCB,"sceDisplayWaitVblankStartMultiCB"},
|
||||
{0xdba6c4c4,&WrapF_V<sceDisplayGetFramePerSec>,"sceDisplayGetFramePerSec"},
|
||||
{0x773dd3a3,sceDisplayGetCurrentHcount,"sceDisplayGetCurrentHcount"},
|
||||
{0x210eab3a,sceDisplayGetAccumulatedHcount,"sceDisplayGetAccumulatedHcount"},
|
||||
{0x9C6EAAD7,sceDisplayGetVcount,"sceDisplayGetVcount"},
|
||||
{0x984C27E7,0,"sceDisplayWaitVblankStart"},
|
||||
{0xDEA197D4,0,"sceDisplayGetMode"},
|
||||
{0x7ED59BC4,0,"sceDisplaySetHoldMode"},
|
||||
{0xA544C486,0,"sceDisplaySetResumeMode"},
|
||||
{0x289D82FE,0,"sceDisplaySetFrameBuf"},
|
||||
{0xEEDA2E54,sceDisplayGetFramebuf,"sceDisplayGetFrameBuf"},
|
||||
{0xB4F378FA,0,"sceDisplayIsForeground"},
|
||||
{0x31C4BAA8,0,"sceDisplayGetBrightness"},
|
||||
{0x4D4E10EC,sceDisplayIsVblank,"sceDisplayIsVblank"},
|
||||
|
||||
};
|
||||
|
||||
void Register_sceDisplay()
|
||||
|
@ -20,3 +20,9 @@
|
||||
void __DisplayInit();
|
||||
|
||||
void Register_sceDisplay();
|
||||
|
||||
// will return true once after every end-of-frame.
|
||||
bool __DisplayFrameDone();
|
||||
|
||||
typedef void (*VblankCallback)();
|
||||
void __DisplayListenVblank(VblankCallback callback);
|
||||
|
@ -22,7 +22,7 @@ u32 sceDmacMemcpy(u32 dst, u32 src, u32 size)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
|
||||
// TODO: check the addresses.
|
||||
memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size);
|
||||
Memory::Memcpy(dst, Memory::GetPointer(src), size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
358
Core/HLE/sceFont.cpp
Normal file
358
Core/HLE/sceFont.cpp
Normal file
@ -0,0 +1,358 @@
|
||||
#include "sceFont.h"
|
||||
|
||||
#include "base/timeutil.h"
|
||||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
|
||||
#include "sceFont.h"
|
||||
|
||||
|
||||
typedef u32 FontLibraryHandle;
|
||||
typedef u32 FontHandle;
|
||||
|
||||
typedef struct {
|
||||
u32* userDataAddr;
|
||||
u32 numFonts;
|
||||
u32* cacheDataAddr;
|
||||
|
||||
// Driver callbacks.
|
||||
void *(*allocFuncAddr)(void *, u32);
|
||||
void (*freeFuncAddr )(void *, void *);
|
||||
u32* openFuncAddr;
|
||||
u32* closeFuncAddr;
|
||||
u32* readFuncAddr;
|
||||
u32* seekFuncAddr;
|
||||
u32* errorFuncAddr;
|
||||
u32* ioFinishFuncAddr;
|
||||
} FontNewLibParams;
|
||||
|
||||
typedef enum {
|
||||
FONT_FAMILY_SANS_SERIF = 1,
|
||||
FONT_FAMILY_SERIF = 2,
|
||||
} Family;
|
||||
|
||||
typedef enum {
|
||||
FONT_STYLE_REGULAR = 1,
|
||||
FONT_STYLE_ITALIC = 2,
|
||||
FONT_STYLE_BOLD = 5,
|
||||
FONT_STYLE_BOLD_ITALIC = 6,
|
||||
FONT_STYLE_DB = 103, // Demi-Bold / semi-bold
|
||||
} Style;
|
||||
|
||||
typedef enum {
|
||||
FONT_LANGUAGE_JAPANESE = 1,
|
||||
FONT_LANGUAGE_LATIN = 2,
|
||||
FONT_LANGUAGE_KOREAN = 3,
|
||||
} Language;
|
||||
|
||||
typedef struct {
|
||||
float fontH;
|
||||
float fontV;
|
||||
float fontHRes;
|
||||
float fontVRes;
|
||||
float fontWeight;
|
||||
u16 fontFamily;
|
||||
u16 fontStyle;
|
||||
// Check.
|
||||
u16 fontStyleSub;
|
||||
u16 fontLanguage;
|
||||
u16 fontRegion;
|
||||
u16 fontCountry;
|
||||
char fontName[64];
|
||||
char fontFileName[64];
|
||||
u32 fontAttributes;
|
||||
u32 fontExpire;
|
||||
} FontStyle;
|
||||
|
||||
typedef struct {
|
||||
// Glyph metrics (in 26.6 signed fixed-point).
|
||||
u32 maxGlyphWidthI;
|
||||
u32 maxGlyphHeightI;
|
||||
u32 maxGlyphAscenderI;
|
||||
u32 maxGlyphDescenderI;
|
||||
u32 maxGlyphLeftXI;
|
||||
u32 maxGlyphBaseYI;
|
||||
u32 minGlyphCenterXI;
|
||||
u32 maxGlyphTopYI;
|
||||
u32 maxGlyphAdvanceXI;
|
||||
u32 maxGlyphAdvanceYI;
|
||||
|
||||
// Glyph metrics (replicated as float).
|
||||
float maxGlyphWidthF;
|
||||
float maxGlyphHeightF;
|
||||
float maxGlyphAscenderF;
|
||||
float maxGlyphDescenderF;
|
||||
float maxGlyphLeftXF;
|
||||
float maxGlyphBaseYF;
|
||||
float minGlyphCenterXF;
|
||||
float maxGlyphTopYF;
|
||||
float maxGlyphAdvanceXF;
|
||||
float maxGlyphAdvanceYF;
|
||||
|
||||
// Bitmap dimensions.
|
||||
short maxGlyphWidth;
|
||||
short maxGlyphHeight;
|
||||
u32 charMapLength; // Number of elements in the font's charmap.
|
||||
u32 shadowMapLength; // Number of elements in the font's shadow charmap.
|
||||
|
||||
// Font style (used by font comparison functions).
|
||||
FontStyle fontStyle;
|
||||
|
||||
u8 BPP; // Font's BPP.
|
||||
u8 pad[3];
|
||||
} FontInfo;
|
||||
|
||||
typedef struct {
|
||||
u32 bitmapWidth;
|
||||
u32 bitmapHeight;
|
||||
u32 bitmapLeft;
|
||||
u32 bitmapTop;
|
||||
// Glyph metrics (in 26.6 signed fixed-point).
|
||||
u32 spf26Width;
|
||||
u32 spf26Height;
|
||||
s32 spf26Ascender;
|
||||
s32 spf26Descender;
|
||||
s32 spf26BearingHX;
|
||||
s32 spf26BearingHY;
|
||||
s32 spf26BearingVX;
|
||||
s32 spf26BearingVY;
|
||||
s32 spf26AdvanceH;
|
||||
s32 spf26AdvanceV;
|
||||
u8 pad[4];
|
||||
} CharInfo;
|
||||
|
||||
typedef enum {
|
||||
PSP_FONT_PIXELFORMAT_4 = 0,
|
||||
PSP_FONT_PIXELFORMAT_4_REV = 1,
|
||||
PSP_FONT_PIXELFORMAT_8 = 2,
|
||||
PSP_FONT_PIXELFORMAT_24 = 3,
|
||||
PSP_FONT_PIXELFORMAT_32 = 4
|
||||
} FontPixelFormat;
|
||||
|
||||
typedef struct {
|
||||
FontPixelFormat pixelFormat;
|
||||
s32 xPos64;
|
||||
s32 yPos64;
|
||||
u16 bufWidth;
|
||||
u16 bufHeight;
|
||||
u16 bytesPerLine;
|
||||
u16 pad;
|
||||
void *buffer;
|
||||
} GlyphImage;
|
||||
|
||||
FontNewLibParams fontLib;
|
||||
|
||||
u32 sceFontNewLib(u32 FontNewLibParamsPtr, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontNewLib %x, %x", FontNewLibParamsPtr, errorCodePtr);
|
||||
|
||||
if (Memory::IsValidAddress(FontNewLibParamsPtr)&&Memory::IsValidAddress(errorCodePtr))
|
||||
{
|
||||
Memory::Write_U32(0, errorCodePtr);
|
||||
Memory::ReadStruct(FontNewLibParamsPtr, &fontLib);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int sceFontDoneLib(u32 FontLibraryHandlePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontDoneLib %x", FontLibraryHandlePtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontDoneLib %x, %x, %x, %x", libHandle, index, mode, errorCodePtr);
|
||||
if (Memory::IsValidAddress(errorCodePtr))
|
||||
{
|
||||
Memory::Write_U32(0, errorCodePtr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontAddrPtr, u32 memoryFontLength, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontOpenUserMemory %x, %x, %x, %x", libHandle, memoryFontAddrPtr, memoryFontLength, errorCodePtr);
|
||||
if (Memory::IsValidAddress(errorCodePtr))
|
||||
{
|
||||
Memory::Write_U32(0, errorCodePtr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 sceFontOpenUserFile(u32 libHandle, u32 fileNamePtr, u32 mode, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontOpenUserFile %x, %x, %x, %x", libHandle, fileNamePtr, mode, errorCodePtr);
|
||||
if (Memory::IsValidAddress(errorCodePtr))
|
||||
{
|
||||
Memory::Write_U32(0, errorCodePtr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sceFontClose(u32 fontHandle)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontClose %x", fontHandle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sceFontGetNumFontList(u32 libHandle, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontGetNumFontList %x, %x", libHandle, errorCodePtr);
|
||||
if (Memory::IsValidAddress(errorCodePtr))
|
||||
{
|
||||
Memory::Write_U32(0, errorCodePtr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sceFontFindOptimumFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontFindOptimumFont %x, %x, %x", libHandlePtr, fontStylePtr, errorCodePtr);
|
||||
if (Memory::IsValidAddress(errorCodePtr))
|
||||
{
|
||||
Memory::Write_U32(0, errorCodePtr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sceFontFindFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontFindFont %x, %x, %x", libHandlePtr, fontStylePtr, errorCodePtr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontGetFontInfo %x, %x", fontHandle, fontInfoPtr);
|
||||
|
||||
FontInfo fi;
|
||||
memset (&fi, 0, sizeof(fi));
|
||||
if (Memory::IsValidAddress(fontInfoPtr))
|
||||
{
|
||||
fi.BPP =4;
|
||||
fi.charMapLength = 255;
|
||||
// fi.fontStyle =1;
|
||||
fi.maxGlyphAdvanceXF = 2.0;
|
||||
fi.maxGlyphAdvanceXI =2;
|
||||
fi.maxGlyphAdvanceYF = 2.0;
|
||||
fi.maxGlyphAdvanceYI = 32 << 6;
|
||||
fi.maxGlyphAscenderF =32 << 6;
|
||||
fi.maxGlyphAscenderI = 32 << 6;
|
||||
fi.maxGlyphBaseYF= 0.0;
|
||||
fi.maxGlyphBaseYI=0.0;
|
||||
fi.maxGlyphDescenderF =0;
|
||||
fi.maxGlyphDescenderI =0;
|
||||
fi.maxGlyphHeight = 32;
|
||||
fi.maxGlyphHeightF= 32;
|
||||
fi.maxGlyphHeightI = 32;
|
||||
fi.maxGlyphLeftXF= 0;
|
||||
fi.maxGlyphLeftXI = 0;
|
||||
fi.maxGlyphTopYF =0;
|
||||
fi.maxGlyphTopYI = 0;
|
||||
fi.maxGlyphWidth =32;
|
||||
fi.maxGlyphWidthF = 32;
|
||||
fi.maxGlyphWidthI= 32;
|
||||
fi.minGlyphCenterXF = 16;
|
||||
fi.minGlyphCenterXI= 16;
|
||||
fi.shadowMapLength=0;
|
||||
Memory::WriteStruct(fontInfoPtr, &fi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 unknown, u32 fontIndex)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontGetFontInfoByIndexNumber %x, %x, %x, %x", libHandle, fontInfoPtr, unknown, fontIndex);
|
||||
// clearly wrong..
|
||||
return sceFontGetFontInfo(libHandle, fontInfoPtr);
|
||||
|
||||
}
|
||||
|
||||
int sceFontGetCharInfo(u32 libHandler, u32 charCode, u32 charInfoPtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontGetCharInfo %x, %x, %x", libHandler, charCode, charInfoPtr);
|
||||
if (Memory::IsValidAddress(charInfoPtr))
|
||||
{
|
||||
CharInfo pspCharInfo;
|
||||
memset(&pspCharInfo, 0, sizeof(pspCharInfo));
|
||||
pspCharInfo.bitmapWidth = 32;
|
||||
pspCharInfo.bitmapHeight = 32;
|
||||
|
||||
pspCharInfo.spf26Width = pspCharInfo.bitmapWidth << 6;
|
||||
pspCharInfo.spf26Height = pspCharInfo.bitmapHeight << 6;
|
||||
pspCharInfo.spf26AdvanceH = pspCharInfo.bitmapWidth << 6;
|
||||
pspCharInfo.spf26AdvanceV = pspCharInfo.bitmapHeight << 6;
|
||||
Memory::WriteStruct(charInfoPtr, &pspCharInfo);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceFontGetCharGlyphImage(u32 libHandler, u32 charCode, u32 glyphImagePtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontGetCharGlyphImage %x, %x, %x (%c)", libHandler, charCode, glyphImagePtr, charCode);
|
||||
|
||||
int pixelFormat = Memory::Read_U32(glyphImagePtr);
|
||||
int xPos64 = Memory::Read_U32(glyphImagePtr+4);
|
||||
int yPos64 = Memory::Read_U32(glyphImagePtr+8);
|
||||
int bufWidth = Memory::Read_U16(glyphImagePtr+12);
|
||||
int bufHeight = Memory::Read_U16(glyphImagePtr+14);
|
||||
int bytesPerLine = Memory::Read_U16(glyphImagePtr+16);
|
||||
int buffer =Memory::Read_U32(glyphImagePtr+20);
|
||||
|
||||
Memory::Memset(buffer, 0x7F, bytesPerLine*bufHeight*pixelFormat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceFontGetCharGlyphImage_Clip(u32 libHandler, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip %x, %x, %x (%c)", libHandler, charCode, glyphImagePtr, charCode);
|
||||
//sceFontGetCharGlyphImage(libHandler, charCode, glyphImagePtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const HLEFunction sceLibFont[] =
|
||||
{
|
||||
{0x67f17ed7, WrapU_UU<sceFontNewLib>, "sceFontNewLib"},
|
||||
{0x574b6fbc, WrapI_U<sceFontDoneLib>, "sceFontDoneLib"},
|
||||
{0x48293280, 0, "sceFontSetResolution"},
|
||||
{0x27f6e642, WrapI_UU<sceFontGetNumFontList>, "sceFontGetNumFontList"},
|
||||
{0xbc75d85b, 0, "sceFontGetFontList"},
|
||||
{0x099ef33c, WrapI_UUU<sceFontFindOptimumFont>, "sceFontFindOptimumFont"},
|
||||
{0x681e61a7, WrapI_UUU<sceFontFindFont>, "sceFontFindFont"},
|
||||
{0x2f67356a, 0, "sceFontCalcMemorySize"},
|
||||
{0x5333322d, WrapI_UUUU<sceFontGetFontInfoByIndexNumber>, "sceFontGetFontInfoByIndexNumber"},
|
||||
{0xa834319d, WrapU_UUUU<sceFontOpen>, "sceFontOpen"},
|
||||
{0x57fcb733, WrapU_UUUU<sceFontOpenUserFile>, "sceFontOpenUserFile"},
|
||||
{0xbb8e7fe6, WrapU_UUUU<sceFontOpenUserMemory>, "sceFontOpenUserMemory"},
|
||||
{0x3aea8cb6, WrapI_U<sceFontClose>, "sceFontClose"},
|
||||
{0x0da7535e, WrapI_UU<sceFontGetFontInfo>, "sceFontGetFontInfo"},
|
||||
{0xdcc80c2f, WrapI_UUU<sceFontGetCharInfo>, "sceFontGetCharInfo"},
|
||||
{0x5c3e4a9e, 0, "sceFontGetCharImageRect"},
|
||||
{0x980f4895, WrapI_UUU<sceFontGetCharGlyphImage>, "sceFontGetCharGlyphImage"},
|
||||
{0xca1e6945, WrapI_UUUIIII<sceFontGetCharGlyphImage_Clip>, "sceFontGetCharGlyphImage_Clip"},
|
||||
{0x74b21701, 0, "sceFontPixelToPointH"},
|
||||
{0xf8f0752e, 0, "sceFontPixelToPointV"},
|
||||
{0x472694cd, 0, "sceFontPointToPixelH"},
|
||||
{0x3c4b7e82, 0, "sceFontPointToPixelV"},
|
||||
{0xee232411, 0, "sceFontSetAltCharacterCode"},
|
||||
{0xaa3de7b5, 0, "sceFontGetShadowInfo"},
|
||||
{0x48b06520, 0, "sceFontGetShadowImageRect"},
|
||||
{0x568be516, 0, "sceFontGetShadowGlyphImage"},
|
||||
{0x5dcf6858, 0, "sceFontGetShadowGlyphImage_Clip"},
|
||||
{0x02d7f94b, 0, "sceFontFlush"},
|
||||
|
||||
};
|
||||
void Register_sceFont()
|
||||
{
|
||||
RegisterModule("sceLibFont", ARRAY_SIZE(sceLibFont), sceLibFont);
|
||||
}
|
||||
|
3
Core/HLE/sceFont.h
Normal file
3
Core/HLE/sceFont.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void Register_sceFont();
|
@ -28,7 +28,6 @@
|
||||
// TODO: This doesn't really belong here
|
||||
static int state;
|
||||
|
||||
|
||||
void __GeInit()
|
||||
{
|
||||
state = 0;
|
||||
@ -42,26 +41,26 @@ void __GeShutdown()
|
||||
// The GE is implemented wrong - it should be parallel to the CPU execution instead of
|
||||
// synchronous.
|
||||
|
||||
|
||||
|
||||
u32 sceGeEdramGetAddr()
|
||||
{
|
||||
u32 retVal = 0x04000000;
|
||||
DEBUG_LOG(HLE,"%08x = sceGeEdramGetAddr",retVal);
|
||||
DEBUG_LOG(HLE, "%08x = sceGeEdramGetAddr", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
u32 sceGeEdramGetSize()
|
||||
{
|
||||
u32 retVal = 0x00200000;
|
||||
DEBUG_LOG(HLE,"%08x = sceGeEdramGetSize()",retVal);
|
||||
DEBUG_LOG(HLE, "%08x = sceGeEdramGetSize()", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr)
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId,
|
||||
u32 optParamAddr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceGeListEnQueue(addr=%08x, stall=%08x, cbid=%08x, param=%08x)",
|
||||
listAddress,stallAddress,callbackId,optParamAddr);
|
||||
DEBUG_LOG(HLE,
|
||||
"sceGeListEnQueue(addr=%08x, stall=%08x, cbid=%08x, param=%08x)",
|
||||
listAddress, stallAddress, callbackId, optParamAddr);
|
||||
//if (!stallAddress)
|
||||
// stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress);
|
||||
@ -71,75 +70,84 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optP
|
||||
else
|
||||
state = SCE_GE_LIST_COMPLETED;
|
||||
|
||||
DEBUG_LOG(HLE,"List enqueued.");
|
||||
DEBUG_LOG(HLE, "List %i enqueued.", listID);
|
||||
//return display list ID
|
||||
return listID;
|
||||
}
|
||||
|
||||
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr)
|
||||
u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId,
|
||||
u32 optParamAddr)
|
||||
{
|
||||
if (!stallAddress)
|
||||
stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress,stallAddress);
|
||||
DEBUG_LOG(HLE,
|
||||
"sceGeListEnQueueHead(addr=%08x, stall=%08x, cbid=%08x, param=%08x)",
|
||||
listAddress, stallAddress, callbackId, optParamAddr);
|
||||
//if (!stallAddress)
|
||||
// stallAddress = listAddress;
|
||||
u32 listID = gpu->EnqueueList(listAddress, stallAddress);
|
||||
// HACKY
|
||||
if (listID)
|
||||
state = SCE_GE_LIST_STALLING;
|
||||
else
|
||||
state = SCE_GE_LIST_COMPLETED;
|
||||
|
||||
DEBUG_LOG(HLE,"%i=sceGeListEnQueueHead(addr=%08x, stall=%08x, cbid=%08x, param=%08x)",
|
||||
listID, listAddress,stallAddress,callbackId,optParamAddr);
|
||||
DEBUG_LOG(HLE,"List enqueued.");
|
||||
DEBUG_LOG(HLE, "List %i enqueued.", listID);
|
||||
//return display list ID
|
||||
return listID;
|
||||
}
|
||||
|
||||
void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
|
||||
void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceGeListUpdateStallAddr(dlid=%i,stalladdr=%08x)",
|
||||
displayListID,stallAddress);
|
||||
DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i,stalladdr=%08x)",
|
||||
displayListID, stallAddress);
|
||||
|
||||
gpu->UpdateStall(displayListID, stallAddress);
|
||||
}
|
||||
|
||||
void sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return
|
||||
int sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceGeListSync(dlid=%08x, mode=%08x)", displayListID,mode);
|
||||
DEBUG_LOG(HLE, "sceGeListSync(dlid=%08x, mode=%08x)", displayListID, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceGeDrawSync(u32 mode)
|
||||
{
|
||||
//wait/check entire drawing state
|
||||
DEBUG_LOG(HLE,"FAKE sceGeDrawSync(mode=%d) (0=wait for completion)",mode);
|
||||
DEBUG_LOG(HLE, "FAKE sceGeDrawSync(mode=%d) (0=wait for completion)",
|
||||
mode);
|
||||
gpu->DrawSync(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGeBreak()
|
||||
{
|
||||
u32 mode = PARAM(0); //0 : current dlist 1: all drawing
|
||||
ERROR_LOG(HLE,"UNIMPL sceGeBreak(mode=%d)",mode);
|
||||
}
|
||||
|
||||
void sceGeContinue()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceGeContinue");
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeContinue");
|
||||
// no arguments
|
||||
}
|
||||
|
||||
void sceGeBreak(u32 mode)
|
||||
{
|
||||
//mode => 0 : current dlist 1: all drawing
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeBreak(mode=%d)", mode);
|
||||
}
|
||||
|
||||
|
||||
u32 sceGeSetCallback(u32 structAddr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceGeSetCallback(struct=%08x)", structAddr);
|
||||
DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr);
|
||||
|
||||
PspGeCallbackData ge_callback_data;
|
||||
Memory::ReadStruct(structAddr, &ge_callback_data);
|
||||
|
||||
if (ge_callback_data.finish_func) {
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, ge_callback_data.finish_func, ge_callback_data.finish_arg);
|
||||
if (ge_callback_data.finish_func)
|
||||
{
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH,
|
||||
ge_callback_data.finish_func, ge_callback_data.finish_arg);
|
||||
sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH);
|
||||
}
|
||||
if (ge_callback_data.signal_func) {
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, ge_callback_data.signal_func, ge_callback_data.signal_arg);
|
||||
if (ge_callback_data.signal_func)
|
||||
{
|
||||
sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL,
|
||||
ge_callback_data.signal_func, ge_callback_data.signal_arg);
|
||||
sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL);
|
||||
}
|
||||
|
||||
@ -147,36 +155,66 @@ u32 sceGeSetCallback(u32 structAddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGeUnsetCallback(u32 cbID)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceGeUnsetCallback(cbid=%08x)", cbID);
|
||||
void sceGeUnsetCallback(u32 cbID) {
|
||||
DEBUG_LOG(HLE, "sceGeUnsetCallback(cbid=%08x)", cbID);
|
||||
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH);
|
||||
sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL);
|
||||
}
|
||||
|
||||
void sceGeSaveContext()
|
||||
// Points to 512 32-bit words, where we can probably layout the context however we want
|
||||
// unless some insane game pokes it and relies on it...
|
||||
u32 sceGeSaveContext(u32 ctxAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceGeSaveContext()");
|
||||
DEBUG_LOG(HLE, "sceGeSaveContext(%08x)", ctxAddr);
|
||||
|
||||
if (sizeof(gstate) > 512 * 4)
|
||||
{
|
||||
ERROR_LOG(HLE, "AARGH! sizeof(gstate) has grown too large!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Let's just dump gstate.
|
||||
if (Memory::IsValidAddress(ctxAddr))
|
||||
{
|
||||
Memory::WriteStruct(ctxAddr, &gstate);
|
||||
}
|
||||
|
||||
// This action should probably be pushed to the end of the queue of the display thread -
|
||||
// when we have one.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGeRestoreContext()
|
||||
u32 sceGeRestoreContext(u32 ctxAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceGeRestoreContext()");
|
||||
DEBUG_LOG(HLE, "sceGeRestoreContext(%08x)", ctxAddr);
|
||||
|
||||
if (sizeof(gstate) > 512 * 4)
|
||||
{
|
||||
ERROR_LOG(HLE, "AARGH! sizeof(gstate) has grown too large!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Memory::IsValidAddress(ctxAddr))
|
||||
{
|
||||
Memory::ReadStruct(ctxAddr, &gstate);
|
||||
}
|
||||
ReapplyGfxState();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceGeGetMtx()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceGeGetMtx()");
|
||||
ERROR_LOG(HLE, "UNIMPL sceGeGetMtx()");
|
||||
}
|
||||
|
||||
void sceGeEdramSetAddrTranslation()
|
||||
u32 sceGeEdramSetAddrTranslation(int new_size)
|
||||
{
|
||||
int new_size = PARAM(0);
|
||||
INFO_LOG(HLE,"sceGeEdramSetAddrTranslation(%i)", new_size);
|
||||
INFO_LOG(HLE, "sceGeEdramSetAddrTranslation(%i)", new_size);
|
||||
static int EDRamWidth;
|
||||
int last = EDRamWidth;
|
||||
EDRamWidth = new_size;
|
||||
RETURN(last);
|
||||
return last;
|
||||
}
|
||||
|
||||
const HLEFunction sceGe_user[] =
|
||||
@ -185,18 +223,18 @@ const HLEFunction sceGe_user[] =
|
||||
{0xAB49E76A,&WrapU_UUUU<sceGeListEnQueue>, "sceGeListEnQueue"},
|
||||
{0x1C0D95A6,&WrapU_UUUU<sceGeListEnQueueHead>, "sceGeListEnQueueHead"},
|
||||
{0xE0D68148,&WrapV_UU<sceGeListUpdateStallAddr>, "sceGeListUpdateStallAddr"},
|
||||
{0x03444EB4,&WrapV_UU<sceGeListSync>, "sceGeListSync"},
|
||||
{0x03444EB4,&WrapI_UU<sceGeListSync>, "sceGeListSync"},
|
||||
{0xB287BD61,&WrapU_U<sceGeDrawSync>, "sceGeDrawSync"},
|
||||
{0xB448EC0D,sceGeBreak, "sceGeBreak"},
|
||||
{0xB448EC0D,&WrapV_U<sceGeBreak>, "sceGeBreak"},
|
||||
{0x4C06E472,sceGeContinue, "sceGeContinue"},
|
||||
{0xA4FC06A4,&WrapU_U<sceGeSetCallback>, "sceGeSetCallback"},
|
||||
{0x05DB22CE,&WrapV_U<sceGeUnsetCallback>, "sceGeUnsetCallback"},
|
||||
{0x1F6752AD,&WrapU_V<sceGeEdramGetSize>, "sceGeEdramGetSize"},
|
||||
{0xB77905EA,&sceGeEdramSetAddrTranslation,"sceGeEdramSetAddrTranslation"},
|
||||
{0xB77905EA,&WrapU_I<sceGeEdramSetAddrTranslation>,"sceGeEdramSetAddrTranslation"},
|
||||
{0xDC93CFEF,0,"sceGeGetCmd"},
|
||||
{0x57C8945B,&sceGeGetMtx,"sceGeGetMtx"},
|
||||
{0x438A385A,0,"sceGeSaveContext"},
|
||||
{0x0BF608FB,0,"sceGeRestoreContext"},
|
||||
{0x438A385A,&WrapU_U<sceGeSaveContext>,"sceGeSaveContext"},
|
||||
{0x0BF608FB,&WrapU_U<sceGeRestoreContext>,"sceGeRestoreContext"},
|
||||
{0x5FB86AB0,0,"sceGeListDeQueue"},
|
||||
};
|
||||
|
||||
|
@ -38,3 +38,10 @@ void Register_sceGe_user();
|
||||
|
||||
void __GeInit();
|
||||
void __GeShutdown();
|
||||
|
||||
|
||||
// Export functions for use by Util/PPGe
|
||||
u32 sceGeRestoreContext(u32 ctxAddr);
|
||||
u32 sceGeSaveContext(u32 ctxAddr);
|
||||
|
||||
u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr);
|
||||
|
@ -65,9 +65,16 @@ const HLEFunction sceHttp[] =
|
||||
{0xae948fee,0,"sceHttpDisableAuth"},
|
||||
{0xccbd167a,0,"sceHttpDisableCache"},
|
||||
{0xd081ec8f,0,"sceHttpGetNetworkErrno"},
|
||||
{0x76d1363b,0,"sceHttp_76d1363b"},
|
||||
{0x87797bdd,0,"sceHttp_87797bdd"},
|
||||
{0xf1657b22,0,"sceHttp_f1657b22"},
|
||||
{0x76d1363b,0,"sceHttpSaveSystemCookie"},
|
||||
{0x87797bdd,0,"sceHttpsLoadDefaultCert"},
|
||||
{0xf1657b22,0,"sceHttpLoadSystemCookie"},
|
||||
{0x9B1F1F36,0,"sceHttpCreateTemplate"},
|
||||
{0xB509B09E,0,"sceHttpCreateRequestWithURL"},
|
||||
{0xCDF8ECB9,0,"sceHttpCreateConnectionWithURL"},
|
||||
{0x1F0FC3E3,0,"sceHttpSetRecvTimeOut"},
|
||||
{0xDB266CCF,0,"sceHttpGetAllHeader"},
|
||||
{0x68AB0F86,0,"sceHttpsInitWithPath"},
|
||||
{0xB3FAF831,0,"sceHttpsDisableOption"},
|
||||
};
|
||||
|
||||
void Register_sceHttp()
|
||||
|
@ -39,7 +39,7 @@ static u32 iButtonValue = 0;
|
||||
|
||||
u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"%i=sceImposeGetBatteryIconStatus(%08x, %08x)", chargingPtr, iconStatusPtr);
|
||||
DEBUG_LOG(HLE, "sceImposeGetBatteryIconStatus(%08x, %08x)", chargingPtr, iconStatusPtr);
|
||||
if (Memory::IsValidAddress(chargingPtr))
|
||||
Memory::Write_U32(1, chargingPtr);
|
||||
if (Memory::IsValidAddress(iconStatusPtr))
|
||||
@ -49,7 +49,7 @@ u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr)
|
||||
|
||||
u32 sceImposeSetLanguageMode(u32 languageVal, u32 buttonVal)
|
||||
{
|
||||
DEBUG_LOG(HLE,"%i=sceImposeSetLanguageMode(%08x, %08x)", languageVal, buttonVal);
|
||||
DEBUG_LOG(HLE, "sceImposeSetLanguageMode(%08x, %08x)", languageVal, buttonVal);
|
||||
iLanguage = languageVal;
|
||||
iButtonValue = buttonVal;
|
||||
return 0;
|
||||
@ -57,7 +57,7 @@ u32 sceImposeSetLanguageMode(u32 languageVal, u32 buttonVal)
|
||||
|
||||
u32 sceImposeGetLanguageMode(u32 languagePtr, u32 btnPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"%i=sceImposeGetLanguageMode(%08x, %08x)", languagePtr, btnPtr);
|
||||
DEBUG_LOG(HLE, "sceImposeGetLanguageMode(%08x, %08x)", languagePtr, btnPtr);
|
||||
if (Memory::IsValidAddress(languagePtr))
|
||||
Memory::Write_U32(iLanguage, languagePtr);
|
||||
if (Memory::IsValidAddress(btnPtr))
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
||||
|
||||
#include "__sceAudio.h"
|
||||
#include "sceAudio.h"
|
||||
#include "sceCtrl.h"
|
||||
#include "sceDisplay.h"
|
||||
#include "sceGe.h"
|
||||
#include "sceIo.h"
|
||||
@ -49,6 +50,9 @@
|
||||
#include "scePower.h"
|
||||
#include "sceUtility.h"
|
||||
#include "sceUmd.h"
|
||||
#include "sceSsl.h"
|
||||
|
||||
#include "../Util/PPGeDraw.h"
|
||||
|
||||
extern MetaFileSystem pspFileSystem;
|
||||
|
||||
@ -80,6 +84,11 @@ void __KernelInit()
|
||||
__UtilityInit();
|
||||
__UmdInit();
|
||||
__MpegInit(PSP_CoreParameter().useMediaEngine);
|
||||
__CtrlInit();
|
||||
__SslInit();
|
||||
|
||||
// "Internal" PSP libraries
|
||||
__PPGeInit();
|
||||
|
||||
kernelRunning = true;
|
||||
INFO_LOG(HLE, "Kernel initialized.");
|
||||
@ -97,6 +106,8 @@ void __KernelShutdown()
|
||||
kernelObjects.Clear();
|
||||
|
||||
__MpegShutdown();
|
||||
__PPGeShutdown();
|
||||
|
||||
__GeShutdown();
|
||||
__AudioShutdown();
|
||||
__IoShutdown();
|
||||
@ -147,12 +158,6 @@ void sceKernelDevkitVersion()
|
||||
RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DEBUG
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void sceKernelRegisterKprintfHandler()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelRegisterKprintfHandler()");
|
||||
@ -177,21 +182,19 @@ void sceKernelGetGPI()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
// Don't even log these, they're spammy and we probably won't
|
||||
// need to emulate them.
|
||||
void sceKernelDcacheWritebackAll()
|
||||
{
|
||||
//RETURN(0);
|
||||
}
|
||||
void sceKernelDcacheWritebackRange()
|
||||
{
|
||||
//RETURN(0);
|
||||
}
|
||||
void sceKernelDcacheWritebackInvalidateRange()
|
||||
{
|
||||
//RETURN(0);
|
||||
}
|
||||
void sceKernelDcacheWritebackInvalidateAll()
|
||||
{
|
||||
// RETURN(0)
|
||||
}
|
||||
|
||||
KernelObjectPool kernelObjects;
|
||||
@ -201,13 +204,15 @@ KernelObjectPool::KernelObjectPool()
|
||||
memset(occupied, 0, sizeof(bool)*maxCount);
|
||||
}
|
||||
|
||||
SceUID KernelObjectPool::Create(KernelObject *obj)
|
||||
SceUID KernelObjectPool::Create(KernelObject *obj, int rangeBottom, int rangeTop)
|
||||
{
|
||||
for (int i=0; i<maxCount; i++)
|
||||
if (rangeTop > maxCount)
|
||||
rangeTop = maxCount;
|
||||
for (int i = rangeBottom; i < rangeTop; i++)
|
||||
{
|
||||
if (!occupied[i])
|
||||
{
|
||||
occupied[i]=true;
|
||||
occupied[i] = true;
|
||||
pool[i] = obj;
|
||||
pool[i]->uid = i + handleOffset;
|
||||
return i + handleOffset;
|
||||
@ -324,37 +329,36 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x812346E4,&WrapU_IU<sceKernelClearEventFlag>, "sceKernelClearEventFlag"},
|
||||
{0xEF9E4C70,&WrapU_I<sceKernelDeleteEventFlag>, "sceKernelDeleteEventFlag"},
|
||||
{0x1fb15a32,&WrapU_IU<sceKernelSetEventFlag>, "sceKernelSetEventFlag"},
|
||||
{0x402FCF22,&WrapV_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
|
||||
{0x328C546A,&WrapV_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
|
||||
{0x402FCF22,&WrapI_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
|
||||
{0x328C546A,&WrapI_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
|
||||
{0x30FD48F0,&WrapI_IUUUU<sceKernelPollEventFlag>, "sceKernelPollEventFlag"},
|
||||
{0xCD203292,&WrapU_V<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
|
||||
{0xCD203292,&WrapU_IUU<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
|
||||
{0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"},
|
||||
|
||||
{0x8FFDF9A2,&WrapV_IIU<sceKernelCancelSema>, "sceKernelCancelSema"},
|
||||
{0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"},
|
||||
{0x28b6489c,&WrapV_I<sceKernelDeleteSema>, "sceKernelDeleteSema"},
|
||||
{0x58b1f937,&WrapI_II<sceKernelPollSema>, "sceKernelPollSema"},
|
||||
{0xBC6FEBC5,&WrapI_IU<sceKernelReferSemaStatus>, "sceKernelReferSemaStatus"},
|
||||
{0x3F53E640,&WrapV_II<sceKernelSignalSema>, "sceKernelSignalSema"},
|
||||
{0x4E3A1105,&WrapV_IIU<sceKernelWaitSema>, "sceKernelWaitSema"},
|
||||
{0x6d212bac,&WrapV_IIU<sceKernelWaitSemaCB>, "sceKernelWaitSemaCB"},
|
||||
|
||||
{0x60107536,0,"sceKernelDeleteLwMutex"},
|
||||
{0x19CFF145,0,"sceKernelCreateLwMutex"},
|
||||
{0xf8170fbe,&WrapU_U<sceKernelDeleteMutex>,"sceKernelDeleteMutex"},
|
||||
{0xB011B11F,&WrapU_UUU<sceKernelLockMutex>,"sceKernelLockMutex"},
|
||||
{0x5bf4dd27,&WrapU_UUU<sceKernelLockMutexCB>,"sceKernelLockMutexCB"},
|
||||
{0x6b30100f,&WrapU_UU<sceKernelUnlockMutex>,"sceKernelUnlockMutex"},
|
||||
{0xb7d098c6,&WrapU_CUU<sceKernelCreateMutex>,"sceKernelCreateMutex"},
|
||||
{0x0DDCD2C9, 0, "sceKernelTryLockMutex"},
|
||||
{0x8FFDF9A2,&WrapI_IIU<sceKernelCancelSema>, "sceKernelCancelSema"},
|
||||
{0xD6DA4BA1,&WrapI_CUIIU<sceKernelCreateSema>, "sceKernelCreateSema"},
|
||||
{0x28b6489c,&WrapI_I<sceKernelDeleteSema>, "sceKernelDeleteSema"},
|
||||
{0x58b1f937,&WrapI_II<sceKernelPollSema>, "sceKernelPollSema"},
|
||||
{0xBC6FEBC5,&WrapI_IU<sceKernelReferSemaStatus>, "sceKernelReferSemaStatus"},
|
||||
{0x3F53E640,&WrapI_II<sceKernelSignalSema>, "sceKernelSignalSema"},
|
||||
{0x4E3A1105,&WrapI_IIU<sceKernelWaitSema>, "sceKernelWaitSema"},
|
||||
{0x6d212bac,&WrapI_IIU<sceKernelWaitSemaCB>, "sceKernelWaitSemaCB"},
|
||||
|
||||
{0x60107536,&WrapI_U<sceKernelDeleteLwMutex>, "sceKernelDeleteLwMutex"},
|
||||
{0x19CFF145,&WrapI_UCUIU<sceKernelCreateLwMutex>, "sceKernelCreateLwMutex"},
|
||||
{0xf8170fbe,&WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
|
||||
{0xB011B11F,&WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex"},
|
||||
{0x5bf4dd27,&WrapI_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB"},
|
||||
{0x6b30100f,&WrapI_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"},
|
||||
{0xb7d098c6,&WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
|
||||
{0x0DDCD2C9,&WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
|
||||
// NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp.
|
||||
|
||||
{0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"},
|
||||
{0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"},
|
||||
{0x71bc9871,sceKernelChangeThreadPriority,"sceKernelChangeThreadPriority"},
|
||||
{0x446D8DE6,sceKernelCreateThread,"sceKernelCreateThread"},
|
||||
{0x9fa03cd3,sceKernelDeleteThread,"sceKernelDeleteThread"},
|
||||
{0x446D8DE6,WrapI_CUUIUU<sceKernelCreateThread>,"sceKernelCreateThread"},
|
||||
{0x9fa03cd3,WrapI_I<sceKernelDeleteThread>,"sceKernelDeleteThread"},
|
||||
{0xBD123D9E,0,"sceKernelDelaySysClockThread"},
|
||||
{0x1181E963,0,"sceKernelDelaySysClockThreadCB"},
|
||||
{0xceadeb47,sceKernelDelayThread,"sceKernelDelayThread"},
|
||||
@ -374,10 +378,10 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x912354a7,sceKernelRotateThreadReadyQueue,"sceKernelRotateThreadReadyQueue"},
|
||||
{0x9ACE131E,sceKernelSleepThread,"sceKernelSleepThread"},
|
||||
{0x82826f70,sceKernelSleepThreadCB,"sceKernelSleepThreadCB"},
|
||||
{0xF475845D,&WrapU_V<sceKernelStartThread>,"sceKernelStartThread"},
|
||||
{0xF475845D,&WrapI_IUU<sceKernelStartThread>,"sceKernelStartThread"},
|
||||
{0x9944f31f,sceKernelSuspendThread,"sceKernelSuspendThread"},
|
||||
{0x616403ba,0,"sceKernelTerminateThread"},
|
||||
{0x383f7bcc,sceKernelTerminateDeleteThread,"sceKernelTerminateDeleteThread"},
|
||||
{0x616403ba,WrapI_U<sceKernelTerminateThread>,"sceKernelTerminateThread"},
|
||||
{0x383f7bcc,WrapI_I<sceKernelTerminateDeleteThread>,"sceKernelTerminateDeleteThread"},
|
||||
{0x840E8133,sceKernelWaitThreadEndCB,"sceKernelWaitThreadEndCB"},
|
||||
{0xd13bde95,sceKernelCheckThreadStack,"sceKernelCheckThreadStack"},
|
||||
|
||||
@ -415,7 +419,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
|
||||
{0xba6b92e2,sceKernelSysClock2USec,"sceKernelSysClock2USec"},
|
||||
{0x110DEC9A,0,"sceKernelUSec2SysClock"},
|
||||
{0xC8CD158C,0,"sceKernelUSec2SysClockWide"},
|
||||
{0xC8CD158C,WrapU_U<sceKernelUSec2SysClockWide>,"sceKernelUSec2SysClockWide"},
|
||||
{0xE1619D7C,sceKernelSysClock2USecWide,"sceKernelSysClock2USecWide"},
|
||||
|
||||
{0x110dec9a,sceKernelUSec2SysClock,"sceKernelUSec2SysClock"},
|
||||
@ -434,11 +438,11 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x2A3D44FF,sceKernelGetCallbackCount,"sceKernelGetCallbackCount"},
|
||||
{0x730ED8BC,sceKernelReferCallbackStatus,"sceKernelReferCallbackStatus"},
|
||||
|
||||
{0x8125221D,&WrapU_CIUIU<sceKernelCreateMbx>,"sceKernelCreateMbx"},
|
||||
{0x8125221D,&WrapI_CUU<sceKernelCreateMbx>,"sceKernelCreateMbx"},
|
||||
{0x86255ADA,&WrapI_I<sceKernelDeleteMbx>,"sceKernelDeleteMbx"},
|
||||
{0xE9B3061E,&WrapV_IU<sceKernelSendMbx>,"sceKernelSendMbx"},
|
||||
{0x18260574,&WrapV_IUU<sceKernelReceiveMbx>,"sceKernelReceiveMbx"},
|
||||
{0xF3986382,&WrapV_IUU<sceKernelReceiveMbxCB>,"sceKernelReceiveMbxCB"},
|
||||
{0xE9B3061E,&WrapI_IU<sceKernelSendMbx>,"sceKernelSendMbx"},
|
||||
{0x18260574,&WrapI_IUU<sceKernelReceiveMbx>,"sceKernelReceiveMbx"},
|
||||
{0xF3986382,&WrapI_IUU<sceKernelReceiveMbxCB>,"sceKernelReceiveMbxCB"},
|
||||
{0x0D81716A,&WrapI_IU<sceKernelPollMbx>,"sceKernelPollMbx"},
|
||||
{0x87D4DD36,&WrapI_IU<sceKernelCancelReceiveMbx>,"sceKernelCancelReceiveMbx"},
|
||||
{0xA8E8C846,&WrapI_IU<sceKernelReferMbxStatus>,"sceKernelReferMbxStatus"},
|
||||
|
@ -20,205 +20,228 @@
|
||||
#include "../../Globals.h"
|
||||
#include <cstring>
|
||||
|
||||
enum
|
||||
enum
|
||||
{
|
||||
SCE_KERNEL_ERROR_OK = 0,
|
||||
SCE_KERNEL_ERROR_ERROR = 0x80020001,
|
||||
SCE_KERNEL_ERROR_NOTIMP = 0x80020002,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_EXPCODE = 0x80020032,
|
||||
SCE_KERNEL_ERROR_EXPHANDLER_NOUSE = 0x80020033,
|
||||
SCE_KERNEL_ERROR_EXPHANDLER_USED = 0x80020034,
|
||||
SCE_KERNEL_ERROR_SYCALLTABLE_NOUSED = 0x80020035,
|
||||
SCE_KERNEL_ERROR_SYCALLTABLE_USED = 0x80020036,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SYSCALLTABLE = 0x80020037,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PRIMARY_SYSCALL_NUMBER = 0x80020038,
|
||||
SCE_KERNEL_ERROR_PRIMARY_SYSCALL_NUMBER_INUSE = 0x80020039,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = 0x80020064,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = 0x80020065,
|
||||
SCE_KERNEL_ERROR_CPUDI = 0x80020066,
|
||||
SCE_KERNEL_ERROR_FOUND_HANDLER = 0x80020067,
|
||||
SCE_KERNEL_ERROR_NOTFOUND_HANDLER = 0x80020068,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_INTRLEVEL = 0x80020069,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ADDRESS = 0x8002006a,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = 0x8002006b,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_STACK_ADDRESS = 0x8002006c,
|
||||
SCE_KERNEL_ERROR_ALREADY_STACK_SET = 0x8002006d,
|
||||
SCE_KERNEL_ERROR_NO_TIMER = 0x80020096,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_TIMERID = 0x80020097,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SOURCE = 0x80020098,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PRESCALE = 0x80020099,
|
||||
SCE_KERNEL_ERROR_TIMER_BUSY = 0x8002009a,
|
||||
SCE_KERNEL_ERROR_TIMER_NOT_SETUP = 0x8002009b,
|
||||
SCE_KERNEL_ERROR_TIMER_NOT_INUSE = 0x8002009c,
|
||||
SCE_KERNEL_ERROR_UNIT_USED = 0x800200a0,
|
||||
SCE_KERNEL_ERROR_UNIT_NOUSE = 0x800200a1,
|
||||
SCE_KERNEL_ERROR_NO_ROMDIR = 0x800200a2,
|
||||
SCE_KERNEL_ERROR_IDTYPE_EXIST = 0x800200c8,
|
||||
SCE_KERNEL_ERROR_IDTYPE_NOT_EXIST = 0x800200c9,
|
||||
SCE_KERNEL_ERROR_IDTYPE_NOT_EMPTY = 0x800200ca,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_UID = 0x800200cb,
|
||||
SCE_KERNEL_ERROR_UNMATCH_UID_TYPE = 0x800200cc,
|
||||
SCE_KERNEL_ERROR_ID_NOT_EXIST = 0x800200cd,
|
||||
SCE_KERNEL_ERROR_NOT_FOUND_UIDFUNC = 0x800200ce,
|
||||
SCE_KERNEL_ERROR_UID_ALREADY_HOLDER = 0x800200cf,
|
||||
SCE_KERNEL_ERROR_UID_NOT_HOLDER = 0x800200d0,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PERM = 0x800200d1,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT = 0x800200d2,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ADDR = 0x800200d3,
|
||||
SCE_KERNEL_ERROR_OUT_OF_RANGE = 0x800200d4,
|
||||
SCE_KERNEL_ERROR_MEM_RANGE_OVERLAP = 0x800200d5,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PARTITION = 0x800200d6,
|
||||
SCE_KERNEL_ERROR_PARTITION_INUSE = 0x800200d7,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE = 0x800200d8,
|
||||
SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED = 0x800200d9,
|
||||
SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_LOCKED = 0x800200da,
|
||||
SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_FAILED = 0x800200db,
|
||||
SCE_KERNEL_ERROR_HEAPBLOCK_ALLOC_FAILED = 0x800200dc,
|
||||
SCE_KERNEL_ERROR_HEAP_ALLOC_FAILED = 0x800200dd,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_CHUNK_ID = 0x800200de,
|
||||
SCE_KERNEL_ERROR_NOCHUNK = 0x800200df,
|
||||
SCE_KERNEL_ERROR_NO_FREECHUNK = 0x800200e0,
|
||||
SCE_KERNEL_ERROR_LINKERR = 0x8002012c,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e,
|
||||
SCE_KERNEL_ERROR_NOFILE = 0x8002012f,
|
||||
SCE_KERNEL_ERROR_FILEERR = 0x80020130,
|
||||
SCE_KERNEL_ERROR_MEMINUSE = 0x80020131,
|
||||
SCE_KERNEL_ERROR_PARTITION_MISMATCH = 0x80020132,
|
||||
SCE_KERNEL_ERROR_ALREADY_STARTED = 0x80020133,
|
||||
SCE_KERNEL_ERROR_NOT_STARTED = 0x80020134,
|
||||
SCE_KERNEL_ERROR_ALREADY_STOPPED = 0x80020135,
|
||||
SCE_KERNEL_ERROR_CAN_NOT_STOP = 0x80020136,
|
||||
SCE_KERNEL_ERROR_NOT_STOPPED = 0x80020137,
|
||||
SCE_KERNEL_ERROR_NOT_REMOVABLE = 0x80020138,
|
||||
SCE_KERNEL_ERROR_EXCLUSIVE_LOAD = 0x80020139,
|
||||
SCE_KERNEL_ERROR_LIBRARY_NOT_YET_LINKED = 0x8002013a,
|
||||
SCE_KERNEL_ERROR_LIBRARY_FOUND = 0x8002013b,
|
||||
SCE_KERNEL_ERROR_LIBRARY_NOTFOUND = 0x8002013c,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_LIBRARY = 0x8002013d,
|
||||
SCE_KERNEL_ERROR_LIBRARY_INUSE = 0x8002013e,
|
||||
SCE_KERNEL_ERROR_ALREADY_STOPPING = 0x8002013f,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_OFFSET = 0x80020140,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_POSITION = 0x80020141,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ACCESS = 0x80020142,
|
||||
SCE_KERNEL_ERROR_MODULE_MGR_BUSY = 0x80020143,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_FLAG = 0x80020144,
|
||||
SCE_KERNEL_ERROR_CANNOT_GET_MODULELIST = 0x80020145,
|
||||
SCE_KERNEL_ERROR_PROHIBIT_LOADMODULE_DEVICE = 0x80020146,
|
||||
SCE_KERNEL_ERROR_PROHIBIT_LOADEXEC_DEVICE = 0x80020147,
|
||||
SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE = 0x80020148,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PERM_CALL = 0x80020149,
|
||||
SCE_KERNEL_ERROR_CANNOT_GET_MODULE_INFORMATION = 0x8002014a,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_BUFFER = 0x8002014b,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_FILENAME = 0x8002014c,
|
||||
SCE_KERNEL_ERROR_NO_EXIT_CALLBACK = 0x8002014d,
|
||||
SCE_KERNEL_ERROR_NO_MEMORY = 0x80020190,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ATTR = 0x80020191,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ENTRY = 0x80020192,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = 0x80020193,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = 0x80020194,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MODE = 0x80020195,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MASK = 0x80020196,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_THID = 0x80020197,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_THID = 0x80020198,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_SEMID = 0x80020199,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_EVFID = 0x8002019a,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_MBXID = 0x8002019b,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_VPLID = 0x8002019c,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_FPLID = 0x8002019d,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_MPPID = 0x8002019e,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_ALMID = 0x8002019f,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_TEID = 0x800201a0,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_CBID = 0x800201a1,
|
||||
SCE_KERNEL_ERROR_DORMANT = 0x800201a2,
|
||||
SCE_KERNEL_ERROR_SUSPEND = 0x800201a3,
|
||||
SCE_KERNEL_ERROR_NOT_DORMANT = 0x800201a4,
|
||||
SCE_KERNEL_ERROR_NOT_SUSPEND = 0x800201a5,
|
||||
SCE_KERNEL_ERROR_NOT_WAIT = 0x800201a6,
|
||||
SCE_KERNEL_ERROR_CAN_NOT_WAIT = 0x800201a7,
|
||||
SCE_KERNEL_ERROR_WAIT_TIMEOUT = 0x800201a8,
|
||||
SCE_KERNEL_ERROR_WAIT_CANCEL = 0x800201a9,
|
||||
SCE_KERNEL_ERROR_RELEASE_WAIT = 0x800201aa,
|
||||
SCE_KERNEL_ERROR_NOTIFY_CALLBACK = 0x800201ab,
|
||||
SCE_KERNEL_ERROR_THREAD_TERMINATED = 0x800201ac,
|
||||
SCE_KERNEL_ERROR_SEMA_ZERO = 0x800201ad,
|
||||
SCE_KERNEL_ERROR_SEMA_OVF = 0x800201ae,
|
||||
SCE_KERNEL_ERROR_EVF_COND = 0x800201af,
|
||||
SCE_KERNEL_ERROR_EVF_MULTI = 0x800201b0,
|
||||
SCE_KERNEL_ERROR_EVF_ILPAT = 0x800201b1,
|
||||
SCE_KERNEL_ERROR_MBOX_NOMSG = 0x800201b2,
|
||||
SCE_KERNEL_ERROR_MPP_FULL = 0x800201b3,
|
||||
SCE_KERNEL_ERROR_MPP_EMPTY = 0x800201b4,
|
||||
SCE_KERNEL_ERROR_WAIT_DELETE = 0x800201b5,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK = 0x800201b6,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE = 0x800201b7,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SPADADDR = 0x800201b8,
|
||||
SCE_KERNEL_ERROR_SPAD_INUSE = 0x800201b9,
|
||||
SCE_KERNEL_ERROR_SPAD_NOT_INUSE = 0x800201ba,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_TYPE = 0x800201bb,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SIZE = 0x800201bc,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_COUNT = 0x800201bd,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_VTID = 0x800201be,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_VTID = 0x800201bf,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_KTLSID = 0x800201c0,
|
||||
SCE_KERNEL_ERROR_KTLS_FULL = 0x800201c1,
|
||||
SCE_KERNEL_ERROR_KTLS_BUSY = 0x800201c2,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_PRIORITY = 0x80020258,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_DEVNAME = 0x80020259,
|
||||
SCE_KERNEL_ERROR_PM_UNKNOWN_DEVNAME = 0x8002025a,
|
||||
SCE_KERNEL_ERROR_PM_PMINFO_REGISTERED = 0x8002025b,
|
||||
SCE_KERNEL_ERROR_PM_PMINFO_UNREGISTERED = 0x8002025c,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_MAJOR_STATE = 0x8002025d,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_REQUEST = 0x8002025e,
|
||||
SCE_KERNEL_ERROR_PM_UNKNOWN_REQUEST = 0x8002025f,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_UNIT = 0x80020260,
|
||||
SCE_KERNEL_ERROR_PM_CANNOT_CANCEL = 0x80020261,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_PMINFO = 0x80020262,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_ARGUMENT = 0x80020263,
|
||||
SCE_KERNEL_ERROR_PM_ALREADY_TARGET_PWRSTATE = 0x80020264,
|
||||
SCE_KERNEL_ERROR_PM_CHANGE_PWRSTATE_FAILED = 0x80020265,
|
||||
SCE_KERNEL_ERROR_PM_CANNOT_CHANGE_DEVPWR_STATE = 0x80020266,
|
||||
SCE_KERNEL_ERROR_PM_NO_SUPPORT_DEVPWR_STATE = 0x80020267,
|
||||
SCE_KERNEL_ERROR_DMAC_REQUEST_FAILED = 0x800202bc,
|
||||
SCE_KERNEL_ERROR_DMAC_REQUEST_DENIED = 0x800202bd,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_QUEUED = 0x800202be,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_NOT_QUEUED = 0x800202bf,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_RUNNING = 0x800202c0,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_NOT_ASSIGNED = 0x800202c1,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_TIMEOUT = 0x800202c2,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_FREED = 0x800202c3,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_USED = 0x800202c4,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_EMPTY = 0x800202c5,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_ABORTED = 0x800202c6,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_ERROR = 0x800202c7,
|
||||
SCE_KERNEL_ERROR_DMAC_CHANNEL_RESERVED = 0x800202c8,
|
||||
SCE_KERNEL_ERROR_DMAC_CHANNEL_EXCLUDED = 0x800202c9,
|
||||
SCE_KERNEL_ERROR_DMAC_PRIVILEGE_ADDRESS = 0x800202ca,
|
||||
SCE_KERNEL_ERROR_DMAC_NO_ENOUGHSPACE = 0x800202cb,
|
||||
SCE_KERNEL_ERROR_DMAC_CHANNEL_NOT_ASSIGNED = 0x800202cc,
|
||||
SCE_KERNEL_ERROR_DMAC_CHILD_OPERATION = 0x800202cd,
|
||||
SCE_KERNEL_ERROR_DMAC_TOO_MUCH_SIZE = 0x800202ce,
|
||||
SCE_KERNEL_ERROR_DMAC_INVALID_ARGUMENT = 0x800202cf,
|
||||
SCE_KERNEL_ERROR_MFILE = 0x80020320,
|
||||
SCE_KERNEL_ERROR_NODEV = 0x80020321,
|
||||
SCE_KERNEL_ERROR_XDEV = 0x80020322,
|
||||
SCE_KERNEL_ERROR_BADF = 0x80020323,
|
||||
SCE_KERNEL_ERROR_INVAL = 0x80020324,
|
||||
SCE_KERNEL_ERROR_UNSUP = 0x80020325,
|
||||
SCE_KERNEL_ERROR_ALIAS_USED = 0x80020326,
|
||||
SCE_KERNEL_ERROR_CANNOT_MOUNT = 0x80020327,
|
||||
SCE_KERNEL_ERROR_DRIVER_DELETED = 0x80020328,
|
||||
SCE_KERNEL_ERROR_ASYNC_BUSY = 0x80020329,
|
||||
SCE_KERNEL_ERROR_NOASYNC = 0x8002032a,
|
||||
SCE_KERNEL_ERROR_REGDEV = 0x8002032b,
|
||||
SCE_KERNEL_ERROR_NOCWD = 0x8002032c,
|
||||
SCE_KERNEL_ERROR_NAMETOOLONG = 0x8002032d,
|
||||
SCE_KERNEL_ERROR_NXIO = 0x800203e8,
|
||||
SCE_KERNEL_ERROR_IO = 0x800203e9,
|
||||
SCE_KERNEL_ERROR_NOMEM = 0x800203ea,
|
||||
SCE_KERNEL_ERROR_STDIO_NOT_OPENED = 0x800203eb,
|
||||
SCE_KERNEL_ERROR_CACHE_ALIGNMENT = 0x8002044c,
|
||||
SCE_KERNEL_ERROR_ERRORMAX = 0x8002044d,
|
||||
SCE_KERNEL_ERROR_OK = 0,
|
||||
SCE_KERNEL_ERROR_INVALID_VALUE = 0x800001fe,
|
||||
SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x800001ff,
|
||||
SCE_KERNEL_ERROR_ERROR = 0x80020001,
|
||||
SCE_KERNEL_ERROR_NOTIMP = 0x80020002,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_EXPCODE = 0x80020032,
|
||||
SCE_KERNEL_ERROR_EXPHANDLER_NOUSE = 0x80020033,
|
||||
SCE_KERNEL_ERROR_EXPHANDLER_USED = 0x80020034,
|
||||
SCE_KERNEL_ERROR_SYCALLTABLE_NOUSED = 0x80020035,
|
||||
SCE_KERNEL_ERROR_SYCALLTABLE_USED = 0x80020036,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SYSCALLTABLE = 0x80020037,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PRIMARY_SYSCALL_NUMBER = 0x80020038,
|
||||
SCE_KERNEL_ERROR_PRIMARY_SYSCALL_NUMBER_INUSE = 0x80020039,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = 0x80020064,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = 0x80020065,
|
||||
SCE_KERNEL_ERROR_CPUDI = 0x80020066,
|
||||
SCE_KERNEL_ERROR_FOUND_HANDLER = 0x80020067,
|
||||
SCE_KERNEL_ERROR_NOTFOUND_HANDLER = 0x80020068,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_INTRLEVEL = 0x80020069,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ADDRESS = 0x8002006a,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = 0x8002006b,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_STACK_ADDRESS = 0x8002006c,
|
||||
SCE_KERNEL_ERROR_ALREADY_STACK_SET = 0x8002006d,
|
||||
SCE_KERNEL_ERROR_NO_TIMER = 0x80020096,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_TIMERID = 0x80020097,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SOURCE = 0x80020098,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PRESCALE = 0x80020099,
|
||||
SCE_KERNEL_ERROR_TIMER_BUSY = 0x8002009a,
|
||||
SCE_KERNEL_ERROR_TIMER_NOT_SETUP = 0x8002009b,
|
||||
SCE_KERNEL_ERROR_TIMER_NOT_INUSE = 0x8002009c,
|
||||
SCE_KERNEL_ERROR_UNIT_USED = 0x800200a0,
|
||||
SCE_KERNEL_ERROR_UNIT_NOUSE = 0x800200a1,
|
||||
SCE_KERNEL_ERROR_NO_ROMDIR = 0x800200a2,
|
||||
SCE_KERNEL_ERROR_IDTYPE_EXIST = 0x800200c8,
|
||||
SCE_KERNEL_ERROR_IDTYPE_NOT_EXIST = 0x800200c9,
|
||||
SCE_KERNEL_ERROR_IDTYPE_NOT_EMPTY = 0x800200ca,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_UID = 0x800200cb,
|
||||
SCE_KERNEL_ERROR_UNMATCH_UID_TYPE = 0x800200cc,
|
||||
SCE_KERNEL_ERROR_ID_NOT_EXIST = 0x800200cd,
|
||||
SCE_KERNEL_ERROR_NOT_FOUND_UIDFUNC = 0x800200ce,
|
||||
SCE_KERNEL_ERROR_UID_ALREADY_HOLDER = 0x800200cf,
|
||||
SCE_KERNEL_ERROR_UID_NOT_HOLDER = 0x800200d0,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PERM = 0x800200d1,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT = 0x800200d2,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ADDR = 0x800200d3,
|
||||
SCE_KERNEL_ERROR_OUT_OF_RANGE = 0x800200d4,
|
||||
SCE_KERNEL_ERROR_MEM_RANGE_OVERLAP = 0x800200d5,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PARTITION = 0x800200d6,
|
||||
SCE_KERNEL_ERROR_PARTITION_INUSE = 0x800200d7,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCKTYPE = 0x800200d8,
|
||||
SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED = 0x800200d9,
|
||||
SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_LOCKED = 0x800200da,
|
||||
SCE_KERNEL_ERROR_MEMBLOCK_RESIZE_FAILED = 0x800200db,
|
||||
SCE_KERNEL_ERROR_HEAPBLOCK_ALLOC_FAILED = 0x800200dc,
|
||||
SCE_KERNEL_ERROR_HEAP_ALLOC_FAILED = 0x800200dd,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_CHUNK_ID = 0x800200de,
|
||||
SCE_KERNEL_ERROR_NOCHUNK = 0x800200df,
|
||||
SCE_KERNEL_ERROR_NO_FREECHUNK = 0x800200e0,
|
||||
SCE_KERNEL_ERROR_LINKERR = 0x8002012c,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_OBJECT = 0x8002012d,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_MODULE = 0x8002012e,
|
||||
SCE_KERNEL_ERROR_NOFILE = 0x8002012f,
|
||||
SCE_KERNEL_ERROR_FILEERR = 0x80020130,
|
||||
SCE_KERNEL_ERROR_MEMINUSE = 0x80020131,
|
||||
SCE_KERNEL_ERROR_PARTITION_MISMATCH = 0x80020132,
|
||||
SCE_KERNEL_ERROR_ALREADY_STARTED = 0x80020133,
|
||||
SCE_KERNEL_ERROR_NOT_STARTED = 0x80020134,
|
||||
SCE_KERNEL_ERROR_ALREADY_STOPPED = 0x80020135,
|
||||
SCE_KERNEL_ERROR_CAN_NOT_STOP = 0x80020136,
|
||||
SCE_KERNEL_ERROR_NOT_STOPPED = 0x80020137,
|
||||
SCE_KERNEL_ERROR_NOT_REMOVABLE = 0x80020138,
|
||||
SCE_KERNEL_ERROR_EXCLUSIVE_LOAD = 0x80020139,
|
||||
SCE_KERNEL_ERROR_LIBRARY_NOT_YET_LINKED = 0x8002013a,
|
||||
SCE_KERNEL_ERROR_LIBRARY_FOUND = 0x8002013b,
|
||||
SCE_KERNEL_ERROR_LIBRARY_NOTFOUND = 0x8002013c,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_LIBRARY = 0x8002013d,
|
||||
SCE_KERNEL_ERROR_LIBRARY_INUSE = 0x8002013e,
|
||||
SCE_KERNEL_ERROR_ALREADY_STOPPING = 0x8002013f,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_OFFSET = 0x80020140,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_POSITION = 0x80020141,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ACCESS = 0x80020142,
|
||||
SCE_KERNEL_ERROR_MODULE_MGR_BUSY = 0x80020143,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_FLAG = 0x80020144,
|
||||
SCE_KERNEL_ERROR_CANNOT_GET_MODULELIST = 0x80020145,
|
||||
SCE_KERNEL_ERROR_PROHIBIT_LOADMODULE_DEVICE = 0x80020146,
|
||||
SCE_KERNEL_ERROR_PROHIBIT_LOADEXEC_DEVICE = 0x80020147,
|
||||
SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE = 0x80020148,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PERM_CALL = 0x80020149,
|
||||
SCE_KERNEL_ERROR_CANNOT_GET_MODULE_INFORMATION = 0x8002014a,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_BUFFER = 0x8002014b,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_LOADEXEC_FILENAME = 0x8002014c,
|
||||
SCE_KERNEL_ERROR_NO_EXIT_CALLBACK = 0x8002014d,
|
||||
SCE_KERNEL_ERROR_NO_MEMORY = 0x80020190,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ATTR = 0x80020191,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_ENTRY = 0x80020192,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = 0x80020193,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = 0x80020194,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MODE = 0x80020195,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MASK = 0x80020196,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_THID = 0x80020197,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_THID = 0x80020198,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_SEMID = 0x80020199,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_EVFID = 0x8002019a,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_MBXID = 0x8002019b,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_VPLID = 0x8002019c,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_FPLID = 0x8002019d,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_MPPID = 0x8002019e,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_ALMID = 0x8002019f,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_TEID = 0x800201a0,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_CBID = 0x800201a1,
|
||||
SCE_KERNEL_ERROR_DORMANT = 0x800201a2,
|
||||
SCE_KERNEL_ERROR_SUSPEND = 0x800201a3,
|
||||
SCE_KERNEL_ERROR_NOT_DORMANT = 0x800201a4,
|
||||
SCE_KERNEL_ERROR_NOT_SUSPEND = 0x800201a5,
|
||||
SCE_KERNEL_ERROR_NOT_WAIT = 0x800201a6,
|
||||
SCE_KERNEL_ERROR_CAN_NOT_WAIT = 0x800201a7,
|
||||
SCE_KERNEL_ERROR_WAIT_TIMEOUT = 0x800201a8,
|
||||
SCE_KERNEL_ERROR_WAIT_CANCEL = 0x800201a9,
|
||||
SCE_KERNEL_ERROR_RELEASE_WAIT = 0x800201aa,
|
||||
SCE_KERNEL_ERROR_NOTIFY_CALLBACK = 0x800201ab,
|
||||
SCE_KERNEL_ERROR_THREAD_TERMINATED = 0x800201ac,
|
||||
SCE_KERNEL_ERROR_SEMA_ZERO = 0x800201ad,
|
||||
SCE_KERNEL_ERROR_SEMA_OVF = 0x800201ae,
|
||||
SCE_KERNEL_ERROR_EVF_COND = 0x800201af,
|
||||
SCE_KERNEL_ERROR_EVF_MULTI = 0x800201b0,
|
||||
SCE_KERNEL_ERROR_EVF_ILPAT = 0x800201b1,
|
||||
SCE_KERNEL_ERROR_MBOX_NOMSG = 0x800201b2,
|
||||
SCE_KERNEL_ERROR_MPP_FULL = 0x800201b3,
|
||||
SCE_KERNEL_ERROR_MPP_EMPTY = 0x800201b4,
|
||||
SCE_KERNEL_ERROR_WAIT_DELETE = 0x800201b5,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK = 0x800201b6,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE = 0x800201b7,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SPADADDR = 0x800201b8,
|
||||
SCE_KERNEL_ERROR_SPAD_INUSE = 0x800201b9,
|
||||
SCE_KERNEL_ERROR_SPAD_NOT_INUSE = 0x800201ba,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_TYPE = 0x800201bb,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_SIZE = 0x800201bc,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_COUNT = 0x800201bd,
|
||||
SCE_KERNEL_ERROR_UNKNOWN_VTID = 0x800201be,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_VTID = 0x800201bf,
|
||||
SCE_KERNEL_ERROR_ILLEGAL_KTLSID = 0x800201c0,
|
||||
SCE_KERNEL_ERROR_KTLS_FULL = 0x800201c1,
|
||||
SCE_KERNEL_ERROR_KTLS_BUSY = 0x800201c2,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_PRIORITY = 0x80020258,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_DEVNAME = 0x80020259,
|
||||
SCE_KERNEL_ERROR_PM_UNKNOWN_DEVNAME = 0x8002025a,
|
||||
SCE_KERNEL_ERROR_PM_PMINFO_REGISTERED = 0x8002025b,
|
||||
SCE_KERNEL_ERROR_PM_PMINFO_UNREGISTERED = 0x8002025c,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_MAJOR_STATE = 0x8002025d,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_REQUEST = 0x8002025e,
|
||||
SCE_KERNEL_ERROR_PM_UNKNOWN_REQUEST = 0x8002025f,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_UNIT = 0x80020260,
|
||||
SCE_KERNEL_ERROR_PM_CANNOT_CANCEL = 0x80020261,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_PMINFO = 0x80020262,
|
||||
SCE_KERNEL_ERROR_PM_INVALID_ARGUMENT = 0x80020263,
|
||||
SCE_KERNEL_ERROR_PM_ALREADY_TARGET_PWRSTATE = 0x80020264,
|
||||
SCE_KERNEL_ERROR_PM_CHANGE_PWRSTATE_FAILED = 0x80020265,
|
||||
SCE_KERNEL_ERROR_PM_CANNOT_CHANGE_DEVPWR_STATE = 0x80020266,
|
||||
SCE_KERNEL_ERROR_PM_NO_SUPPORT_DEVPWR_STATE = 0x80020267,
|
||||
SCE_KERNEL_ERROR_DMAC_REQUEST_FAILED = 0x800202bc,
|
||||
SCE_KERNEL_ERROR_DMAC_REQUEST_DENIED = 0x800202bd,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_QUEUED = 0x800202be,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_NOT_QUEUED = 0x800202bf,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_RUNNING = 0x800202c0,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_NOT_ASSIGNED = 0x800202c1,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_TIMEOUT = 0x800202c2,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_FREED = 0x800202c3,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_USED = 0x800202c4,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_EMPTY = 0x800202c5,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_ABORTED = 0x800202c6,
|
||||
SCE_KERNEL_ERROR_DMAC_OP_ERROR = 0x800202c7,
|
||||
SCE_KERNEL_ERROR_DMAC_CHANNEL_RESERVED = 0x800202c8,
|
||||
SCE_KERNEL_ERROR_DMAC_CHANNEL_EXCLUDED = 0x800202c9,
|
||||
SCE_KERNEL_ERROR_DMAC_PRIVILEGE_ADDRESS = 0x800202ca,
|
||||
SCE_KERNEL_ERROR_DMAC_NO_ENOUGHSPACE = 0x800202cb,
|
||||
SCE_KERNEL_ERROR_DMAC_CHANNEL_NOT_ASSIGNED = 0x800202cc,
|
||||
SCE_KERNEL_ERROR_DMAC_CHILD_OPERATION = 0x800202cd,
|
||||
SCE_KERNEL_ERROR_DMAC_TOO_MUCH_SIZE = 0x800202ce,
|
||||
SCE_KERNEL_ERROR_DMAC_INVALID_ARGUMENT = 0x800202cf,
|
||||
SCE_KERNEL_ERROR_MFILE = 0x80020320,
|
||||
SCE_KERNEL_ERROR_NODEV = 0x80020321,
|
||||
SCE_KERNEL_ERROR_XDEV = 0x80020322,
|
||||
SCE_KERNEL_ERROR_BADF = 0x80020323,
|
||||
SCE_KERNEL_ERROR_INVAL = 0x80020324,
|
||||
SCE_KERNEL_ERROR_UNSUP = 0x80020325,
|
||||
SCE_KERNEL_ERROR_ALIAS_USED = 0x80020326,
|
||||
SCE_KERNEL_ERROR_CANNOT_MOUNT = 0x80020327,
|
||||
SCE_KERNEL_ERROR_DRIVER_DELETED = 0x80020328,
|
||||
SCE_KERNEL_ERROR_ASYNC_BUSY = 0x80020329,
|
||||
SCE_KERNEL_ERROR_NOASYNC = 0x8002032a,
|
||||
SCE_KERNEL_ERROR_REGDEV = 0x8002032b,
|
||||
SCE_KERNEL_ERROR_NOCWD = 0x8002032c,
|
||||
SCE_KERNEL_ERROR_NAMETOOLONG = 0x8002032d,
|
||||
SCE_KERNEL_ERROR_NXIO = 0x800203e8,
|
||||
SCE_KERNEL_ERROR_IO = 0x800203e9,
|
||||
SCE_KERNEL_ERROR_NOMEM = 0x800203ea,
|
||||
SCE_KERNEL_ERROR_STDIO_NOT_OPENED = 0x800203eb,
|
||||
SCE_KERNEL_ERROR_CACHE_ALIGNMENT = 0x8002044c,
|
||||
SCE_KERNEL_ERROR_ERRORMAX = 0x8002044d,
|
||||
};
|
||||
|
||||
enum TMIDPurpose
|
||||
{
|
||||
SCE_KERNEL_TMID_Thread = 1,
|
||||
SCE_KERNEL_TMID_Semaphore = 2,
|
||||
SCE_KERNEL_TMID_EventFlag = 3,
|
||||
SCE_KERNEL_TMID_Mbox = 4,
|
||||
SCE_KERNEL_TMID_Vpl = 5,
|
||||
SCE_KERNEL_TMID_Fpl = 6,
|
||||
SCE_KERNEL_TMID_Mpipe = 7,
|
||||
SCE_KERNEL_TMID_Callback = 8,
|
||||
SCE_KERNEL_TMID_ThreadEventHandler = 9,
|
||||
SCE_KERNEL_TMID_Alarm = 10,
|
||||
SCE_KERNEL_TMID_VTimer = 11,
|
||||
SCE_KERNEL_TMID_Mutex = 12,
|
||||
SCE_KERNEL_TMID_LwMutex = 13,
|
||||
SCE_KERNEL_TMID_SleepThread = 64,
|
||||
SCE_KERNEL_TMID_DelayThread = 65,
|
||||
SCE_KERNEL_TMID_SuspendThread = 66,
|
||||
SCE_KERNEL_TMID_DormantThread = 67,
|
||||
};
|
||||
|
||||
typedef int SceUID;
|
||||
@ -232,9 +255,9 @@ typedef u64 SceIores;
|
||||
|
||||
struct SceKernelLoadExecParam
|
||||
{
|
||||
SceSize size; // Size of the structure
|
||||
SceSize args; // Size of the arg string
|
||||
void *argp; // Pointer to the arg string
|
||||
SceSize size; // Size of the structure
|
||||
SceSize args; // Size of the arg string
|
||||
void *argp; // Pointer to the arg string
|
||||
const char *key; // Encryption key? Not yet used
|
||||
};
|
||||
|
||||
@ -242,15 +265,14 @@ void __KernelInit();
|
||||
void __KernelShutdown();
|
||||
bool __KernelIsRunning();
|
||||
bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param);
|
||||
|
||||
|
||||
int sceKernelLoadExec(const char *filename, u32 paramPtr);
|
||||
|
||||
void sceKernelRegisterExitCallback();
|
||||
void sceKernelExitGame();
|
||||
|
||||
void sceKernelSleepThread();
|
||||
void sceKernelSleepThreadCB();
|
||||
void sceKernelSleepThread();
|
||||
void sceKernelSleepThreadCB();
|
||||
|
||||
void sceKernelDevkitVersion();
|
||||
|
||||
@ -282,47 +304,27 @@ public:
|
||||
SceUID GetUID() const {return uid;}
|
||||
virtual const char *GetTypeName() {return "[BAD KERNEL OBJECT TYPE]";}
|
||||
virtual const char *GetName() {return "[UNKNOWN KERNEL OBJECT]";}
|
||||
virtual int GetIDType() const = 0;
|
||||
virtual int GetIDType() const = 0;
|
||||
virtual void GetQuickInfo(char *ptr, int size) {strcpy(ptr,"-");}
|
||||
|
||||
// Implement this in all subclasses:
|
||||
// static u32 GetMissingErrorCode()
|
||||
// Implement this in all subclasses:
|
||||
// static u32 GetMissingErrorCode()
|
||||
|
||||
// Future
|
||||
// void Serialize(ChunkFile)
|
||||
// void DeSerialize(ChunkFile)
|
||||
// Future
|
||||
// void Serialize(ChunkFile)
|
||||
// void DeSerialize(ChunkFile)
|
||||
};
|
||||
|
||||
enum TMIDPurpose
|
||||
{
|
||||
SCE_KERNEL_TMID_Thread = 1,
|
||||
SCE_KERNEL_TMID_Semaphore = 2,
|
||||
SCE_KERNEL_TMID_EventFlag = 3,
|
||||
SCE_KERNEL_TMID_Mbox = 4,
|
||||
SCE_KERNEL_TMID_Vpl = 5,
|
||||
SCE_KERNEL_TMID_Fpl = 6,
|
||||
SCE_KERNEL_TMID_Mpipe = 7,
|
||||
SCE_KERNEL_TMID_Callback = 8,
|
||||
SCE_KERNEL_TMID_ThreadEventHandler = 9,
|
||||
SCE_KERNEL_TMID_Alarm = 10,
|
||||
SCE_KERNEL_TMID_VTimer = 11,
|
||||
SCE_KERNEL_TMID_Mutex = 12,
|
||||
SCE_KERNEL_TMID_LwMutex = 13,
|
||||
SCE_KERNEL_TMID_SleepThread = 64,
|
||||
SCE_KERNEL_TMID_DelayThread = 65,
|
||||
SCE_KERNEL_TMID_SuspendThread = 66,
|
||||
SCE_KERNEL_TMID_DormantThread = 67,
|
||||
};
|
||||
|
||||
class KernelObjectPool
|
||||
{
|
||||
enum {maxCount=2048, handleOffset=0x100};
|
||||
KernelObject *pool[maxCount];
|
||||
bool occupied[maxCount];
|
||||
class KernelObjectPool {
|
||||
public:
|
||||
KernelObjectPool();
|
||||
~KernelObjectPool() {}
|
||||
|
||||
SceUID Create(KernelObject *obj);
|
||||
// Allocates a UID within the range and inserts the object into the map.
|
||||
SceUID Create(KernelObject *obj, int rangeBottom = 16, int rangeTop = 0x7fffffff);
|
||||
|
||||
// TODO: How will we ever save/restore this pool?
|
||||
|
||||
template <class T>
|
||||
u32 Destroy(SceUID handle)
|
||||
@ -338,7 +340,7 @@ public:
|
||||
|
||||
bool IsValid(SceUID handle);
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
T* Get(SceUID handle, u32 &outError)
|
||||
{
|
||||
if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset])
|
||||
@ -360,19 +362,42 @@ public:
|
||||
return t;
|
||||
}
|
||||
}
|
||||
static u32 GetMissingErrorCode() { return -1; } // TODO
|
||||
template <class T>
|
||||
T* GetByModuleByEntryAddr(u32 entryAddr)
|
||||
{
|
||||
for (int i=0; i <4096; i++)
|
||||
{
|
||||
T* t = dynamic_cast<T*>(pool[i]);
|
||||
|
||||
bool GetIDType(SceUID handle, int *type) const
|
||||
{
|
||||
KernelObject *t = pool[handle - handleOffset];
|
||||
*type = t->GetIDType();
|
||||
return true;
|
||||
}
|
||||
if (t)
|
||||
{
|
||||
if (t->nm.entry_addr == entryAddr)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 GetMissingErrorCode() { return -1; } // TODO
|
||||
|
||||
bool GetIDType(SceUID handle, int *type) const
|
||||
{
|
||||
KernelObject *t = pool[handle - handleOffset];
|
||||
*type = t->GetIDType();
|
||||
return true;
|
||||
}
|
||||
|
||||
KernelObject *&operator [](SceUID handle);
|
||||
void List();
|
||||
void Clear();
|
||||
int GetCount();
|
||||
|
||||
private:
|
||||
enum {maxCount=4096, handleOffset=0x100};
|
||||
KernelObject *pool[maxCount];
|
||||
bool occupied[maxCount];
|
||||
};
|
||||
|
||||
extern KernelObjectPool kernelObjects;
|
||||
|
@ -19,18 +19,18 @@
|
||||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../../Core/CoreTiming.h"
|
||||
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelEventFlag.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
void __KernelEventFlagTimeout(u64 userdata, int cycleslate);
|
||||
|
||||
struct NativeEventFlag
|
||||
{
|
||||
u32 size;
|
||||
char name[32];
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
u32 attr;
|
||||
u32 initPattern;
|
||||
u32 currentPattern;
|
||||
@ -79,37 +79,162 @@ enum PspEventFlagAttributes
|
||||
enum PspEventFlagWaitTypes
|
||||
{
|
||||
/** Wait for all bits in the pattern to be set */
|
||||
PSP_EVENT_WAITAND = 0,
|
||||
PSP_EVENT_WAITAND = 0x00,
|
||||
/** Wait for one or more bits in the pattern to be set */
|
||||
PSP_EVENT_WAITOR = 1,
|
||||
PSP_EVENT_WAITOR = 0x01,
|
||||
/** Clear the entire pattern when it matches. */
|
||||
PSP_EVENT_WAITCLEARALL = 0x10,
|
||||
/** Clear the wait pattern when it matches */
|
||||
PSP_EVENT_WAITCLEAR = 0x20
|
||||
PSP_EVENT_WAITCLEAR = 0x20,
|
||||
|
||||
PSP_EVENT_WAITKNOWN = PSP_EVENT_WAITCLEAR | PSP_EVENT_WAITCLEARALL | PSP_EVENT_WAITOR,
|
||||
};
|
||||
|
||||
bool eventFlagInitComplete = false;
|
||||
int eventFlagWaitTimer = 0;
|
||||
|
||||
void __KernelEventFlagInit()
|
||||
{
|
||||
eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", &__KernelEventFlagTimeout);
|
||||
eventFlagInitComplete = true;
|
||||
}
|
||||
|
||||
bool __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
|
||||
{
|
||||
if ((wait & PSP_EVENT_WAITOR)
|
||||
? (bits & *pattern) /* one or more bits of the mask */
|
||||
: ((bits & *pattern) == bits)) /* all the bits of the mask */
|
||||
{
|
||||
if (Memory::IsValidAddress(outAddr))
|
||||
Memory::Write_U32(*pattern, outAddr);
|
||||
|
||||
if (wait & PSP_EVENT_WAITCLEAR)
|
||||
*pattern &= ~bits;
|
||||
if (wait & PSP_EVENT_WAITCLEARALL)
|
||||
*pattern = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32 &error, int result, bool &wokeThreads)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(th.tid, WAITTYPE_EVENTFLAG, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.tid, error);
|
||||
|
||||
// The waitID may be different after a timeout.
|
||||
if (waitID != e->GetUID())
|
||||
return true;
|
||||
|
||||
// If result is an error code, we're just letting it go.
|
||||
if (result == 0)
|
||||
{
|
||||
if (!__KernelEventFlagMatches(&e->nef.currentPattern, th.bits, th.wait, th.outAddr))
|
||||
return false;
|
||||
|
||||
e->nef.numWaitThreads--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, we set the current result since we're bailing.
|
||||
if (Memory::IsValidAddress(th.outAddr))
|
||||
Memory::Write_U32(e->nef.currentPattern, th.outAddr);
|
||||
}
|
||||
|
||||
if (timeoutPtr != 0 && eventFlagWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
u64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, th.tid);
|
||||
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(th.tid, result);
|
||||
wokeThreads = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __KernelClearEventFlagThreads(EventFlag *e, int reason)
|
||||
{
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
std::vector<EventFlagTh>::iterator iter, end;
|
||||
for (iter = e->waitingThreads.begin(), end = e->waitingThreads.end(); iter != end; ++iter)
|
||||
__KernelUnlockEventFlagForThread(e, *iter, error, reason, wokeThreads);
|
||||
e->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt);
|
||||
int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr)
|
||||
{
|
||||
if (!eventFlagInitComplete)
|
||||
__KernelEventFlagInit();
|
||||
|
||||
if (!name)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=sceKernelCreateEventFlag(): invalid name", SCE_KERNEL_ERROR_ERROR);
|
||||
return SCE_KERNEL_ERROR_ERROR;
|
||||
}
|
||||
|
||||
// These attributes aren't valid.
|
||||
if ((flag_attr & 0x100) != 0 || flag_attr >= 0x300)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=sceKernelCreateEventFlag(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, flag_attr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
|
||||
}
|
||||
|
||||
EventFlag *e = new EventFlag();
|
||||
SceUID id = kernelObjects.Create(e);
|
||||
|
||||
e->nef.size = sizeof(NativeEventFlag);
|
||||
strncpy(e->nef.name, name, 32);
|
||||
strncpy(e->nef.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
e->nef.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||
e->nef.attr = flag_attr;
|
||||
e->nef.initPattern = flag_initPattern;
|
||||
e->nef.currentPattern = e->nef.initPattern;
|
||||
e->nef.numWaitThreads = 0;
|
||||
|
||||
DEBUG_LOG(HLE,"%i=sceKernelCreateEventFlag(\"%s\", %08x, %08x, %08x)", id, e->nef.name, e->nef.attr, e->nef.currentPattern, optPtr);
|
||||
DEBUG_LOG(HLE, "%i=sceKernelCreateEventFlag(\"%s\", %08x, %08x, %08x)", id, e->nef.name, e->nef.attr, e->nef.currentPattern, optPtr);
|
||||
|
||||
if (optPtr != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateEventFlag(%s) unsupported options parameter: %08x", name, optPtr);
|
||||
if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelEventFlag(%i, %08X, %08X)", uid, pattern, numWaitThreadsPtr);
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
|
||||
if (e)
|
||||
{
|
||||
if (Memory::IsValidAddress(numWaitThreadsPtr))
|
||||
Memory::Write_U32(e->nef.numWaitThreads, numWaitThreadsPtr);
|
||||
|
||||
e->nef.currentPattern = pattern;
|
||||
e->nef.numWaitThreads = 0;
|
||||
|
||||
if (__KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_CANCEL))
|
||||
hleReSchedule("event flag canceled");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 sceKernelClearEventFlag(SceUID id, u32 bits)
|
||||
{
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelClearEventFlag(%i, %08x)", id, bits);
|
||||
DEBUG_LOG(HLE, "sceKernelClearEventFlag(%i, %08x)", id, bits);
|
||||
e->nef.currentPattern &= bits;
|
||||
// Note that it's not possible for threads to get woken up by this action.
|
||||
return 0;
|
||||
@ -123,30 +248,26 @@ u32 sceKernelClearEventFlag(SceUID id, u32 bits)
|
||||
|
||||
u32 sceKernelDeleteEventFlag(SceUID uid)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelDeleteEventFlag(%i)", uid);
|
||||
return kernelObjects.Destroy<EventFlag>(uid);
|
||||
}
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteEventFlag(%i)", uid);
|
||||
|
||||
u8 __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
|
||||
{
|
||||
if ((wait & PSP_EVENT_WAITOR)
|
||||
? (bits & *pattern) /* one or more bits of the mask */
|
||||
: ((bits & *pattern) == bits)) /* all the bits of the mask */
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
|
||||
if (e)
|
||||
{
|
||||
if (Memory::IsValidAddress(outAddr))
|
||||
Memory::Write_U32(*pattern, outAddr);
|
||||
bool wokeThreads = __KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("event flag deleted");
|
||||
|
||||
if (wait & PSP_EVENT_WAITCLEAR)
|
||||
*pattern &= ~bits;
|
||||
return 1;
|
||||
return kernelObjects.Destroy<EventFlag>(uid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
|
||||
{
|
||||
u32 error;
|
||||
DEBUG_LOG(HLE,"sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
|
||||
DEBUG_LOG(HLE, "sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
{
|
||||
@ -154,19 +275,20 @@ u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
|
||||
|
||||
e->nef.currentPattern |= bitsToSet;
|
||||
|
||||
retry:
|
||||
for (size_t i = 0; i < e->waitingThreads.size(); i++)
|
||||
for (size_t i = 0; i < e->waitingThreads.size(); ++i)
|
||||
{
|
||||
EventFlagTh *t = &e->waitingThreads[i];
|
||||
if (__KernelEventFlagMatches(&e->nef.currentPattern, t->bits, t->wait, t->outAddr))
|
||||
if (__KernelUnlockEventFlagForThread(e, *t, error, 0, wokeThreads))
|
||||
{
|
||||
__KernelResumeThreadFromWait(t->tid);
|
||||
wokeThreads = true;
|
||||
e->nef.numWaitThreads--;
|
||||
e->waitingThreads.erase(e->waitingThreads.begin() + i);
|
||||
goto retry;
|
||||
// Try the one that used to be in this place next.
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("event flag set");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@ -175,43 +297,80 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
// Actually RETURNs a u32
|
||||
void sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
|
||||
void __KernelEventFlagTimeout(u64 userdata, int cycleslate)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0)
|
||||
Memory::Write_U32(0, timeoutPtr);
|
||||
|
||||
SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(flagID, error);
|
||||
if (e)
|
||||
{
|
||||
EventFlagTh th;
|
||||
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
|
||||
for (size_t i = 0; i < e->waitingThreads.size(); i++)
|
||||
{
|
||||
// No match - must wait.
|
||||
e->nef.numWaitThreads++;
|
||||
th.tid = __KernelGetCurThread();
|
||||
th.bits = bits;
|
||||
th.wait = wait;
|
||||
th.outAddr = outBitsPtr;
|
||||
e->waitingThreads.push_back(th);
|
||||
u32 timeout;
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
EventFlagTh *t = &e->waitingThreads[i];
|
||||
if (t->tid == threadID)
|
||||
{
|
||||
bool wokeThreads;
|
||||
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, false); // sets RETURN
|
||||
// Do not set RETURN here; it's already set for us and we'd overwrite the wrong thread's RETURN
|
||||
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
|
||||
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
|
||||
// actually running, it will get a DELETE result instead of a TIMEOUT.
|
||||
// So, we need to remember it or we won't be able to mark it DELETE instead later.
|
||||
__KernelUnlockEventFlagForThread(e, *t, error, SCE_KERNEL_ERROR_WAIT_TIMEOUT, wokeThreads);
|
||||
e->nef.numWaitThreads--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Actually RETURNs a u32
|
||||
void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
|
||||
void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
if (timeoutPtr == 0 || eventFlagWaitTimer == 0)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// This seems like the actual timing of timeouts on hardware.
|
||||
if (micro <= 1)
|
||||
micro = 5;
|
||||
else if (micro <= 209)
|
||||
micro = 240;
|
||||
|
||||
// This should call __KernelEventFlagTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
void __KernelEventFlagRemoveThread(EventFlag *e, SceUID threadID)
|
||||
{
|
||||
for (size_t i = 0; i < e->waitingThreads.size(); i++)
|
||||
{
|
||||
EventFlagTh *t = &e->waitingThreads[i];
|
||||
if (t->tid == threadID)
|
||||
{
|
||||
e->waitingThreads.erase(e->waitingThreads.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
|
||||
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelWaitEventFlag(%i) invalid mode parameter: %08x", id, wait);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
// Can't wait on 0, that's guaranteed to wait forever.
|
||||
if (bits == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_ILPAT;
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
@ -220,30 +379,112 @@ void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
|
||||
EventFlagTh th;
|
||||
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
|
||||
{
|
||||
// If this thread was left in waitingThreads after a timeout, remove it.
|
||||
// Otherwise we might write the outBitsPtr in the wrong place.
|
||||
__KernelEventFlagRemoveThread(e, __KernelGetCurThread());
|
||||
|
||||
u32 timeout = 0xFFFFFFFF;
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// Do we allow more than one thread to wait?
|
||||
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_MULTI;
|
||||
|
||||
// No match - must wait.
|
||||
e->nef.numWaitThreads++;
|
||||
th.tid = __KernelGetCurThread();
|
||||
th.bits = bits;
|
||||
th.wait = wait;
|
||||
th.outAddr = outBitsPtr;
|
||||
// If < 5ms, sometimes hardware doesn't write this, but it's unpredictable.
|
||||
th.outAddr = timeout == 0 ? NULL : outBitsPtr;
|
||||
e->waitingThreads.push_back(th);
|
||||
u32 timeout;
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true); // sets RETURN
|
||||
__KernelCheckCallbacks();
|
||||
__KernelSetEventFlagTimeout(e, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
|
||||
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelWaitEventFlagCB(%i) invalid mode parameter: %08x", id, wait);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
// Can't wait on 0, that's guaranteed to wait forever.
|
||||
if (bits == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_ILPAT;
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
{
|
||||
EventFlagTh th;
|
||||
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
|
||||
{
|
||||
// If this thread was left in waitingThreads after a timeout, remove it.
|
||||
// Otherwise we might write the outBitsPtr in the wrong place.
|
||||
__KernelEventFlagRemoveThread(e, __KernelGetCurThread());
|
||||
|
||||
u32 timeout = 0xFFFFFFFF;
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// Do we allow more than one thread to wait?
|
||||
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_MULTI;
|
||||
|
||||
// No match - must wait.
|
||||
e->nef.numWaitThreads++;
|
||||
th.tid = __KernelGetCurThread();
|
||||
th.bits = bits;
|
||||
th.wait = wait;
|
||||
// If < 5ms, sometimes hardware doesn't write this, but it's unpredictable.
|
||||
th.outAddr = timeout == 0 ? NULL : outBitsPtr;
|
||||
e->waitingThreads.push_back(th);
|
||||
|
||||
__KernelSetEventFlagTimeout(e, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true);
|
||||
}
|
||||
else
|
||||
hleCheckCurrentCallbacks();
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
|
||||
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
// Poll seems to also fail when CLEAR and CLEARALL are used together, but not wait.
|
||||
if ((wait & PSP_EVENT_WAITCLEAR) != 0 && (wait & PSP_EVENT_WAITCLEARALL) != 0)
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
// Can't wait on 0, it never matches.
|
||||
if (bits == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_ILPAT;
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
@ -253,6 +494,10 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
{
|
||||
if (Memory::IsValidAddress(outBitsPtr))
|
||||
Memory::Write_U32(e->nef.currentPattern, outBitsPtr);
|
||||
|
||||
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_MULTI;
|
||||
|
||||
// No match - return that, this is polling, not waiting.
|
||||
return SCE_KERNEL_ERROR_EVF_COND;
|
||||
}
|
||||
@ -270,7 +515,7 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
//int sceKernelReferEventFlagStatus(SceUID event, SceKernelEventFlagInfo *status);
|
||||
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelReferEventFlagStatus(%i, %08x)", id, statusPtr);
|
||||
DEBUG_LOG(HLE, "sceKernelReferEventFlagStatus(%i, %08x)", id, statusPtr);
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
@ -283,10 +528,3 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// never seen this one
|
||||
u32 sceKernelCancelEventFlag()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL: sceKernelCancelEventFlag()");
|
||||
return 0;
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte
|
||||
u32 sceKernelClearEventFlag(SceUID id, u32 bits);
|
||||
u32 sceKernelDeleteEventFlag(SceUID uid);
|
||||
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet);
|
||||
void sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr);
|
||||
u32 sceKernelCancelEventFlag();
|
||||
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr);
|
||||
|
@ -26,8 +26,9 @@
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelInterrupt.h"
|
||||
#include "sceKernelMutex.h"
|
||||
|
||||
struct Interrupt
|
||||
struct Interrupt
|
||||
{
|
||||
PSPInterrupt intno;
|
||||
};
|
||||
@ -199,10 +200,12 @@ public:
|
||||
{
|
||||
return subIntrHandlers.find(subIntrNum) != subIntrHandlers.end();
|
||||
}
|
||||
SubIntrHandler &get(int subIntrNum)
|
||||
SubIntrHandler *get(int subIntrNum)
|
||||
{
|
||||
if (has(subIntrNum))
|
||||
return subIntrHandlers[subIntrNum];
|
||||
return &subIntrHandlers[subIntrNum];
|
||||
else
|
||||
return 0;
|
||||
// what to do, what to do...
|
||||
}
|
||||
|
||||
@ -328,7 +331,7 @@ u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handl
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x)", intrNumber, subIntrNumber, handler, handlerArg);
|
||||
|
||||
if (intrNumber < 0 || intrNumber >= PSP_NUMBER_INTERRUPTS)
|
||||
if (intrNumber >= PSP_NUMBER_INTERRUPTS)
|
||||
return -1;
|
||||
|
||||
SubIntrHandler subIntrHandler;
|
||||
@ -346,12 +349,12 @@ u32 sceKernelReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber)
|
||||
|
||||
// TODO: should check if it's pending and remove it from pending list! (although that's probably unlikely)
|
||||
|
||||
if (intrNumber < 0 || intrNumber >= PSP_NUMBER_INTERRUPTS)
|
||||
if (intrNumber >= PSP_NUMBER_INTERRUPTS)
|
||||
return -1;
|
||||
|
||||
if (!intrHandlers[intrNumber].has(subIntrNumber))
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
|
||||
intrHandlers[intrNumber].remove(subIntrNumber);
|
||||
return 0;
|
||||
}
|
||||
@ -364,8 +367,8 @@ u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber)
|
||||
|
||||
if (!intrHandlers[intrNumber].has(subIntrNumber))
|
||||
return -1;
|
||||
|
||||
intrHandlers[intrNumber].get(subIntrNumber).enabled = true;
|
||||
|
||||
intrHandlers[intrNumber].get(subIntrNumber)->enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -378,7 +381,7 @@ u32 sceKernelDisableSubIntr(u32 intrNumber, u32 subIntrNumber)
|
||||
if (!intrHandlers[intrNumber].has(subIntrNumber))
|
||||
return -1;
|
||||
|
||||
intrHandlers[intrNumber].get(subIntrNumber).enabled = false;
|
||||
intrHandlers[intrNumber].get(subIntrNumber)->enabled = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -415,7 +418,17 @@ void sceKernelMemset()
|
||||
DEBUG_LOG(HLE, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
Memory::Write_U8((u8)c, addr + i);
|
||||
RETURN(addr); /* TODO: verify it should return this */
|
||||
RETURN(0); /* TODO: verify it should return this */
|
||||
}
|
||||
|
||||
u32 sceKernelMemcpy(u32 dst, u32 src, u32 size)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
|
||||
if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src+size)) // a bit of bound checking. Wrong??
|
||||
{
|
||||
Memory::Memcpy(dst, Memory::GetPointer(src), size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HLEFunction Kernel_Library[] =
|
||||
@ -426,13 +439,13 @@ const HLEFunction Kernel_Library[] =
|
||||
{0x47a0b729,sceKernelIsCpuIntrSuspended, "sceKernelIsCpuIntrSuspended"}, //flags
|
||||
{0xb55249d2,sceKernelIsCpuIntrEnable, "sceKernelIsCpuIntrEnable"},
|
||||
{0xa089eca4,sceKernelMemset, "sceKernelMemset"},
|
||||
{0xDC692EE3,0, "sceKernelTryLockLwMutex"},
|
||||
{0xbea46419,0, "sceKernelLockLwMutex"},
|
||||
{0x1FC64E09,0, "sceKernelLockLwMutexCB"},
|
||||
{0x15b6446b,0, "sceKernelUnlockLwMutex"},
|
||||
{0xDC692EE3,&WrapI_UI<sceKernelTryLockLwMutex>, "sceKernelTryLockLwMutex"},
|
||||
{0x37431849,&WrapI_UI<sceKernelTryLockLwMutex_600>, "sceKernelTryLockLwMutex_600"},
|
||||
{0xbea46419,&WrapI_UIU<sceKernelLockLwMutex>, "sceKernelLockLwMutex"},
|
||||
{0x1FC64E09,&WrapI_UIU<sceKernelLockLwMutexCB>, "sceKernelLockLwMutexCB"},
|
||||
{0x15b6446b,&WrapI_UI<sceKernelUnlockLwMutex>, "sceKernelUnlockLwMutex"},
|
||||
{0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"},
|
||||
{0x1839852A,0,"sce_paf_private_memcpy"},
|
||||
{0xA089ECA4,0,"sce_paf_private_memset"},
|
||||
{0x1839852A,&WrapU_UUU<sceKernelMemcpy>,"sce_paf_private_memcpy"},
|
||||
};
|
||||
|
||||
void Register_Kernel_Library()
|
||||
|
@ -19,23 +19,31 @@
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelMbx.h"
|
||||
#include "HLE.h"
|
||||
#include "../../Core/CoreTiming.h"
|
||||
|
||||
#define SCE_KERNEL_MBA_THPRI 0x100
|
||||
#define SCE_KERNEL_MBA_MSPRI 0x400
|
||||
#define SCE_KERNEL_MBA_ATTR_KNOWN (SCE_KERNEL_MBA_THPRI | SCE_KERNEL_MBA_MSPRI)
|
||||
|
||||
// TODO: when a thread is being resumed (message received or cancellation), sceKernelReceiveMbx() always returns 0
|
||||
const int PSP_MBX_ERROR_DUPLICATE_MSG = 0x800201C9;
|
||||
|
||||
typedef std::pair<SceUID, u32> MbxWaitingThread;
|
||||
void __KernelMbxTimeout(u64 userdata, int cyclesLate);
|
||||
|
||||
bool mbxInitComplete = false;
|
||||
int mbxWaitTimer = 0;
|
||||
|
||||
struct NativeMbx
|
||||
{
|
||||
SceSize size;
|
||||
char name[32];
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
SceUInt attr;
|
||||
int numWaitThreads;
|
||||
int numMessages;
|
||||
u32 packetListHead;
|
||||
};
|
||||
|
||||
struct Mbx : public KernelObject
|
||||
struct Mbx : public KernelObject
|
||||
{
|
||||
const char *GetName() {return nmb.name;}
|
||||
const char *GetTypeName() {return "Mbx";}
|
||||
@ -44,43 +52,250 @@ struct Mbx : public KernelObject
|
||||
|
||||
void AddWaitingThread(SceUID id, u32 addr)
|
||||
{
|
||||
bool inserted = false;
|
||||
if (nmb.attr & SCE_KERNEL_MBA_THPRI)
|
||||
{
|
||||
for (std::vector<std::pair<SceUID, u32>>::iterator it = waitingThreads.begin(); it != waitingThreads.end(); it++)
|
||||
for (std::vector<MbxWaitingThread>::iterator it = waitingThreads.begin(); it != waitingThreads.end(); it++)
|
||||
{
|
||||
if (__KernelGetThreadPrio(id) >= __KernelGetThreadPrio((*it).first))
|
||||
if (__KernelGetThreadPrio(id) < __KernelGetThreadPrio((*it).first))
|
||||
{
|
||||
waitingThreads.insert(it, std::make_pair(id, addr));
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!inserted)
|
||||
waitingThreads.push_back(std::make_pair(id, addr));
|
||||
}
|
||||
|
||||
inline void AddInitialMessage(u32 ptr)
|
||||
{
|
||||
nmb.numMessages++;
|
||||
Memory::Write_U32(ptr, ptr);
|
||||
nmb.packetListHead = ptr;
|
||||
}
|
||||
|
||||
inline void AddFirstMessage(u32 endPtr, u32 ptr)
|
||||
{
|
||||
nmb.numMessages++;
|
||||
Memory::Write_U32(nmb.packetListHead, ptr);
|
||||
Memory::Write_U32(ptr, endPtr);
|
||||
nmb.packetListHead = ptr;
|
||||
}
|
||||
|
||||
inline void AddLastMessage(u32 endPtr, u32 ptr)
|
||||
{
|
||||
nmb.numMessages++;
|
||||
Memory::Write_U32(ptr, endPtr);
|
||||
Memory::Write_U32(nmb.packetListHead, ptr);
|
||||
}
|
||||
|
||||
inline void AddMessage(u32 beforePtr, u32 afterPtr, u32 ptr)
|
||||
{
|
||||
nmb.numMessages++;
|
||||
Memory::Write_U32(afterPtr, ptr);
|
||||
Memory::Write_U32(ptr, beforePtr);
|
||||
}
|
||||
|
||||
int ReceiveMessage(u32 receivePtr)
|
||||
{
|
||||
u32 ptr = nmb.packetListHead;
|
||||
|
||||
if (nmb.numMessages == 991)
|
||||
{
|
||||
u32 next = Memory::Read_U32(nmb.packetListHead);
|
||||
u32 next2 = Memory::Read_U32(next);
|
||||
if (next2 == ptr && next != ptr)
|
||||
{
|
||||
Memory::Write_U32(next, next);
|
||||
nmb.packetListHead = next;
|
||||
}
|
||||
else
|
||||
nmb.packetListHead = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
waitingThreads.push_back(std::make_pair(id, addr));
|
||||
// Check over the linked list and reset the head.
|
||||
int c = 0;
|
||||
while (true)
|
||||
{
|
||||
u32 next = Memory::Read_U32(nmb.packetListHead);
|
||||
if (!Memory::IsValidAddress(next))
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
|
||||
if (next == ptr)
|
||||
{
|
||||
if (nmb.packetListHead != ptr)
|
||||
{
|
||||
next = Memory::Read_U32(next);
|
||||
Memory::Write_U32(next, nmb.packetListHead);
|
||||
nmb.packetListHead = next;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c < nmb.numMessages - 1)
|
||||
return PSP_MBX_ERROR_DUPLICATE_MSG;
|
||||
|
||||
nmb.packetListHead = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nmb.packetListHead = next;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the receiver about the message.
|
||||
Memory::Write_U32(ptr, receivePtr);
|
||||
nmb.numMessages--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NativeMbx nmb;
|
||||
|
||||
std::vector<std::pair<SceUID, u32>> waitingThreads;
|
||||
std::vector<u32> messageQueue;
|
||||
std::vector<MbxWaitingThread> waitingThreads;
|
||||
};
|
||||
|
||||
SceUID sceKernelCreateMbx(const char *name, int memoryPartition, SceUInt attr, int size, u32 optAddr)
|
||||
void __KernelMbxInit()
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCreateMbx(%s, %i, %08x, %i, %08x)", name, memoryPartition, attr, size, optAddr);
|
||||
mbxWaitTimer = CoreTiming::RegisterEvent("MbxTimeout", &__KernelMbxTimeout);
|
||||
|
||||
mbxInitComplete = true;
|
||||
}
|
||||
|
||||
bool __KernelUnlockMbxForThread(Mbx *m, MbxWaitingThread &th, u32 &error, int result, bool &wokeThreads)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(th.first, WAITTYPE_MBX, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.first, error);
|
||||
|
||||
// The waitID may be different after a timeout.
|
||||
if (waitID != m->GetUID())
|
||||
return true;
|
||||
|
||||
if (timeoutPtr != 0 && mbxWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
u64 cyclesLeft = CoreTiming::UnscheduleEvent(mbxWaitTimer, th.first);
|
||||
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(th.first, result);
|
||||
wokeThreads = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void __KernelMbxTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
u32 error;
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0)
|
||||
Memory::Write_U32(0, timeoutPtr);
|
||||
|
||||
SceUID mbxID = __KernelGetWaitID(threadID, WAITTYPE_MBX, error);
|
||||
Mbx *m = kernelObjects.Get<Mbx>(mbxID, error);
|
||||
if (m)
|
||||
{
|
||||
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
|
||||
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
|
||||
// actually running, it will get a DELETE result instead of a TIMEOUT.
|
||||
// So, we need to remember it or we won't be able to mark it DELETE instead later.
|
||||
|
||||
// TODO: Should numWaitThreads be decreased yet?
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
void __KernelWaitMbx(Mbx *m, u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || mbxWaitTimer == 0)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// This seems to match the actual timing.
|
||||
if (micro <= 2)
|
||||
micro = 10;
|
||||
else if (micro <= 209)
|
||||
micro = 250;
|
||||
|
||||
// This should call __KernelMbxTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mbxWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
void __KernelMbxRemoveThread(Mbx *m, SceUID threadID)
|
||||
{
|
||||
for (size_t i = 0; i < m->waitingThreads.size(); i++)
|
||||
{
|
||||
MbxWaitingThread *t = &m->waitingThreads[i];
|
||||
if (t->first == threadID)
|
||||
{
|
||||
m->waitingThreads.erase(m->waitingThreads.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<MbxWaitingThread>::iterator __KernelMbxFindPriority(std::vector<MbxWaitingThread> &waiting)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
|
||||
|
||||
std::vector<MbxWaitingThread>::iterator iter, end, best = waiting.end();
|
||||
u32 best_prio = 0xFFFFFFFF;
|
||||
for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter)
|
||||
{
|
||||
u32 iter_prio = __KernelGetThreadPrio(iter->first);
|
||||
if (iter_prio < best_prio)
|
||||
{
|
||||
best = iter;
|
||||
best_prio = iter_prio;
|
||||
}
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(HLE, best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread.");
|
||||
return best;
|
||||
}
|
||||
|
||||
SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr)
|
||||
{
|
||||
if (!mbxInitComplete)
|
||||
__KernelMbxInit();
|
||||
|
||||
if (!name)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=%s(): invalid name", SCE_KERNEL_ERROR_ERROR, __FUNCTION__);
|
||||
return SCE_KERNEL_ERROR_ERROR;
|
||||
}
|
||||
// Accepts 0x000 - 0x0FF, 0x100 - 0x1FF, and 0x400 - 0x4FF.
|
||||
if (((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) & ~0xFF) != 0)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=%s(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, __FUNCTION__, attr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
|
||||
}
|
||||
|
||||
Mbx *m = new Mbx();
|
||||
SceUID id = kernelObjects.Create(m);
|
||||
|
||||
m->nmb.size = sizeof(NativeMbx);
|
||||
strncpy(m->nmb.name, name, sizeof(m->nmb.name));
|
||||
strncpy(m->nmb.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
m->nmb.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||
m->nmb.attr = attr;
|
||||
m->nmb.numWaitThreads = 0;
|
||||
m->nmb.numMessages = 0;
|
||||
m->nmb.packetListHead = 0;
|
||||
|
||||
DEBUG_LOG(HLE, "%i=sceKernelCreateMbx(%s, %08x, %08x)", id, name, attr, optAddr);
|
||||
|
||||
if (optAddr != 0)
|
||||
WARN_LOG(HLE, "%s(%s) unsupported options parameter: %08x", __FUNCTION__, name, optAddr);
|
||||
if ((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) != 0)
|
||||
WARN_LOG(HLE, "%s(%s) unsupported attr parameter: %08x", __FUNCTION__, name, attr);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -91,11 +306,14 @@ int sceKernelDeleteMbx(SceUID id)
|
||||
if (m)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteMbx(%i)", id);
|
||||
|
||||
bool wokeThreads = false;
|
||||
for (size_t i = 0; i < m->waitingThreads.size(); i++)
|
||||
{
|
||||
Memory::Write_U32(0, m->waitingThreads[i].second);
|
||||
__KernelResumeThreadFromWait(m->waitingThreads[i].first);
|
||||
}
|
||||
__KernelUnlockMbxForThread(m, m->waitingThreads[i], error, SCE_KERNEL_ERROR_WAIT_DELETE, wokeThreads);
|
||||
m->waitingThreads.clear();
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("mbx deleted");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -104,63 +322,99 @@ int sceKernelDeleteMbx(SceUID id)
|
||||
return kernelObjects.Destroy<Mbx>(id);
|
||||
}
|
||||
|
||||
void sceKernelSendMbx(SceUID id, u32 packetAddr)
|
||||
int sceKernelSendMbx(SceUID id, u32 packetAddr)
|
||||
{
|
||||
u32 error;
|
||||
Mbx *m = kernelObjects.Get<Mbx>(id, error);
|
||||
if (!m)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeMbxPacket *addPacket = (NativeMbxPacket*)Memory::GetPointer(packetAddr);
|
||||
if (addPacket == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid packet address", id, packetAddr);
|
||||
RETURN(-1);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!m)
|
||||
// If the queue is empty, maybe someone is waiting.
|
||||
// We have to check them first, they might've timed out.
|
||||
if (m->nmb.numMessages == 0)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr);
|
||||
RETURN(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m->waitingThreads.empty())
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr);
|
||||
if (m->nmb.attr & SCE_KERNEL_MBA_MSPRI)
|
||||
bool wokeThreads = false;
|
||||
std::vector<MbxWaitingThread>::iterator iter;
|
||||
while (!wokeThreads && !m->waitingThreads.empty())
|
||||
{
|
||||
for (std::vector<u32>::iterator it = m->messageQueue.begin(); it != m->messageQueue.end(); it++)
|
||||
if ((m->nmb.attr & SCE_KERNEL_MBA_THPRI) != 0)
|
||||
iter = __KernelMbxFindPriority(m->waitingThreads);
|
||||
else
|
||||
iter = m->waitingThreads.begin();
|
||||
|
||||
MbxWaitingThread t = *iter;
|
||||
__KernelUnlockMbxForThread(m, t, error, 0, wokeThreads);
|
||||
m->waitingThreads.erase(iter);
|
||||
|
||||
if (wokeThreads)
|
||||
{
|
||||
NativeMbxPacket *p = (NativeMbxPacket*)Memory::GetPointer(*it);
|
||||
if (addPacket->priority >= p->priority)
|
||||
{
|
||||
m->messageQueue.insert(it, packetAddr);
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, t.first);
|
||||
Memory::Write_U32(packetAddr, t.second);
|
||||
hleReSchedule("mbx sent");
|
||||
|
||||
// We don't need to do anything else, finish here.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m->messageQueue.push_back(packetAddr);
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
else if (m->messageQueue.empty())
|
||||
{
|
||||
Memory::Write_U32(packetAddr, m->waitingThreads.front().second);
|
||||
__KernelResumeThreadFromWait(m->waitingThreads.front().first);
|
||||
DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, m->waitingThreads.front().first);
|
||||
m->waitingThreads.erase(m->waitingThreads.begin());
|
||||
RETURN(0);
|
||||
__KernelReSchedule();
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr);
|
||||
|
||||
if (m->nmb.numMessages == 0)
|
||||
m->AddInitialMessage(packetAddr);
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): WTF!? thread waiting while there is a message in the queue?", id, packetAddr);
|
||||
RETURN(-1);
|
||||
u32 next = m->nmb.packetListHead, prev;
|
||||
for (int i = 0, n = m->nmb.numMessages; i < n; i++)
|
||||
{
|
||||
if (next == packetAddr)
|
||||
return PSP_MBX_ERROR_DUPLICATE_MSG;
|
||||
if (!Memory::IsValidAddress(next))
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
|
||||
|
||||
prev = next;
|
||||
next = Memory::Read_U32(next);
|
||||
}
|
||||
|
||||
bool inserted = false;
|
||||
if (m->nmb.attr & SCE_KERNEL_MBA_MSPRI)
|
||||
{
|
||||
NativeMbxPacket p;
|
||||
for (int i = 0, n = m->nmb.numMessages; i < n; i++)
|
||||
{
|
||||
Memory::ReadStruct<NativeMbxPacket>(next, &p);
|
||||
if (addPacket->priority < p.priority)
|
||||
{
|
||||
if (i == 0)
|
||||
m->AddFirstMessage(prev, packetAddr);
|
||||
else
|
||||
m->AddMessage(prev, next, packetAddr);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = next;
|
||||
next = Memory::Read_U32(next);
|
||||
}
|
||||
}
|
||||
if (!inserted)
|
||||
m->AddLastMessage(prev, packetAddr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
|
||||
int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
Mbx *m = kernelObjects.Get<Mbx>(id, error);
|
||||
@ -168,52 +422,50 @@ void sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
|
||||
if (!m)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelReceiveMbx(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr);
|
||||
RETURN(error);
|
||||
return;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!m->messageQueue.empty())
|
||||
if (m->nmb.numMessages > 0)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelReceiveMbx(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr);
|
||||
Memory::Write_U32(m->messageQueue.front(), packetAddrPtr);
|
||||
m->messageQueue.erase(m->messageQueue.begin());
|
||||
RETURN(0);
|
||||
return m->ReceiveMessage(packetAddrPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr);
|
||||
__KernelMbxRemoveThread(m, __KernelGetCurThread());
|
||||
m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr);
|
||||
RETURN(0);
|
||||
__KernelWaitCurThread(WAITTYPE_MBX, 0, 0, 0, false); // ?
|
||||
__KernelWaitMbx(m, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
|
||||
int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
Mbx *m = kernelObjects.Get<Mbx>(id, error);
|
||||
__KernelCheckCallbacks();
|
||||
|
||||
if (!m)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelReceiveMbxCB(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr);
|
||||
RETURN(error);
|
||||
return;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!m->messageQueue.empty())
|
||||
if (m->nmb.numMessages > 0)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelReceiveMbxCB(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr);
|
||||
Memory::Write_U32(m->messageQueue.front(), packetAddrPtr);
|
||||
m->messageQueue.erase(m->messageQueue.begin());
|
||||
RETURN(0);
|
||||
hleCheckCurrentCallbacks();
|
||||
return m->ReceiveMessage(packetAddrPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr);
|
||||
m->AddWaitingThread(id, packetAddrPtr);
|
||||
RETURN(0);
|
||||
__KernelWaitCurThread(WAITTYPE_MBX, 0, 0, 0, true); // ?
|
||||
__KernelMbxRemoveThread(m, __KernelGetCurThread());
|
||||
m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr);
|
||||
__KernelWaitMbx(m, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,12 +480,10 @@ int sceKernelPollMbx(SceUID id, u32 packetAddrPtr)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!m->messageQueue.empty())
|
||||
if (m->nmb.numMessages > 0)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelPollMbx(%i, %08x): sending first queue message", id, packetAddrPtr);
|
||||
Memory::Write_U32(m->messageQueue.front(), packetAddrPtr);
|
||||
m->messageQueue.erase(m->messageQueue.begin());
|
||||
return 0;
|
||||
return m->ReceiveMessage(packetAddrPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -246,7 +496,6 @@ int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr)
|
||||
{
|
||||
u32 error;
|
||||
Mbx *m = kernelObjects.Get<Mbx>(id, error);
|
||||
int *numWaitingThreads = (int*)Memory::GetPointer(numWaitingThreadsAddr);
|
||||
|
||||
if (!m)
|
||||
{
|
||||
@ -256,14 +505,17 @@ int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr)
|
||||
|
||||
u32 count = m->waitingThreads.size();
|
||||
DEBUG_LOG(HLE, "sceKernelCancelReceiveMbx(%i, %08x): cancelling %d threads", id, numWaitingThreadsAddr, count);
|
||||
|
||||
bool wokeThreads = false;
|
||||
for (size_t i = 0; i < m->waitingThreads.size(); i++)
|
||||
{
|
||||
Memory::Write_U32(0, m->waitingThreads[i].second);
|
||||
__KernelResumeThreadFromWait(m->waitingThreads[i].first);
|
||||
}
|
||||
__KernelUnlockMbxForThread(m, m->waitingThreads[i], error, SCE_KERNEL_ERROR_WAIT_CANCEL, wokeThreads);
|
||||
m->waitingThreads.clear();
|
||||
if (numWaitingThreads)
|
||||
*numWaitingThreads = count;
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("mbx canceled");
|
||||
|
||||
if (numWaitingThreadsAddr)
|
||||
Memory::Write_U32(count, numWaitingThreadsAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -277,34 +529,19 @@ int sceKernelReferMbxStatus(SceUID id, u32 infoAddr)
|
||||
return error;
|
||||
}
|
||||
|
||||
SceKernelMbxInfo *info = (SceKernelMbxInfo*)Memory::GetPointer(infoAddr);
|
||||
DEBUG_LOG(HLE, "sceKernelReferMbxStatus(%i, %08x)", id, infoAddr);
|
||||
if (info)
|
||||
{
|
||||
strncpy(info->name, m->nmb.name, 32);
|
||||
info->attr = m->nmb.attr;
|
||||
info->numWaitThreads = m->waitingThreads.size();
|
||||
info->numMessage = m->messageQueue.size();
|
||||
// Fill the 'next' parameter of packets which we don't use by default but could be used by a game
|
||||
if (m->messageQueue.size() != 0)
|
||||
{
|
||||
info->topPacketAddr = m->messageQueue[0];
|
||||
for (u32 i = 0; i < m->messageQueue.size() - 1; i++)
|
||||
{
|
||||
Memory::Write_U32(m->messageQueue[i + 1], Memory::Read_U32(m->messageQueue[i]));
|
||||
}
|
||||
Memory::Write_U32(m->messageQueue[m->messageQueue.size() - 1], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->topPacketAddr = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should we crash the thread somehow?
|
||||
if (!Memory::IsValidAddress(infoAddr))
|
||||
return -1;
|
||||
|
||||
for (int i = 0, n = m->nmb.numMessages; i < n; ++i)
|
||||
m->nmb.packetListHead = Memory::Read_U32(m->nmb.packetListHead);
|
||||
|
||||
// For whatever reason, it won't write if the size (first member) is 0.
|
||||
if (Memory::Read_U32(infoAddr) != 0)
|
||||
{
|
||||
m->nmb.numWaitThreads = m->waitingThreads.size();
|
||||
Memory::WriteStruct<NativeMbx>(infoAddr, &m->nmb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -24,22 +24,11 @@ struct NativeMbxPacket
|
||||
u8 padding[3];
|
||||
};
|
||||
|
||||
struct SceKernelMbxInfo
|
||||
{
|
||||
SceSize size;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
SceUInt attr;
|
||||
int numWaitThreads;
|
||||
int numMessage;
|
||||
u32 topPacketAddr;
|
||||
};
|
||||
|
||||
SceUID sceKernelCreateMbx(const char *name, int memoryPartition, SceUInt attr, int size, u32 optAddr);
|
||||
SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr);
|
||||
int sceKernelDeleteMbx(SceUID id);
|
||||
void sceKernelSendMbx(SceUID id, u32 addPacketAddr);
|
||||
void sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr);
|
||||
void sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr);
|
||||
int sceKernelSendMbx(SceUID id, u32 addPacketAddr);
|
||||
int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr);
|
||||
int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr);
|
||||
int sceKernelPollMbx(SceUID id, u32 packetAddrPtr);
|
||||
int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr);
|
||||
int sceKernelReferMbxStatus(SceUID id, u32 infoAddr);
|
||||
|
||||
|
@ -515,13 +515,12 @@ void sceKernelAllocateVpl()
|
||||
if (vpl)
|
||||
{
|
||||
u32 size = PARAM(1);
|
||||
u32 *blockPtrPtr = (u32 *)Memory::GetPointer(PARAM(2));
|
||||
int timeOut = PARAM(2);
|
||||
int timeOut = PARAM(3);
|
||||
DEBUG_LOG(HLE,"sceKernelAllocateVpl(vpl=%i, size=%i, ptrout= %08x , timeout=%i)", id, size, PARAM(2), timeOut);
|
||||
u32 addr = vpl->alloc.Alloc(size);
|
||||
if (addr != (u32)-1)
|
||||
{
|
||||
*blockPtrPtr = addr;
|
||||
Memory::Write_U32(addr, PARAM(2));
|
||||
RETURN(0);
|
||||
}
|
||||
else
|
||||
@ -545,13 +544,12 @@ void sceKernelAllocateVplCB()
|
||||
if (vpl)
|
||||
{
|
||||
u32 size = PARAM(1);
|
||||
u32 *blockPtrPtr = (u32 *)Memory::GetPointer(PARAM(2));
|
||||
int timeOut = PARAM(2);
|
||||
int timeOut = PARAM(3);
|
||||
DEBUG_LOG(HLE,"sceKernelAllocateVplCB(vpl=%i, size=%i, ptrout= %08x , timeout=%i)", id, size, PARAM(2), timeOut);
|
||||
u32 addr = vpl->alloc.Alloc(size);
|
||||
if (addr != (u32)-1)
|
||||
{
|
||||
*blockPtrPtr = addr;
|
||||
Memory::Write_U32(addr, PARAM(2));
|
||||
RETURN(0);
|
||||
}
|
||||
else
|
||||
@ -576,13 +574,12 @@ void sceKernelTryAllocateVpl()
|
||||
if (vpl)
|
||||
{
|
||||
u32 size = PARAM(1);
|
||||
u32 *blockPtrPtr = (u32 *)Memory::GetPointer(PARAM(2));
|
||||
int timeOut = PARAM(2);
|
||||
int timeOut = PARAM(3);
|
||||
DEBUG_LOG(HLE,"sceKernelAllocateVplCB(vpl=%i, size=%i, ptrout= %08x , timeout=%i)", id, size, PARAM(2), timeOut);
|
||||
u32 addr = vpl->alloc.Alloc(size);
|
||||
if (addr != (u32)-1)
|
||||
{
|
||||
*blockPtrPtr = addr;
|
||||
Memory::Write_U32(addr, PARAM(2));
|
||||
RETURN(0);
|
||||
}
|
||||
else
|
||||
@ -634,9 +631,8 @@ void sceKernelReferVplStatus()
|
||||
if (v)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelReferVplStatus(%i, %08x)", id, PARAM(1));
|
||||
SceKernelVplInfo *info = (SceKernelVplInfo*)Memory::GetPointer(PARAM(1));
|
||||
v->nv.freeSize = v->alloc.GetTotalFreeBytes();
|
||||
*info = v->nv;
|
||||
Memory::WriteStruct(PARAM(1), &v->nv);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -692,7 +688,7 @@ const HLEFunction SysMemUserForUser[] =
|
||||
{0xf77d77cb,sceKernelSetCompilerVersion,"sceKernelSetCompilerVersion"},
|
||||
{0x35669d4c,0,"sceKernelSetCompiledSdkVersion600_602"}, //??
|
||||
{0x1b4217bc,0,"sceKernelSetCompiledSdkVersion603_605"},
|
||||
|
||||
{0x358ca1bb,0,"sceKernelSetCompiledSdkVersion606"},
|
||||
// Obscure raw block API
|
||||
{0xDB83A952,GetMemoryBlockPtr,"SysMemUserForUser_DB83A952"}, // GetMemoryBlockAddr
|
||||
{0x91DE343C,0,"SysMemUserForUser_91DE343C"},
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "HLE.h"
|
||||
|
||||
#include "Common/Action.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "../Host.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
@ -57,37 +57,71 @@ static const char *blacklistedModules[] = {
|
||||
"sceNet_Library",
|
||||
};
|
||||
|
||||
struct Module : public KernelObject
|
||||
struct NativeModule {
|
||||
u32 next;
|
||||
u16 attribute;
|
||||
u8 version[2];
|
||||
char name[28];
|
||||
u32 status;
|
||||
u32 unk1;
|
||||
u32 usermod_thid;
|
||||
u32 memid;
|
||||
u32 mpidtext;
|
||||
u32 mpiddata;
|
||||
u32 ent_top;
|
||||
u32 ent_size;
|
||||
u32 stub_top;
|
||||
u32 stub_size;
|
||||
u32 module_start_func;
|
||||
u32 module_stop_func;
|
||||
u32 module_bootstart_func;
|
||||
u32 module_reboot_before_func;
|
||||
u32 module_reboot_phase_func;
|
||||
u32 entry_addr;
|
||||
u32 gp_value;
|
||||
u32 text_addr;
|
||||
u32 text_size;
|
||||
u32 data_size;
|
||||
u32 bss_size;
|
||||
u32 nsegment;
|
||||
u32 segmentaddr[4];
|
||||
u32 segmentsize[4];
|
||||
u32 module_start_thread_priority;
|
||||
u32 module_start_thread_stacksize;
|
||||
u32 module_start_thread_attr;
|
||||
u32 module_stop_thread_priority;
|
||||
u32 module_stop_thread_stacksize;
|
||||
u32 module_stop_thread_attr;
|
||||
u32 module_reboot_before_thread_priority;
|
||||
u32 module_reboot_before_thread_stacksize;
|
||||
u32 module_reboot_before_thread_attr;
|
||||
};
|
||||
|
||||
class Module : public KernelObject
|
||||
{
|
||||
const char *GetName() {return name;}
|
||||
public:
|
||||
Module() : memoryBlockAddr(0) {}
|
||||
~Module() {
|
||||
if (memoryBlockAddr) {
|
||||
userMemory.Free(memoryBlockAddr);
|
||||
}
|
||||
}
|
||||
const char *GetName() {return nm.name;}
|
||||
const char *GetTypeName() {return "Module";}
|
||||
void GetQuickInfo(char *ptr, int size)
|
||||
{
|
||||
// ignore size
|
||||
sprintf(ptr, "name=%s gp=%08x entry=%08x",
|
||||
name,
|
||||
gp_value,
|
||||
entry_addr);
|
||||
nm.name,
|
||||
nm.gp_value,
|
||||
nm.entry_addr);
|
||||
}
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MODULE; }
|
||||
int GetIDType() const { return 0; }
|
||||
|
||||
SceSize size;
|
||||
char nsegment;
|
||||
char reserved[3];
|
||||
int segmentaddr[4];
|
||||
int segmentsize[4];
|
||||
unsigned int entry_addr;
|
||||
unsigned int gp_value;
|
||||
unsigned int text_addr;
|
||||
unsigned int text_size;
|
||||
unsigned int data_size;
|
||||
unsigned int bss_size;
|
||||
// The following is only available in the v1.5 firmware and above,
|
||||
// but as sceKernelQueryModuleInfo is broken in v1.0 it doesn't matter.
|
||||
unsigned short attribute;
|
||||
unsigned char version[2];
|
||||
char name[28];
|
||||
NativeModule nm;
|
||||
|
||||
u32 memoryBlockAddr;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -183,6 +217,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
kernelObjects.Destroy<Module>(module->GetUID());
|
||||
return 0;
|
||||
}
|
||||
module->memoryBlockAddr = reader.GetVaddr();
|
||||
|
||||
struct libent
|
||||
{
|
||||
@ -256,8 +291,8 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
}
|
||||
}
|
||||
|
||||
module->gp_value = modinfo->gp;
|
||||
strncpy(module->name, modinfo->name, 28);
|
||||
module->nm.gp_value = modinfo->gp;
|
||||
strncpy(module->nm.name, modinfo->name, 28);
|
||||
|
||||
INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub);
|
||||
|
||||
@ -341,7 +376,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
if (ent->name == 0)
|
||||
{
|
||||
// ?
|
||||
name = module->name;
|
||||
name = module->nm.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -368,7 +403,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
}
|
||||
}
|
||||
|
||||
module->entry_addr = reader.GetEntryPoint();
|
||||
module->nm.entry_addr = reader.GetEntryPoint();
|
||||
|
||||
if (newptr)
|
||||
{
|
||||
@ -418,7 +453,7 @@ bool __KernelLoadPBP(const char *filename, std::string *error_string)
|
||||
Module *module = __KernelLoadELFFromPtr(temp, PSP_GetDefaultLoadAddress(), error_string);
|
||||
if (!module)
|
||||
return false;
|
||||
mipsr4k.pc = module->entry_addr;
|
||||
mipsr4k.pc = module->nm.entry_addr;
|
||||
delete [] temp;
|
||||
}
|
||||
in.close();
|
||||
@ -460,13 +495,13 @@ void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOptio
|
||||
}
|
||||
|
||||
|
||||
u32 __KernelGetModuleGP(SceUID module)
|
||||
u32 __KernelGetModuleGP(SceUID uid)
|
||||
{
|
||||
u32 error;
|
||||
Module *m = kernelObjects.Get<Module>(module,error);
|
||||
if (m)
|
||||
Module *module = kernelObjects.Get<Module>(uid, error);
|
||||
if (module)
|
||||
{
|
||||
return m->gp_value;
|
||||
return module->nm.gp_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -486,18 +521,18 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::
|
||||
|
||||
u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ);
|
||||
|
||||
u8 *temp = new u8[(int)info.size];
|
||||
u8 *temp = new u8[(int)info.size + 0x1000000];
|
||||
|
||||
pspFileSystem.ReadFile(handle, temp, (size_t)info.size);
|
||||
|
||||
Module *m = __KernelLoadModule(temp, 0, error_string);
|
||||
Module *module = __KernelLoadModule(temp, 0, error_string);
|
||||
|
||||
if (!m) {
|
||||
if (!module) {
|
||||
ERROR_LOG(LOADER, "Failed to load module %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
mipsr4k.pc = m->entry_addr;
|
||||
mipsr4k.pc = module->nm.entry_addr;
|
||||
|
||||
INFO_LOG(LOADER, "Module entry: %08x", mipsr4k.pc);
|
||||
|
||||
@ -512,7 +547,7 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::
|
||||
option.priority = 0x20;
|
||||
option.stacksize = 0x40000; // crazy? but seems to be the truth
|
||||
|
||||
__KernelStartModule(m, (u32)strlen(filename) + 1, filename, &option);
|
||||
__KernelStartModule(module, (u32)strlen(filename) + 1, filename, &option);
|
||||
|
||||
__KernelStartIdleThreads();
|
||||
return true;
|
||||
@ -578,6 +613,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags)
|
||||
if (PARAM(2))
|
||||
{
|
||||
SceKernelLMOption *lmoption = (SceKernelLMOption *)Memory::GetPointer(PARAM(2));
|
||||
|
||||
}
|
||||
|
||||
Module *module = 0;
|
||||
@ -608,23 +644,66 @@ u32 sceKernelLoadModule(const char *name, u32 flags)
|
||||
return module->GetUID();
|
||||
}
|
||||
|
||||
void sceKernelStartModule()
|
||||
{
|
||||
int id = PARAM(0);
|
||||
int argsize = PARAM(1);
|
||||
u32 argptr = PARAM(2);
|
||||
u32 ptrReturn = PARAM(3);
|
||||
if (PARAM(4)) {
|
||||
SceKernelSMOption *smoption = (SceKernelSMOption*)Memory::GetPointer(PARAM(4));
|
||||
}
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,...)",
|
||||
id,argsize,argptr,ptrReturn);
|
||||
RETURN(0);
|
||||
class AfterModuleEntryCall : public Action {
|
||||
public:
|
||||
AfterModuleEntryCall() {}
|
||||
Module *module_;
|
||||
u32 retValAddr;
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
void AfterModuleEntryCall::run() {
|
||||
Memory::Write_U32(retValAddr, currentMIPS->r[2]);
|
||||
}
|
||||
|
||||
void sceKernelStopModule()
|
||||
void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStopModule");
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)",
|
||||
moduleId,argsize,argAddr,returnValueAddr,optionAddr);
|
||||
|
||||
// Dunno what these three defaults should be...
|
||||
u32 priority = 0x20;
|
||||
u32 stacksize = 0x40000;
|
||||
u32 attr = 0;
|
||||
int stackPartition = 0;
|
||||
if (optionAddr) {
|
||||
SceKernelSMOption smoption;
|
||||
Memory::ReadStruct(optionAddr, &smoption);;
|
||||
priority = smoption.priority;
|
||||
attr = smoption.attribute;
|
||||
stacksize = smoption.stacksize;
|
||||
stackPartition = smoption.mpidstack;
|
||||
}
|
||||
u32 error;
|
||||
Module *module = kernelObjects.Get<Module>(moduleId, error);
|
||||
if (!module) {
|
||||
// TODO: Try not to lie so much.
|
||||
/*
|
||||
RETURN(error);
|
||||
return;
|
||||
*/
|
||||
} else {
|
||||
u32 entryAddr = module->nm.entry_addr;
|
||||
if (entryAddr == -1) {
|
||||
entryAddr = module->nm.module_start_func;
|
||||
// attr = module->nm
|
||||
}
|
||||
}
|
||||
|
||||
//SceUID threadId;
|
||||
//__KernelCreateThread(threadId, moduleId, module->nm.name, module->nm.entry_addr, priority, stacksize, attr);
|
||||
|
||||
// Apparently, we need to call the entry point directly and insert the return value afterwards. This calls
|
||||
// for a MipsCall and an Action. TODO
|
||||
RETURN(moduleId); // TODO: Delete
|
||||
}
|
||||
|
||||
void sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelStopModule(%i, %i, %08x, %08x, %08x)",
|
||||
moduleId, argSize, argAddr, returnValueAddr, optionAddr);
|
||||
|
||||
// We should call the "stop" entry point and return the value in returnValueAddr. See StartModule.
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
@ -644,19 +723,30 @@ void sceKernelUnloadModule()
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelGetModuleIdByAddress()
|
||||
u32 sceKernelGetModuleIdByAddress(u32 moduleAddr)
|
||||
{
|
||||
ERROR_LOG(HLE,"HACKIMPL sceKernelGetModuleIdByAddress(%08x)", PARAM(0));
|
||||
if ((PARAM(0) & 0xFFFF0000) == 0x08800000)
|
||||
RETURN(mainModuleID);
|
||||
|
||||
if ((moduleAddr & 0xFFFF0000) == 0x08800000)
|
||||
{
|
||||
return mainModuleID;
|
||||
}
|
||||
else
|
||||
RETURN(0);
|
||||
{
|
||||
Module* foundMod= kernelObjects.GetByModuleByEntryAddr<Module>(moduleAddr);
|
||||
|
||||
if(foundMod)
|
||||
{
|
||||
return foundMod->GetUID();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceKernelGetModuleId()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelGetModuleId");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE,"sceKernelGetModuleId()");
|
||||
RETURN(__KernelGetCurThreadModuleId());
|
||||
}
|
||||
|
||||
void sceKernelFindModuleByName()
|
||||
@ -665,23 +755,34 @@ void sceKernelFindModuleByName()
|
||||
RETURN(1);
|
||||
}
|
||||
|
||||
u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) {
|
||||
ERROR_LOG(HLE,"UNIMPL %008x=sceKernelLoadModuleById(%08x, %08x)",id,id,lmoptionPtr);
|
||||
// Apparenty, ID is a sceIo File UID. So this shouldn't be too hard when needed.
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 sceKernelLoadModuleDNAS(const char *name, u32 flags)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL 0=sceKernelLoadModuleDNAS()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HLEFunction ModuleMgrForUser[] =
|
||||
{
|
||||
{0x977DE386,&WrapU_CU<sceKernelLoadModule>,"sceKernelLoadModule"},
|
||||
{0xb7f46618,0,"sceKernelLoadModuleByID"},
|
||||
{0x50F0C1EC,&sceKernelStartModule,"sceKernelStartModule"},
|
||||
{0xb7f46618,&WrapU_UUU<sceKernelLoadModuleByID>,"sceKernelLoadModuleByID"},
|
||||
{0x50F0C1EC,&WrapV_UUUUU<sceKernelStartModule>,"sceKernelStartModule"},
|
||||
{0xD675EBB8,&sceKernelExitGame,"sceKernelSelfStopUnloadModule"}, //HACK
|
||||
{0xd1ff982a,&sceKernelStopModule,"sceKernelStopModule"},
|
||||
{0xd1ff982a,&WrapV_UUUUU<sceKernelStopModule>,"sceKernelStopModule"},
|
||||
{0x2e0911aa,&sceKernelUnloadModule,"sceKernelUnloadModule"},
|
||||
{0x710F61B5,0,"sceKernelLoadModuleMs"},
|
||||
{0xF9275D98,0,"sceKernelLoadModuleBufferUsbWlan"}, ///???
|
||||
{0xCC1D3699,0,"sceKernelStopUnloadSelfModule"},
|
||||
{0x748CBED9,0,"sceKernelQueryModuleInfo"},
|
||||
{0xd8b73127,&sceKernelGetModuleIdByAddress, "sceKernelGetModuleIdByAddress"},
|
||||
{0xd8b73127,&WrapU_U<sceKernelGetModuleIdByAddress>, "sceKernelGetModuleIdByAddress"},
|
||||
{0xf0a26395,&sceKernelGetModuleId, "sceKernelGetModuleId"},
|
||||
{0x8f2df740,0,"sceKernel_ModuleMgr_8f2df740"},
|
||||
{0x8f2df740,0,"sceKernelStopUnloadSelfModuleWithStatus"},
|
||||
{0xfef27dc1,&WrapU_CU<sceKernelLoadModuleDNAS> , "sceKernelLoadModuleDNAS"},
|
||||
};
|
||||
|
||||
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
// UNFINISHED
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../../Core/CoreTiming.h"
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelMutex.h"
|
||||
#include "sceKernelThread.h"
|
||||
@ -26,16 +27,29 @@
|
||||
#define PSP_MUTEX_ATTR_FIFO 0
|
||||
#define PSP_MUTEX_ATTR_PRIORITY 0x100
|
||||
#define PSP_MUTEX_ATTR_ALLOW_RECURSIVE 0x200
|
||||
#define PSP_MUTEX_ATTR_KNOWN (PSP_MUTEX_ATTR_PRIORITY | PSP_MUTEX_ATTR_ALLOW_RECURSIVE)
|
||||
|
||||
// Not sure about the names of these
|
||||
#define PSP_MUTEX_ERROR_NOT_LOCKED 0x800201C7
|
||||
#define PSP_MUTEX_ERROR_NO_SUCH_MUTEX 0x800201C3
|
||||
#define PSP_MUTEX_ERROR_TRYLOCK_FAILED 0x800201C4
|
||||
#define PSP_MUTEX_ERROR_NOT_LOCKED 0x800201C5
|
||||
#define PSP_MUTEX_ERROR_LOCK_OVERFLOW 0x800201C6
|
||||
#define PSP_MUTEX_ERROR_UNLOCK_UNDERFLOW 0x800201C7
|
||||
#define PSP_MUTEX_ERROR_ALREADY_LOCKED 0x800201C8
|
||||
|
||||
#define PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX 0x800201CA
|
||||
// Note: used only for _600.
|
||||
#define PSP_LWMUTEX_ERROR_TRYLOCK_FAILED 0x800201CB
|
||||
#define PSP_LWMUTEX_ERROR_NOT_LOCKED 0x800201CC
|
||||
#define PSP_LWMUTEX_ERROR_LOCK_OVERFLOW 0x800201CD
|
||||
#define PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW 0x800201CE
|
||||
#define PSP_LWMUTEX_ERROR_ALREADY_LOCKED 0x800201CF
|
||||
|
||||
// Guesswork - not exposed anyway
|
||||
struct NativeMutex
|
||||
{
|
||||
SceSize size;
|
||||
char name[32];
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
SceUInt attr;
|
||||
|
||||
int lockLevel;
|
||||
@ -46,139 +60,800 @@ struct Mutex : public KernelObject
|
||||
{
|
||||
const char *GetName() {return nm.name;}
|
||||
const char *GetTypeName() {return "Mutex";}
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } // Not sure?
|
||||
static u32 GetMissingErrorCode() { return PSP_MUTEX_ERROR_NO_SUCH_MUTEX; }
|
||||
int GetIDType() const { return SCE_KERNEL_TMID_Mutex; }
|
||||
NativeMutex nm;
|
||||
std::vector<SceUID> waitingThreads;
|
||||
};
|
||||
|
||||
struct LWMutex : public KernelObject
|
||||
// Guesswork - not exposed anyway
|
||||
struct NativeLwMutex
|
||||
{
|
||||
SceSize size;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
SceUInt attr;
|
||||
SceUInt workareaPtr;
|
||||
};
|
||||
|
||||
struct NativeLwMutexWorkarea
|
||||
{
|
||||
int lockLevel;
|
||||
SceUID lockThread;
|
||||
int attr;
|
||||
int numWaitThreads;
|
||||
SceUID uid;
|
||||
int pad[3];
|
||||
|
||||
void init()
|
||||
{
|
||||
memset(this, 0, sizeof(NativeLwMutexWorkarea));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
lockLevel = 0;
|
||||
lockThread = -1;
|
||||
uid = -1;
|
||||
}
|
||||
};
|
||||
|
||||
struct LwMutex : public KernelObject
|
||||
{
|
||||
const char *GetName() {return nm.name;}
|
||||
const char *GetTypeName() {return "LWMutex";}
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } // Not sure?
|
||||
const char *GetTypeName() {return "LwMutex";}
|
||||
static u32 GetMissingErrorCode() { return PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX; }
|
||||
int GetIDType() const { return SCE_KERNEL_TMID_LwMutex; }
|
||||
NativeMutex nm;
|
||||
NativeLwMutex nm;
|
||||
std::vector<SceUID> waitingThreads;
|
||||
};
|
||||
|
||||
u32 sceKernelCreateMutex(const char *name, u32 attr, u32 options)
|
||||
bool mutexInitComplete = false;
|
||||
int mutexWaitTimer = 0;
|
||||
int lwMutexWaitTimer = 0;
|
||||
// Thread -> Mutex locks for thread end.
|
||||
typedef std::multimap<SceUID, SceUID> MutexMap;
|
||||
MutexMap mutexHeldLocks;
|
||||
|
||||
void __KernelMutexInit()
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelCreateMutex(%s, %08x, %08x)", name, attr, options);
|
||||
mutexWaitTimer = CoreTiming::RegisterEvent("MutexTimeout", &__KernelMutexTimeout);
|
||||
lwMutexWaitTimer = CoreTiming::RegisterEvent("LwMutexTimeout", &__KernelLwMutexTimeout);
|
||||
|
||||
// TODO: Install on first mutex (if it's slow?)
|
||||
__KernelListenThreadEnd(&__KernelMutexThreadEnd);
|
||||
|
||||
mutexInitComplete = true;
|
||||
}
|
||||
|
||||
void __KernelMutexAcquireLock(Mutex *mutex, int count, SceUID thread)
|
||||
{
|
||||
#if _DEBUG
|
||||
std::pair<MutexMap::iterator, MutexMap::iterator> locked = mutexHeldLocks.equal_range(thread);
|
||||
for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter)
|
||||
_dbg_assert_msg_(HLE, (*iter).second != mutex->GetUID(), "Thread %d / mutex %d wasn't removed from mutexHeldLocks properly.", thread, mutex->GetUID());
|
||||
#endif
|
||||
|
||||
mutexHeldLocks.insert(std::make_pair(thread, mutex->GetUID()));
|
||||
|
||||
mutex->nm.lockLevel = count;
|
||||
mutex->nm.lockThread = thread;
|
||||
}
|
||||
|
||||
void __KernelMutexAcquireLock(Mutex *mutex, int count)
|
||||
{
|
||||
__KernelMutexAcquireLock(mutex, count, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
void __KernelMutexEraseLock(Mutex *mutex)
|
||||
{
|
||||
if (mutex->nm.lockThread != -1)
|
||||
{
|
||||
SceUID id = mutex->GetUID();
|
||||
std::pair<MutexMap::iterator, MutexMap::iterator> locked = mutexHeldLocks.equal_range(mutex->nm.lockThread);
|
||||
for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter)
|
||||
{
|
||||
if ((*iter).second == id)
|
||||
{
|
||||
mutexHeldLocks.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex->nm.lockThread = -1;
|
||||
}
|
||||
|
||||
std::vector<SceUID>::iterator __KernelMutexFindPriority(std::vector<SceUID> &waiting)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
|
||||
|
||||
std::vector<SceUID>::iterator iter, end, best = waiting.end();
|
||||
u32 best_prio = 0xFFFFFFFF;
|
||||
for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter)
|
||||
{
|
||||
u32 iter_prio = __KernelGetThreadPrio(*iter);
|
||||
if (iter_prio < best_prio)
|
||||
{
|
||||
best = iter;
|
||||
best_prio = iter_prio;
|
||||
}
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(HLE, best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread.");
|
||||
return best;
|
||||
}
|
||||
|
||||
int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr)
|
||||
{
|
||||
if (!mutexInitComplete)
|
||||
__KernelMutexInit();
|
||||
|
||||
if (!name)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=sceKernelCreateMutex(): invalid name", SCE_KERNEL_ERROR_ERROR);
|
||||
return SCE_KERNEL_ERROR_ERROR;
|
||||
}
|
||||
if (attr >= 0xC00)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=sceKernelCreateMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
|
||||
}
|
||||
|
||||
if (initialCount < 0)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
|
||||
Mutex *mutex = new Mutex();
|
||||
SceUID id = kernelObjects.Create(mutex);
|
||||
|
||||
mutex->nm.size = sizeof(mutex);
|
||||
strncpy(mutex->nm.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||
mutex->nm.attr = attr;
|
||||
mutex->nm.lockLevel = 0;
|
||||
mutex->nm.lockThread = -1;
|
||||
if (initialCount == 0)
|
||||
{
|
||||
mutex->nm.lockLevel = 0;
|
||||
mutex->nm.lockThread = -1;
|
||||
}
|
||||
else
|
||||
__KernelMutexAcquireLock(mutex, initialCount);
|
||||
|
||||
DEBUG_LOG(HLE, "%i=sceKernelCreateMutex(%s, %08x, %d, %08x)", id, name, attr, initialCount, optionsPtr);
|
||||
|
||||
if (optionsPtr != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateMutex(%s) unsupported options parameter: %08x", name, optionsPtr);
|
||||
if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateMutex(%s) unsupported attr parameter: %08x", name, attr);
|
||||
|
||||
strncpy(mutex->nm.name, name, 32);
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 sceKernelDeleteMutex(u32 id)
|
||||
bool __KernelUnlockMutexForThread(Mutex *mutex, SceUID threadID, u32 &error, int result)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
|
||||
// The waitID may be different after a timeout.
|
||||
if (waitID != mutex->GetUID())
|
||||
return false;
|
||||
|
||||
// If result is an error code, we're just letting it go.
|
||||
if (result == 0)
|
||||
{
|
||||
int wVal = (int)__KernelGetWaitValue(threadID, error);
|
||||
__KernelMutexAcquireLock(mutex, wVal, threadID);
|
||||
}
|
||||
|
||||
if (timeoutPtr != 0 && mutexWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID);
|
||||
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
int sceKernelDeleteMutex(SceUID id)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
if (!mutex)
|
||||
return PSP_MUTEX_ERROR_NO_SUCH_MUTEX;
|
||||
kernelObjects.Destroy<Mutex>(id);
|
||||
return 0;
|
||||
}
|
||||
if (mutex)
|
||||
{
|
||||
bool wokeThreads = false;
|
||||
std::vector<SceUID>::iterator iter, end;
|
||||
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
|
||||
wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
|
||||
u32 sceKernelLockMutex(u32 id, u32 count, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
if (!mutex)
|
||||
return PSP_MUTEX_ERROR_NO_SUCH_MUTEX;
|
||||
if (mutex->nm.lockLevel == 0)
|
||||
{
|
||||
mutex->nm.lockLevel += count;
|
||||
mutex->nm.lockThread = __KernelGetCurThread();
|
||||
// Nobody had it locked - no need to block
|
||||
}
|
||||
else if ((mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) && mutex->nm.lockThread == __KernelGetCurThread())
|
||||
{
|
||||
// Recursive mutex, let's just increase the lock count and keep going
|
||||
mutex->nm.lockLevel += count;
|
||||
if (mutex->nm.lockThread != -1)
|
||||
__KernelMutexEraseLock(mutex);
|
||||
mutex->waitingThreads.clear();
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("mutex deleted");
|
||||
|
||||
return kernelObjects.Destroy<Mutex>(id);
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
bool __KernelLockMutex(Mutex *mutex, int count, u32 &error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Yeah, we need to block. Somehow.
|
||||
ERROR_LOG(HLE,"Mutex should block!");
|
||||
if (count <= 0)
|
||||
error = SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
else if (count > 1 && !(mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE))
|
||||
error = SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
// Two positive ints will always overflow to negative.
|
||||
else if (count + mutex->nm.lockLevel < 0)
|
||||
error = PSP_MUTEX_ERROR_LOCK_OVERFLOW;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
if (mutex->nm.lockLevel == 0)
|
||||
{
|
||||
__KernelMutexAcquireLock(mutex, count);
|
||||
// Nobody had it locked - no need to block
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mutex->nm.lockThread == __KernelGetCurThread())
|
||||
{
|
||||
// Recursive mutex, let's just increase the lock count and keep going
|
||||
if (mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE)
|
||||
{
|
||||
mutex->nm.lockLevel += count;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = PSP_MUTEX_ERROR_ALREADY_LOCKED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 sceKernelLockMutexCB(u32 id, u32 count, u32 timeoutPtr)
|
||||
bool __KernelUnlockMutex(Mutex *mutex, u32 &error)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr);
|
||||
return 0;
|
||||
__KernelMutexEraseLock(mutex);
|
||||
|
||||
bool wokeThreads = false;
|
||||
std::vector<SceUID>::iterator iter;
|
||||
while (!wokeThreads && !mutex->waitingThreads.empty())
|
||||
{
|
||||
if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0)
|
||||
iter = __KernelMutexFindPriority(mutex->waitingThreads);
|
||||
else
|
||||
iter = mutex->waitingThreads.begin();
|
||||
|
||||
wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, 0);
|
||||
mutex->waitingThreads.erase(iter);
|
||||
}
|
||||
|
||||
if (!wokeThreads)
|
||||
mutex->nm.lockThread = -1;
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
u32 sceKernelUnlockMutex(u32 id, u32 count)
|
||||
void __KernelMutexTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
DEBUG_LOG(HLE,"UNFINISHED sceKernelUnlockMutex(%i, %i)", id, count);
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
u32 error;
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0)
|
||||
Memory::Write_U32(0, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
|
||||
// We intentionally don't remove from waitingThreads here yet.
|
||||
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
|
||||
// actually running, it will get a DELETE result instead of a TIMEOUT.
|
||||
// So, we need to remember it or we won't be able to mark it DELETE instead later.
|
||||
}
|
||||
|
||||
void __KernelMutexThreadEnd(SceUID threadID)
|
||||
{
|
||||
u32 error;
|
||||
|
||||
// If it was waiting on the mutex, it should finish now.
|
||||
SceUID waitingMutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
|
||||
if (waitingMutexID)
|
||||
{
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(waitingMutexID, error);
|
||||
if (mutex)
|
||||
mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end());
|
||||
}
|
||||
|
||||
// Unlock all mutexes the thread had locked.
|
||||
std::pair<MutexMap::iterator, MutexMap::iterator> locked = mutexHeldLocks.equal_range(threadID);
|
||||
for (MutexMap::iterator iter = locked.first; iter != locked.second; )
|
||||
{
|
||||
// Need to increment early so erase() doesn't invalidate.
|
||||
SceUID mutexID = (*iter++).second;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(mutexID, error);
|
||||
|
||||
if (mutex)
|
||||
{
|
||||
mutex->nm.lockLevel = 0;
|
||||
__KernelUnlockMutex(mutex, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || mutexWaitTimer == 0)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (micro <= 3)
|
||||
micro = 15;
|
||||
else if (micro <= 249)
|
||||
micro = 250;
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
// int sceKernelLockMutex(SceUID id, int count, int *timeout)
|
||||
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
if (!mutex)
|
||||
return PSP_MUTEX_ERROR_NO_SUCH_MUTEX;
|
||||
if (mutex->nm.lockLevel == 0)
|
||||
|
||||
if (__KernelLockMutex(mutex, count, error))
|
||||
return 0;
|
||||
else if (error)
|
||||
return error;
|
||||
else
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
__KernelWaitMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false);
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// int sceKernelLockMutexCB(SceUID id, int count, int *timeout)
|
||||
int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
|
||||
if (__KernelLockMutex(mutex, count, error))
|
||||
{
|
||||
hleCheckCurrentCallbacks();
|
||||
return 0;
|
||||
}
|
||||
else if (error)
|
||||
return error;
|
||||
else
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
__KernelWaitMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true);
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// int sceKernelTryLockMutex(SceUID id, int count)
|
||||
int sceKernelTryLockMutex(SceUID id, int count)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelTryLockMutex(%i, %i)", id, count);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
|
||||
if (__KernelLockMutex(mutex, count, error))
|
||||
return 0;
|
||||
else if (error)
|
||||
return error;
|
||||
else
|
||||
return PSP_MUTEX_ERROR_TRYLOCK_FAILED;
|
||||
}
|
||||
|
||||
// int sceKernelUnlockMutex(SceUID id, int count)
|
||||
int sceKernelUnlockMutex(SceUID id, int count)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelUnlockMutex(%i, %i)", id, count);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
if (count <= 0)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
if ((mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && count > 1)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
if (mutex->nm.lockLevel == 0 || mutex->nm.lockThread != __KernelGetCurThread())
|
||||
return PSP_MUTEX_ERROR_NOT_LOCKED;
|
||||
if (mutex->nm.lockLevel < count)
|
||||
return PSP_MUTEX_ERROR_UNLOCK_UNDERFLOW;
|
||||
|
||||
mutex->nm.lockLevel -= count;
|
||||
// TODO....
|
||||
|
||||
if (mutex->nm.lockLevel == 0)
|
||||
{
|
||||
if (__KernelUnlockMutex(mutex, error))
|
||||
hleReSchedule("mutex unlocked");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct NativeLwMutex
|
||||
int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr)
|
||||
{
|
||||
SceSize size;
|
||||
char name[32];
|
||||
SceUInt attr;
|
||||
SceUID mutexUid;
|
||||
SceUInt opaqueWorkAreaAddr;
|
||||
int numWaitThreads;
|
||||
int locked;
|
||||
int threadid; // thread holding the lock
|
||||
};
|
||||
if (!mutexInitComplete)
|
||||
__KernelMutexInit();
|
||||
|
||||
void sceKernelCreateLwMutex()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelCreateLwMutex()");
|
||||
RETURN(0);
|
||||
if (!name)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=sceKernelCreateLwMutex(): invalid name", SCE_KERNEL_ERROR_ERROR);
|
||||
return SCE_KERNEL_ERROR_ERROR;
|
||||
}
|
||||
if (attr >= 0x400)
|
||||
{
|
||||
WARN_LOG(HLE, "%08x=sceKernelCreateLwMutex(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
|
||||
}
|
||||
|
||||
if (initialCount < 0)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
|
||||
LwMutex *mutex = new LwMutex();
|
||||
SceUID id = kernelObjects.Create(mutex);
|
||||
mutex->nm.size = sizeof(mutex);
|
||||
strncpy(mutex->nm.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||
mutex->nm.attr = attr;
|
||||
mutex->nm.workareaPtr = workareaPtr;
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
workarea.init();
|
||||
workarea.lockLevel = initialCount;
|
||||
if (initialCount == 0)
|
||||
workarea.lockThread = 0;
|
||||
else
|
||||
workarea.lockThread = __KernelGetCurThread();
|
||||
workarea.attr = attr;
|
||||
workarea.uid = id;
|
||||
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
|
||||
DEBUG_LOG(HLE, "sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr);
|
||||
|
||||
if (optionsPtr != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateLwMutex(%s) unsupported options parameter: %08x", name, optionsPtr);
|
||||
if ((attr & ~PSP_MUTEX_ATTR_KNOWN) != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateLwMutex(%s) unsupported attr parameter: %08x", name, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceKernelDeleteLwMutex()
|
||||
bool __KernelUnlockLwMutexForThread(LwMutex *mutex, NativeLwMutexWorkarea &workarea, SceUID threadID, u32 &error, int result)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelDeleteLwMutex()");
|
||||
RETURN(0);
|
||||
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
|
||||
// The waitID may be different after a timeout.
|
||||
if (waitID != mutex->GetUID())
|
||||
return false;
|
||||
|
||||
// If result is an error code, we're just letting it go.
|
||||
if (result == 0)
|
||||
{
|
||||
workarea.lockLevel = (int) __KernelGetWaitValue(threadID, error);
|
||||
workarea.lockThread = threadID;
|
||||
}
|
||||
|
||||
if (timeoutPtr != 0 && lwMutexWaitTimer != 0)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID);
|
||||
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sceKernelTryLockLwMutex()
|
||||
int sceKernelDeleteLwMutex(u32 workareaPtr)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelTryLockLwMutex()");
|
||||
RETURN(0);
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteLwMutex(%08x)", workareaPtr);
|
||||
|
||||
if (!workareaPtr || !Memory::IsValidAddress(workareaPtr))
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
Memory::ReadStruct(workareaPtr, &workarea);
|
||||
|
||||
u32 error;
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (mutex)
|
||||
{
|
||||
bool wokeThreads = false;
|
||||
std::vector<SceUID>::iterator iter, end;
|
||||
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
|
||||
wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
mutex->waitingThreads.clear();
|
||||
|
||||
workarea.clear();
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("lwmutex deleted");
|
||||
|
||||
return kernelObjects.Destroy<LwMutex>(mutex->GetUID());
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
void sceKernelLockLwMutex()
|
||||
bool __KernelLockLwMutex(NativeLwMutexWorkarea &workarea, int count, u32 &error)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelLockLwMutex()");
|
||||
RETURN(0);
|
||||
if (!error)
|
||||
{
|
||||
if (count <= 0)
|
||||
error = SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
else if (count > 1 && !(workarea.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE))
|
||||
error = SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
// Two positive ints will always overflow to negative.
|
||||
else if (count + workarea.lockLevel < 0)
|
||||
error = PSP_LWMUTEX_ERROR_LOCK_OVERFLOW;
|
||||
else if (workarea.uid == -1)
|
||||
error = PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX;
|
||||
}
|
||||
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
if (workarea.lockLevel == 0)
|
||||
{
|
||||
if (workarea.lockThread != 0)
|
||||
{
|
||||
// Validate that it actually exists so we can return an error if not.
|
||||
kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (error)
|
||||
return false;
|
||||
}
|
||||
|
||||
workarea.lockLevel = count;
|
||||
workarea.lockThread = __KernelGetCurThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (workarea.lockThread == __KernelGetCurThread())
|
||||
{
|
||||
// Recursive mutex, let's just increase the lock count and keep going
|
||||
if (workarea.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE)
|
||||
{
|
||||
workarea.lockLevel += count;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = PSP_LWMUTEX_ERROR_ALREADY_LOCKED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void sceKernelLockLwMutexCB()
|
||||
bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL sceKernelLockLwMutexCB()");
|
||||
RETURN(0);
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (error)
|
||||
{
|
||||
workarea.lockThread = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wokeThreads = false;
|
||||
std::vector<SceUID>::iterator iter;
|
||||
while (!wokeThreads && !mutex->waitingThreads.empty())
|
||||
{
|
||||
if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0)
|
||||
iter = __KernelMutexFindPriority(mutex->waitingThreads);
|
||||
else
|
||||
iter = mutex->waitingThreads.begin();
|
||||
|
||||
wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, 0);
|
||||
mutex->waitingThreads.erase(iter);
|
||||
}
|
||||
|
||||
if (!wokeThreads)
|
||||
workarea.lockThread = 0;
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
void sceKernelUnlockLwMutex()
|
||||
void __KernelLwMutexTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL void sceKernelUnlockLwMutex()");
|
||||
RETURN(0);
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
u32 error;
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0)
|
||||
Memory::Write_U32(0, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
|
||||
// We intentionally don't remove from waitingThreads here yet.
|
||||
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
|
||||
// actually running, it will get a DELETE result instead of a TIMEOUT.
|
||||
// So, we need to remember it or we won't be able to mark it DELETE instead later.
|
||||
}
|
||||
|
||||
void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || lwMutexWaitTimer == 0)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (micro <= 3)
|
||||
micro = 15;
|
||||
else if (micro <= 249)
|
||||
micro = 250;
|
||||
|
||||
// This should call __KernelLwMutexTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelTryLockLwMutex(u32 workareaPtr, int count)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelTryLockLwMutex(%08x, %i)", workareaPtr, count);
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
Memory::ReadStruct(workareaPtr, &workarea);
|
||||
|
||||
u32 error = 0;
|
||||
if (__KernelLockLwMutex(workarea, count, error))
|
||||
{
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
return 0;
|
||||
}
|
||||
// Unlike sceKernelTryLockLwMutex_600, this always returns the same error.
|
||||
else if (error)
|
||||
return PSP_MUTEX_ERROR_TRYLOCK_FAILED;
|
||||
else
|
||||
return PSP_MUTEX_ERROR_TRYLOCK_FAILED;
|
||||
}
|
||||
|
||||
int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelTryLockLwMutex_600(%08x, %i)", workareaPtr, count);
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
Memory::ReadStruct(workareaPtr, &workarea);
|
||||
|
||||
u32 error = 0;
|
||||
if (__KernelLockLwMutex(workarea, count, error))
|
||||
{
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
return 0;
|
||||
}
|
||||
else if (error)
|
||||
return error;
|
||||
else
|
||||
return PSP_LWMUTEX_ERROR_TRYLOCK_FAILED;
|
||||
}
|
||||
|
||||
int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelLockLwMutex(%08x, %i, %08x)", workareaPtr, count, timeoutPtr);
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
Memory::ReadStruct(workareaPtr, &workarea);
|
||||
|
||||
u32 error = 0;
|
||||
if (__KernelLockLwMutex(workarea, count, error))
|
||||
{
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
return 0;
|
||||
}
|
||||
else if (error)
|
||||
return error;
|
||||
else
|
||||
{
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (mutex)
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
__KernelWaitLwMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false);
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelLockLwMutexCB(%08x, %i, %08x)", workareaPtr, count, timeoutPtr);
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
Memory::ReadStruct(workareaPtr, &workarea);
|
||||
|
||||
u32 error = 0;
|
||||
if (__KernelLockLwMutex(workarea, count, error))
|
||||
{
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
hleCheckCurrentCallbacks();
|
||||
return 0;
|
||||
}
|
||||
else if (error)
|
||||
return error;
|
||||
else
|
||||
{
|
||||
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
|
||||
if (mutex)
|
||||
{
|
||||
mutex->waitingThreads.push_back(__KernelGetCurThread());
|
||||
__KernelWaitLwMutex(mutex, timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true);
|
||||
|
||||
// Return value will be overwritten by wait.
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelUnlockLwMutex(u32 workareaPtr, int count)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelUnlockLwMutex(%08x, %i)", workareaPtr, count);
|
||||
|
||||
NativeLwMutexWorkarea workarea;
|
||||
Memory::ReadStruct(workareaPtr, &workarea);
|
||||
|
||||
if (workarea.uid == -1)
|
||||
return PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX;
|
||||
else if (count <= 0)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
else if ((workarea.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && count > 1)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
else if (workarea.lockLevel == 0 || workarea.lockThread != __KernelGetCurThread())
|
||||
return PSP_LWMUTEX_ERROR_NOT_LOCKED;
|
||||
else if (workarea.lockLevel < count)
|
||||
return PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW;
|
||||
|
||||
workarea.lockLevel -= count;
|
||||
|
||||
if (workarea.lockLevel == 0)
|
||||
{
|
||||
u32 error;
|
||||
if (__KernelUnlockLwMutex(workarea, error))
|
||||
hleReSchedule("lwmutex unlocked");
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
}
|
||||
else
|
||||
Memory::WriteStruct(workareaPtr, &workarea);
|
||||
|
||||
return 0;
|
||||
}
|
@ -17,16 +17,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// TODO
|
||||
u32 sceKernelCreateMutex(const char *name, u32 attr, u32 options);
|
||||
u32 sceKernelDeleteMutex(u32 id);
|
||||
u32 sceKernelLockMutex(u32 id, u32 count, u32 timeoutPtr);
|
||||
u32 sceKernelLockMutexCB(u32 id, u32 count, u32 timeoutPtr);
|
||||
u32 sceKernelUnlockMutex(u32 id, u32 count);
|
||||
int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr);
|
||||
int sceKernelDeleteMutex(SceUID id);
|
||||
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr);
|
||||
int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr);
|
||||
int sceKernelTryLockMutex(SceUID id, int count);
|
||||
int sceKernelUnlockMutex(SceUID id, int count);
|
||||
|
||||
void sceKernelCreateLwMutex();
|
||||
void sceKernelDeleteLwMutex();
|
||||
void sceKernelTryLockLwMutex();
|
||||
void sceKernelLockLwMutex();
|
||||
void sceKernelLockLwMutexCB();
|
||||
void sceKernelUnlockLwMutex();
|
||||
int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr);
|
||||
int sceKernelDeleteLwMutex(u32 workareaPtr);
|
||||
int sceKernelTryLockLwMutex(u32 workareaPtr, int count);
|
||||
int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count);
|
||||
int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr);
|
||||
int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr);
|
||||
int sceKernelUnlockLwMutex(u32 workareaPtr, int count);
|
||||
|
||||
void __KernelMutexTimeout(u64 userdata, int cyclesLate);
|
||||
void __KernelLwMutexTimeout(u64 userdata, int cyclesLate);
|
||||
void __KernelMutexThreadEnd(SceUID thread);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user