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:
Henrik Rydgard 2012-12-17 18:48:32 +01:00
commit bc214dcf37
266 changed files with 19238 additions and 7499 deletions

3
.gitignore vendored
View File

@ -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
View 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)

View File

@ -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)

View File

@ -22,6 +22,9 @@
#include "Common.h"
#include "MemoryUtil.h"
#ifdef __SYMBIAN32__
#include <signal.h>
#endif
#undef _SP

View File

@ -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})

View File

@ -93,6 +93,10 @@ CPUInfo::CPUInfo() {
Detect();
}
#ifdef _WIN32
#include <windows.h>
#endif
// Detects the various cpu features
void CPUInfo::Detect()
{

View File

@ -25,7 +25,7 @@
#include <stdio.h>
#include <string.h>
#if defined(ANDROID) || defined(BLACKBERRY)
#if defined(ARM)
#define _M_ARM32
#endif

View File

@ -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">

View File

@ -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>

View File

@ -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 ) ; }

View File

@ -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 "."

View File

@ -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;

View File

@ -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 ".."

View File

@ -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);

View File

@ -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_

View File

@ -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) {

View File

@ -19,6 +19,10 @@
#include <stdlib.h>
#include <stdio.h>
#ifndef _MSC_VER
#include <strings.h>
#endif
#include <string>
#include <vector>
#include <iostream>

View File

@ -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();} \
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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

View File

@ -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.

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -33,7 +33,8 @@
#define INFINITE 0xffffffff
#endif
#if !defined(ANDROID) && !defined(BLACKBERRY)
// Assume !ARM = x86
#if !defined(ARM)
#include <xmmintrin.h>
#endif

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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", &currentDirectory, "");
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());

View File

@ -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;

View File

@ -38,7 +38,8 @@ enum CoreState
CORE_RUNNING,
CORE_STEPPING,
CORE_POWERDOWN,
CORE_ERROR
CORE_ERROR,
CORE_NEXTFRAME,
};

View File

@ -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>

View File

@ -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>

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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
View 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
View 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;
};

View 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();
}

View 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;
};

View 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);
}

View 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);
};

View 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;
}
}

View 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();
};

View 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*)&param.GetPspParam()->saveNameList));
INFO_LOG(HLE,"fileName : %s",param.GetPspParam()->fileName);
INFO_LOG(HLE,"dataBuf : %08x",*((unsigned int*)&param.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*)&param.GetPspParam()->icon0FileData.buf));
INFO_LOG(HLE,"icon0 size : %u",param.GetPspParam()->icon0FileData.bufSize);
INFO_LOG(HLE,"icon1 data : %08x",*((unsigned int*)&param.GetPspParam()->icon1FileData.buf));
INFO_LOG(HLE,"icon1 size : %u",param.GetPspParam()->icon1FileData.bufSize);
INFO_LOG(HLE,"pic1 data : %08x",*((unsigned int*)&param.GetPspParam()->pic1FileData.buf));
INFO_LOG(HLE,"pic1 size : %u",param.GetPspParam()->pic1FileData.bufSize);
INFO_LOG(HLE,"snd0 data : %08x",*((unsigned int*)&param.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
View 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;
};

View 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*)&param->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*)&param->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*)&param->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*)&param->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*)&param->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*)&param->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
View 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;
};

View File

@ -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
View 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
View 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;
};

View File

@ -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);

View File

@ -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);
};

View File

@ -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;}
};

View File

@ -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;

View File

@ -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;}
};

View File

@ -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 &currentDirectory, 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;

View File

@ -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(...)

View File

@ -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() {

View File

@ -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
{

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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"},
};

View File

@ -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);
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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();

View File

@ -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()

View File

@ -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);

View File

@ -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
View 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
View File

@ -0,0 +1,3 @@
#pragma once
void Register_sceFont();

View File

@ -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"},
};

View File

@ -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);

View File

@ -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()

View File

@ -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

View File

@ -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"},

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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()

View File

@ -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;
}

View File

@ -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);

View File

@ -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"},

View File

@ -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"},
};

View File

@ -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;
}

View File

@ -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