diff options
| author | John "Lameguy" Wilbert Villamor <lameguy64@gmail.com> | 2022-10-19 17:57:06 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-19 17:57:06 +0800 |
| commit | e08a3d9366f8ca14a76b3dd569dac1fb9f569748 (patch) | |
| tree | 33654513b0b184c27f8035dbc405640fcbeb44ab /libpsn00b | |
| parent | c4a2533d21dfd05cde841ea48c67b05e0e6a853f (diff) | |
| parent | 9b2ffc6078a850b7d354855cca7622090b41f30c (diff) | |
| download | psn00bsdk-e08a3d9366f8ca14a76b3dd569dac1fb9f569748.tar.gz | |
Merge pull request #59 from spicyjpeg/psxmdec
IRQ handler fix, .STR playback example, multiple library builds (v0.21)
Diffstat (limited to 'libpsn00b')
33 files changed, 1064 insertions, 929 deletions
diff --git a/libpsn00b/CMakeLists.txt b/libpsn00b/CMakeLists.txt index a662448..602b3c8 100644 --- a/libpsn00b/CMakeLists.txt +++ b/libpsn00b/CMakeLists.txt @@ -1,7 +1,7 @@ # libpsn00b build script -# (C) 2021 spicyjpeg - MPL licensed +# (C) 2021-2022 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) # ${PROJECT_SOURCE_DIR} is not available until project() is called. set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/sdk.cmake) @@ -13,14 +13,13 @@ project( HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" ) -if(NOT DEFINED PSN00BSDK_LIBGCC) - message(FATAL_ERROR "Failed to obtain information about the GCC toolchain. Check your toolchain settings.") -elseif(PSN00BSDK_LIBGCC STREQUAL "PSN00BSDK_LIBGCC-NOTFOUND") - message(FATAL_ERROR "Failed to find libgcc in the GCC toolchain's files. Check your toolchain settings, or set the path to libgcc using -DPSN00BSDK_LIBGCC.") -endif() +include(${PROJECT_SOURCE_DIR}/cmake/flags.cmake) ## Libraries +set(_types EXECUTABLE_GPREL EXECUTABLE_NOGPREL SHARED_LIBRARY) +set(_suffixes _exe_gprel _exe_nogprel _dll) + foreach(_library IN LISTS PSN00BSDK_LIBRARIES) # libc needs special handling due to the different directory name. if(${_library} STREQUAL "c") @@ -31,37 +30,40 @@ foreach(_library IN LISTS PSN00BSDK_LIBRARIES) file( GLOB_RECURSE _sources - ${_path}/*.s - ${_path}/*.c - ${_path}/*.cpp - ${_path}/*.cxx + ${_path}/*.s ${_path}/*.c ${_path}/*.cpp ) - psn00bsdk_add_library(${_library} STATIC ${_sources}) + # Build a separate version of the library for each supported target type + # and create a virtual target that links the appropriate version of the + # library. + add_library(${_library} INTERFACE) + + foreach(_type _suffix IN ZIP_LISTS _types _suffixes) + set(_name ${_library}${_suffix}) + list(APPEND _libraries ${_name}) + + psn00bsdk_add_library(${_name} STATIC ${_sources}) + set_target_properties(${_name} PROPERTIES PSN00BSDK_TARGET_TYPE ${_type}) + target_link_libraries( + ${_library} INTERFACE + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,${_type}>:${_name}> + ) + endforeach() endforeach() -psn00bsdk_target_incbin(psxgpu PRIVATE _gpu_debug_font psxgpu/dbugfont.tim) - -# Extract libgcc's contents and merge them into libc after building. -# Unfortunately glob expressions won't work on Windows, so we have to manually -# enumerate the contents of libgcc and save the list to a temporary file (as it -# is too long to be passed directly on the command line). This is actually the -# most reliable way I found to do this (I tried $<TARGET_OBJECTS> to no avail). -add_custom_command( - TARGET c POST_BUILD - COMMAND ${CMAKE_AR} t ${PSN00BSDK_LIBGCC} $<ANGLE-R>_libgcc.txt - COMMAND ${CMAKE_AR} x ${PSN00BSDK_LIBGCC} - COMMAND ${CMAKE_AR} q $<TARGET_FILE:c> \@_libgcc.txt - COMMAND ${CMAKE_AR} s $<TARGET_FILE:c> - #COMMAND ${CMAKE_AR} rsuU $<TARGET_FILE:c> *.o - COMMENT "Merging libgcc contents into SDK libc" -) +# Add binary assets to each version of the libraries. +foreach(_suffix IN LISTS _suffixes) + psn00bsdk_target_incbin( + psxgpu${_suffix} PRIVATE _gpu_debug_font + psxgpu/dbugfont.tim + ) +endforeach() ## Installation install( - TARGETS ${PSN00BSDK_LIBRARIES} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b + TARGETS psn00bsdk ${PSN00BSDK_LIBRARIES} ${_libraries} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b/$<LOWER_CASE:$<CONFIG>> EXPORT libpsn00b ) install( @@ -95,9 +97,11 @@ install( ) # Generate an import script, which will be used by the setup script to find the -# libraries. +# libraries. Note that CMake actually generates two separate import scripts +# (one setting configuration-specific options), so this won't create conflicts +# once the debug and release builds are merged into the same installation tree. install( EXPORT libpsn00b - DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b/cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b #EXPORT_LINK_INTERFACE_LIBRARIES ) diff --git a/libpsn00b/cmake/flags.cmake b/libpsn00b/cmake/flags.cmake index 5d9c751..1ca25c2 100644 --- a/libpsn00b/cmake/flags.cmake +++ b/libpsn00b/cmake/flags.cmake @@ -1,151 +1,90 @@ -# libpsn00b interface targets -# (C) 2021 spicyjpeg - MPL licensed +# PSn00bSDK interface targets +# (C) 2021-2022 spicyjpeg - MPL licensed # This script creates several "virtual" targets (psn00bsdk_*) that set include -# directories and compiler flags when a target is linked against them. The -# following targets are currently defined: -# - psn00bsdk_common -# - psn00bsdk_static_exe -# - psn00bsdk_dynamic_exe -# - psn00bsdk_static_lib -# - psn00bsdk_object_lib (same as psn00bsdk_static_lib) -# - psn00bsdk_shared_lib -# - psn00bsdk_module_lib (same as psn00bsdk_shared_lib) -# -# NOTE: building a static library and linking it as part of a DLL is currently -# *not* supported. +# directories and compiler flags when a target is linked against them. It is +# only used when building libpsn00b, as CMake automatically saves these targets +# into the export script once libpsn00b is installed. -if(NOT TARGET psn00bsdk_common) # Include guard +add_library (psn00bsdk INTERFACE) +link_libraries(psn00bsdk) -add_library(psn00bsdk_common INTERFACE) - -foreach( - _target IN ITEMS - static_exe dynamic_exe static_lib object_lib shared_lib module_lib -) - add_library (psn00bsdk_${_target} INTERFACE) - target_link_libraries(psn00bsdk_${_target} INTERFACE psn00bsdk_common) -endforeach() - -# Options common to all target types: -# - Define PLAYSTATION=1 -# - Optimize for MIPS R3000 -# - Inject zero checks into division operations (will throw breaks) -# - All standard libraries (including libgcc) disabled -# - Put all symbols into separate sections when building -# - C++ features that require runtime support disabled -# - Unused section stripping enabled target_compile_options( - psn00bsdk_common INTERFACE - # CPU options - -msoft-float - -march=r3000 - -mtune=r3000 - -mabi=32 - -mno-mt - -mno-llsc - -mdivide-breaks + psn00bsdk INTERFACE + # Options common to all target types + -g + -Wa,--strip-local-absolute -O2 - # Standard library options -ffreestanding -fno-builtin -nostdlib - # Other options - -g -fdata-sections -ffunction-sections -fsigned-char -fno-strict-overflow -fdiagnostics-color=always + -msoft-float + -march=r3000 + -mtune=r3000 + -mabi=32 + -mno-mt + -mno-llsc + -mdivide-breaks $<$<COMPILE_LANGUAGE:CXX>: - # C++ options + # Options common to all target types (C++) -fno-exceptions -fno-rtti -fno-unwind-tables -fno-threadsafe-statics -fno-use-cxa-atexit > -) -target_link_options( - psn00bsdk_common INTERFACE - -nostdlib - -Wl,-gc-sections -) -target_compile_definitions( - psn00bsdk_common INTERFACE - PLAYSTATION=1 - $<$<CONFIG:DEBUG>:DEBUG=1> -) - -# Options for executables without support for dynamic linking: -# - Position-independent code disabled -# - GP-relative addressing enabled only for local symbols -# - ABI-compatible calls disabled (incompatible with GP-relative addr) -target_compile_options( - psn00bsdk_static_exe INTERFACE + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,EXECUTABLE_GPREL>: + # Options for executables with $gp-relative addressing -G8 -fno-pic -mno-abicalls -mgpopt -mno-extern-sdata -) -target_link_options( - psn00bsdk_static_exe INTERFACE - -G8 - -static -) - -# Options for executables with support for dynamic linking: -# - Position-independent code disabled -# - GP-relative addressing disabled -# - ABI-compatible calls disabled (must be performed manually) -target_compile_options( - psn00bsdk_dynamic_exe INTERFACE - -G0 - -fno-pic - -mno-abicalls - -mno-gpopt -) -target_link_options( - psn00bsdk_dynamic_exe INTERFACE - -G0 - -static -) - -# Options for static libraries: -# - Position-independent code disabled -# - GP-relative addressing disabled -# - ABI-compatible calls disabled -# - Local stripping enabled -target_compile_options( - psn00bsdk_static_lib INTERFACE + > + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,EXECUTABLE_NOGPREL>: + # Options for executables without $gp-relative addressing -G0 -fno-pic -mno-abicalls -mno-gpopt - -Wa,--strip-local-absolute -) - -target_link_libraries(psn00bsdk_object_lib INTERFACE psn00bsdk_static_lib) - -# Options for dynamically-loaded libraries: -# - Position-independent code enabled -# - GP-relative addressing disabled (incompatible with ABI calls) -# - ABI-compatible calls enabled -target_compile_options( - psn00bsdk_shared_lib INTERFACE + > + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,SHARED_LIBRARY>: + # Options for DLLs -G0 -fPIC -mabicalls -mno-gpopt -mshared + > ) target_link_options( - psn00bsdk_shared_lib INTERFACE + psn00bsdk INTERFACE + # Options common to all target types + -nostdlib + -Wl,-gc-sections + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,EXECUTABLE_GPREL>: + # Options for executables with $gp-relative addressing + -G8 + -static + > + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,EXECUTABLE_NOGPREL>: + # Options for executables without $gp-relative addressing + -G0 + -static + > + $<$<STREQUAL:$<UPPER_CASE:$<TARGET_PROPERTY:PSN00BSDK_TARGET_TYPE>>,SHARED_LIBRARY>: + # Options for DLLs -G0 -shared + > +) +target_compile_definitions( + psn00bsdk INTERFACE + PSN00BSDK=1 + $<$<CONFIG:Release>:NDEBUG=1> ) - -target_link_libraries(psn00bsdk_module_lib INTERFACE psn00bsdk_shared_lib) - -endif() diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake index d293127..e78355f 100644 --- a/libpsn00b/cmake/internal_setup.cmake +++ b/libpsn00b/cmake/internal_setup.cmake @@ -1,12 +1,29 @@ # PSn00bSDK internal setup script for CMake -# (C) 2021 spicyjpeg - MPL licensed +# (C) 2021-2022 spicyjpeg - MPL licensed # This script is included automatically when using the toolchain file and # defines helper functions. -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) include(GNUInstallDirs) +## CMake configuration + +# Setting these variables and properties would technically be the toolchain +# script's responsibility, however they are overridden by project() so their +# setting is deferred to this script. +set(CMAKE_EXECUTABLE_SUFFIX ".elf") +set(CMAKE_STATIC_LIBRARY_PREFIX "lib") +set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") +set(CMAKE_SHARED_LIBRARY_PREFIX "") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") +set(CMAKE_SHARED_MODULE_PREFIX "") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") + +set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS ON) + +## PSn00bSDK initialization + # Fetch SDK version information from build.json. if(NOT DEFINED PSN00BSDK_VERSION) file(READ ${CMAKE_CURRENT_LIST_DIR}/../build.json _json) @@ -17,13 +34,10 @@ if(NOT DEFINED PSN00BSDK_VERSION) string(JSON PSN00BSDK_GIT_COMMIT GET ${_json} git_commit) endif() -## Settings (can be overridden by projects) - -set(PSN00BSDK_EXECUTABLE_SUFFIX ".exe") -set(PSN00BSDK_SHARED_LIBRARY_SUFFIX ".dll") -set(PSN00BSDK_SYMBOL_MAP_SUFFIX ".map") - -## SDK libraries +include(${CMAKE_CURRENT_LIST_DIR}/../libpsn00b.cmake OPTIONAL) +if(TARGET psn00bsdk) + link_libraries(psn00bsdk) +endif() # DON'T CHANGE THE ORDER or you'll break the libraries' internal dependencies. set( @@ -40,33 +54,33 @@ set( c ) -include(${CMAKE_CURRENT_LIST_DIR}/libpsn00b.cmake OPTIONAL) -include(${CMAKE_CURRENT_LIST_DIR}/flags.cmake) +## Settings (can be overridden by projects) -# Use the toolchain path to find libgcc (used to build libpsn00b). Of course -# different installers, packages and distros have different opinions when it -# comes to deciding where to install toolchains, so we have to bruteforce -# multiple combinations of paths. -if(CMAKE_C_COMPILER_VERSION) - string(REGEX MATCH "^([0-9]+)\." _dummy ${CMAKE_C_COMPILER_VERSION}) +set(PSN00BSDK_EXECUTABLE_LINK_LIBRARIES ${PSN00BSDK_LIBRARIES}) +set(PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES "") - find_library( - PSN00BSDK_LIBGCC gcc - HINTS - ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - NO_DEFAULT_PATH - DOC "Path to libgcc (bundled with the GCC toolchain)" - ) +set(PSN00BSDK_EXECUTABLE_SUFFIX ".exe") +set(PSN00BSDK_SHARED_LIBRARY_SUFFIX ".dll") +set(PSN00BSDK_SYMBOL_MAP_SUFFIX ".map") + +define_property( + TARGET PROPERTY PSN00BSDK_TARGET_TYPE + BRIEF_DOCS "Type of this target (EXECUTABLE_GPREL, EXECUTABLE_NOGPREL or SHARED_LIBRARY)" + FULL_DOCS "Type of this target (if executable or DLL) or of the executable/DLL this target is going to be linked to (if static library)" +) + +## Include paths + +set(PSN00BSDK_LDSCRIPTS ${CMAKE_CURRENT_LIST_DIR}/../ldscripts) +if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../include) + set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../include) +else() + set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../../../include/libpsn00b) endif() -## Tools +include_directories(AFTER ${PSN00BSDK_INCLUDE}) + +## Tool paths set( PSN00BSDK_TOOLS @@ -80,24 +94,49 @@ find_program(SMXLINK smxlink HINTS ${PSN00BSDK_TOOLS}) find_program(LZPACK lzpack HINTS ${PSN00BSDK_TOOLS}) find_program(MKPSXISO mkpsxiso HINTS ${PSN00BSDK_TOOLS}) -## Helper functions for executables +## libgcc -set(PSN00BSDK_LDSCRIPTS ${CMAKE_CURRENT_LIST_DIR}/../ldscripts) -if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../include) - set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../include) -else() - set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../../../include/libpsn00b) +# Use the toolchain path to find libgcc. Of course different installers, +# packages and distros have different opinions when it comes to deciding where +# to install toolchains, so we have to bruteforce multiple combinations of +# paths. +if(CMAKE_C_COMPILER_VERSION) + string(REGEX MATCH "^([0-9]+)\." _dummy ${CMAKE_C_COMPILER_VERSION}) + + find_library( + PSN00BSDK_LIBGCC gcc #REQUIRED + HINTS + ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + NO_DEFAULT_PATH + DOC "Path to libgcc (bundled with the GCC toolchain)" + ) + if(PSN00BSDK_LIBGCC STREQUAL "PSN00BSDK_LIBGCC-NOTFOUND") + message(FATAL_ERROR "Failed to find libgcc in the GCC toolchain's files. Check your toolchain settings, or set the path to libgcc using -DPSN00BSDK_LIBGCC.") + endif() + + add_library (gcc STATIC IMPORTED) + set_target_properties(gcc PROPERTIES IMPORTED_LOCATION ${PSN00BSDK_LIBGCC}) + link_libraries (gcc) endif() -# psn00bsdk_add_executable( -# <target name> <STATIC|DYNAMIC> -# [EXCLUDE_FROM_ALL] -# <sources> ... -# ) +## Target helpers + function(psn00bsdk_add_executable name type) - string(TOLOWER ${type} _type) - if(NOT ${_type} MATCHES "^(static|dynamic)$") - message(FATAL_ERROR "Invalid executable type: ${type} (must be STATIC or DYNAMIC)") + string(TOUPPER ${type} _type) + + if(_type MATCHES "^(STATIC|GPREL)$") + set(_type EXECUTABLE_GPREL) + elseif(_type MATCHES "^(DYNAMIC|NOGPREL)$") + set(_type EXECUTABLE_NOGPREL) + else() + message(FATAL_ERROR "Invalid executable type: ${type} (must be STATIC, GPREL, DYNAMIC or NOGPREL)") endif() # Throw an error if elf2x was not found (which should never happen if the @@ -107,111 +146,79 @@ function(psn00bsdk_add_executable name type) endif() add_executable (${name} ${ARGN}) - target_link_libraries(${name} psn00bsdk_${_type}_exe ${PSN00BSDK_LIBRARIES}) - set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".elf") - target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/exe.ld) - - target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + set_target_properties(${name} PROPERTIES PSN00BSDK_TARGET_TYPE ${_type}) + target_link_libraries(${name} PRIVATE ${PSN00BSDK_EXECUTABLE_LINK_LIBRARIES}) + target_link_options (${name} PRIVATE -T$<SHELL_PATH:${PSN00BSDK_LDSCRIPTS}/exe.ld>) # Add post-build steps to generate the .exe and symbol map once the # executable is built. + # FIXME: CMake does not (yet) allow target-dependent generator expressions + # to specify the byproducts, so we have to make sure the generated files + # have no prefix/suffix and are in the current build directory. + #set(_repl PATH:REPLACE_EXTENSION,LAST_ONLY,$<TARGET_FILE:${name}>) add_custom_command( - TARGET ${name} POST_BUILD - COMMAND ${ELF2X} -q ${name}.elf ${name}${PSN00BSDK_EXECUTABLE_SUFFIX} - COMMAND ${TOOLCHAIN_NM} -f posix -l -n ${name}.elf $<ANGLE-R>${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} - BYPRODUCTS ${name}${PSN00BSDK_EXECUTABLE_SUFFIX} ${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} + TARGET ${name} POST_BUILD + COMMAND + ${ELF2X} -q + $<SHELL_PATH:$<TARGET_FILE:${name}>> + #$<SHELL_PATH:$<${_repl},${PSN00BSDK_EXECUTABLE_SUFFIX}>> + $<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_EXECUTABLE_SUFFIX}> + COMMAND + ${TOOLCHAIN_NM} -f posix -l -n + $<SHELL_PATH:$<TARGET_FILE:${name}>> + #$<ANGLE-R>$<SHELL_PATH:$<${_repl},${PSN00BSDK_SYMBOL_MAP_SUFFIX}>> + $<ANGLE-R>$<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX}> + BYPRODUCTS + #$<${_repl},${PSN00BSDK_EXECUTABLE_SUFFIX}> + #$<${_repl},${PSN00BSDK_SYMBOL_MAP_SUFFIX}> + ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_EXECUTABLE_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} ) endfunction() -# psn00bsdk_add_library( -# <target name> <STATIC|SHARED|MODULE> -# [EXCLUDE_FROM_ALL] -# <sources> ... -# ) -# Note that SHARED and MODULE have the same meaning (both will create a DLL). -# SDK libraries are NOT statically linked in by default; if you need to link -# something, use target_link_libraries() manually. function(psn00bsdk_add_library name type) - string(TOUPPER ${type} _type_upper) - string(TOLOWER ${type} _type) - if(NOT ${_type} MATCHES "^(static|object|shared|module)$") - message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") - endif() + string(TOUPPER ${type} _type) - add_library (${name} ${_type_upper} ${ARGN}) - target_link_libraries(${name} psn00bsdk_${_type}_lib) - - target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) - - if(${_type} MATCHES "^(shared|module)$") - set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".so") - target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/dll.ld) + if(_type MATCHES "^(STATIC|OBJECT)$") + add_library (${name} ${_type} ${ARGN}) + #target_link_libraries(${name} PRIVATE psn00bsdk) + elseif(_type MATCHES "^(SHARED|MODULE)$") + add_library (${name} ${_type} ${ARGN}) + set_target_properties(${name} PROPERTIES PSN00BSDK_TARGET_TYPE SHARED_LIBRARY) + target_link_libraries(${name} PRIVATE ${PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES}) + target_link_options (${name} PRIVATE -T$<SHELL_PATH:${PSN00BSDK_LDSCRIPTS}/dll.ld>) # Add a post-build step to dump the DLL's raw contents into a new file # separate from the built ELF. + #set(_repl PATH:REPLACE_EXTENSION,LAST_ONLY,$<TARGET_FILE:${name}>) add_custom_command( - TARGET ${name} POST_BUILD - COMMAND ${CMAKE_OBJCOPY} -O binary ${name}.so ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} - BYPRODUCTS ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} + TARGET ${name} POST_BUILD + COMMAND + ${CMAKE_OBJCOPY} -O binary + $<SHELL_PATH:$<TARGET_FILE:${name}>> + #$<SHELL_PATH:$<${_repl},${PSN00BSDK_SHARED_LIBRARY_SUFFIX}>> + $<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX}> + #BYPRODUCTS $<${_repl},${PSN00BSDK_SHARED_LIBRARY_SUFFIX}> + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} ) else() - set_target_properties(${name} PROPERTIES PREFIX "lib" SUFFIX ".a") - - # Remove virtual target dependencies to make sure linking against the - # library does not also propagate static library flags. - set_target_properties(${name} PROPERTIES INTERFACE_LINK_LIBRARIES "") - endif() -endfunction() - -# psn00bsdk_add_cd_image( -# <target name> -# <image file name> -# <mkpsxiso config template> -# [DEPENDS <dependencies> ...] -# [additional options passed to add_custom_target()] -# ) -function(psn00bsdk_add_cd_image name image_name config_file) - # Throw an error if mkpsxiso was not found. Performing this check manually - # (instead of just marking mkpsxiso as required) allows simple projects to - # be built even if mkpsxiso is not installed. - if(MKPSXISO STREQUAL "MKPSXISO-NOTFOUND") - message(FATAL_ERROR "Failed to locate mkpsxiso. If mkpsxiso wasn't installed alongside the SDK, check your PATH environment variable.") + message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") endif() - - cmake_path(HASH config_file _hash) - - set(CD_IMAGE_NAME ${image_name}) - set(CD_CONFIG_FILE cd_image_${_hash}.xml) - configure_file(${config_file} ${CD_CONFIG_FILE}) - - add_custom_target( - ${name} ALL - COMMAND ${MKPSXISO} -y ${CD_CONFIG_FILE} - BYPRODUCTS ${image_name}.bin ${image_name}.cue - COMMENT "Building CD image ${image_name}" - ${ARGN} - ) endfunction() -## Helper functions for assets +## Linking helpers -# psn00bsdk_target_incbin_a( -# <existing target name> <PRIVATE|PUBLIC|INTERFACE> -# <data symbol name> -# <size symbol name> -# <path to binary file> -# <linker section name> -# <alignment> -# ) function(psn00bsdk_target_incbin_a name type symbol_name size_name path section align) string(MAKE_C_IDENTIFIER ${symbol_name} _id) string(MAKE_C_IDENTIFIER ${size_name} _size) cmake_path(ABSOLUTE_PATH path OUTPUT_VARIABLE _path) + string(SHA1 _hash "${name} ${_id}") + set(_asm_file ${CMAKE_CURRENT_BINARY_DIR}/incbin_${_hash}.s) + # Generate an assembly source file that includes the binary file and add it # to the target's sources. The file is also added as a depedency to ensure # CMake builds it before the target (if it's not a static file). - set(_asm_file ${PROJECT_BINARY_DIR}/incbin_${name}_${_id}.s) file( CONFIGURE OUTPUT ${_asm_file} @@ -246,11 +253,6 @@ ${_size}: set_source_files_properties(${_asm_file} PROPERTIES OBJECT_DEPENDS ${_path}) endfunction() -# psn00bsdk_target_incbin( -# <existing target name> <PRIVATE|PUBLIC|INTERFACE> -# <symbol name> -# <path to binary file> -# ) function(psn00bsdk_target_incbin name type symbol_name path) string(MAKE_C_IDENTIFIER ${symbol_name} _id) @@ -264,3 +266,28 @@ function(psn00bsdk_target_incbin name type symbol_name path) 4 ) endfunction() + +## CD image and asset helpers + +function(psn00bsdk_add_cd_image name image_name config_file) + # Throw an error if mkpsxiso was not found. Performing this check manually + # (instead of just marking mkpsxiso as required) allows simple projects to + # be built even if mkpsxiso is not installed. + if(MKPSXISO STREQUAL "MKPSXISO-NOTFOUND") + message(FATAL_ERROR "Failed to locate mkpsxiso. If mkpsxiso wasn't installed alongside the SDK, check your PATH environment variable.") + endif() + + cmake_path(HASH config_file _hash) + + set(CD_IMAGE_NAME ${image_name}) + set(CD_CONFIG_FILE cd_image_${_hash}.xml) + configure_file(${config_file} ${CD_CONFIG_FILE}) + + add_custom_target( + ${name} ALL + COMMAND ${MKPSXISO} -y ${CD_CONFIG_FILE} + BYPRODUCTS ${image_name}.bin ${image_name}.cue + COMMENT "Building CD image ${image_name}" + ${ARGN} + ) +endfunction() diff --git a/libpsn00b/cmake/sdk.cmake b/libpsn00b/cmake/sdk.cmake index 8965e79..facee26 100644 --- a/libpsn00b/cmake/sdk.cmake +++ b/libpsn00b/cmake/sdk.cmake @@ -1,7 +1,7 @@ # PSn00bSDK toolchain setup file for CMake -# (C) 2021 spicyjpeg - MPL licensed +# (C) 2021-2022 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) set( PSN00BSDK_TC "" @@ -14,7 +14,7 @@ set( ## CMake configuration -set(CMAKE_SYSTEM_NAME PlayStation) +set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR mipsel) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) @@ -28,6 +28,11 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES PSN00BSDK_TC PSN00BSDK_TARGET PSN00BSDK_VERSION) +# Always generate compile_commands.json alongside build scripts. This allows +# some IDEs and tools (such as clangd) to automatically configure include +# directories and other options. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + ## Toolchain path setup # Attempt to find GCC using a list of common installation locations. @@ -65,10 +70,9 @@ endif() ## Toolchain executables -# ${CMAKE_EXECUTABLE_SUFFIX} seems not to work in toolchain scripts, so we -# can't rely on it to determine the host OS extension for executables. The best -# workaround I found is to extract the extension from the path returned by -# find_program() using a regex. +# As we have overridden ${CMAKE_EXECUTABLE_SUFFIX} we can't rely on it to +# determine the host OS extension for executables. A workaround is to extract +# the extension from the path returned by find_program() using a regex. set(_prefix ${_bin}/${PSN00BSDK_TARGET}) string(REGEX MATCH ".+-gcc(.*)$" _dummy ${_gcc}) @@ -85,7 +89,6 @@ set(TOOLCHAIN_NM ${_prefix}-nm${CMAKE_MATCH_1}) ## SDK setup -# We can't set up the SDK here as the find_*() functions may fail if they are -# called before project(). We can however set a script to be executed right -# after project() is invoked. +# Continue initialization by running internal_setup.cmake after project() is +# invoked. set(CMAKE_PROJECT_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/internal_setup.cmake) diff --git a/libpsn00b/include/assert.h b/libpsn00b/include/assert.h index e27f2ed..32301e2 100644 --- a/libpsn00b/include/assert.h +++ b/libpsn00b/include/assert.h @@ -8,13 +8,13 @@ void _assert_abort(const char *file, int line, const char *expr); -#ifdef DEBUG +#ifdef NDEBUG +#define assert(x) +#else #define assert(expr) { \ if (!(expr)) \ _assert_abort(__FILE__, __LINE__, #expr); \ } -#else -#define assert(x) #endif #endif diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h index 03ee792..0460f20 100644 --- a/libpsn00b/include/psxcd.h +++ b/libpsn00b/include/psxcd.h @@ -55,8 +55,10 @@ #define CdlModeAP 0x02 #define CdlModeRept 0x04 #define CdlModeSF 0x08 -#define CdlModeSize0 0x10 -#define CdlModeSize1 0x20 +//#define CdlModeSize0 0x10 +//#define CdlModeSize1 0x20 +#define CdlModeIgnore 0x10 +#define CdlModeSize 0x20 #define CdlModeRT 0x40 #define CdlModeSpeed 0x80 @@ -143,8 +145,10 @@ int CdControlF(uint8_t com, const void *param); int CdSync(int mode, uint8_t *result); uint32_t CdSyncCallback(CdlCB func); -long CdReadyCallback(CdlCB func); +int CdReadyCallback(CdlCB func); int CdGetSector(void *madr, int size); +int CdGetSector2(void *madr, int size); +int CdDataSync(int mode); CdlFILE* CdSearchFile(CdlFILE *loc, const char *filename); @@ -164,7 +168,7 @@ void CdCloseDir(CdlDIR* dir); int CdGetVolumeLabel(char* label); -long* CdAutoPauseCallback(void(*func)()); +int* CdAutoPauseCallback(void(*func)()); int CdIsoError(); int CdLoadSession(int session); diff --git a/libpsn00b/include/psxetc.h b/libpsn00b/include/psxetc.h index 24485d9..fcfec06 100644 --- a/libpsn00b/include/psxetc.h +++ b/libpsn00b/include/psxetc.h @@ -6,12 +6,27 @@ #ifndef __PSXETC_H #define __PSXETC_H +/* Macros */ + +// This macro is used internally by PSn00bSDK to log debug messages to a buffer +// which is then printed to stdout when calling VSync(). +#ifdef NDEBUG +#define _sdk_log(...) +#define _sdk_dump_log() +#else +#define _sdk_log(...) _sdk_log_inner(__VA_ARGS__) +#define _sdk_dump_log() _sdk_dump_log_inner() +#endif + /* Public API */ #ifdef __cplusplus extern "C" { #endif +void _sdk_log_inner(const char *fmt, ...); +void _sdk_dump_log_inner(void); + void *InterruptCallback(int irq, void (*func)(void)); void *GetInterruptCallback(int irq); void *DMACallback(int dma, void (*func)(void)); diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h index 0e7ec00..f2568b0 100644 --- a/libpsn00b/include/psxgpu.h +++ b/libpsn00b/include/psxgpu.h @@ -488,20 +488,30 @@ void PutDrawEnvFast(DRAWENV *env); int GetODE(void); int VSync(int mode); -int DrawSync(int mode); - void *VSyncHaltFunction(void (*func)(void)); void *VSyncCallback(void (*func)(void)); + +int EnqueueDrawOp( + void (*func)(uint32_t, uint32_t, uint32_t), + uint32_t arg1, + uint32_t arg2, + uint32_t arg3 +); +int DrawSync(int mode); void *DrawSyncCallback(void (*func)(void)); -void LoadImage(const RECT *rect, const uint32_t *data); -void StoreImage(const RECT *rect, uint32_t *data); +int LoadImage(const RECT *rect, const uint32_t *data); +int StoreImage(const RECT *rect, uint32_t *data); +int MoveImage(const RECT *rect, int x, int y); +void LoadImage2(const RECT *rect, const uint32_t *data); +void StoreImage2(const RECT *rect, uint32_t *data); +void MoveImage2(const RECT *rect, int x, int y); void ClearOTagR(uint32_t *ot, size_t length); void ClearOTag(uint32_t *ot, size_t length); -void DrawOTag(const uint32_t *ot); +int DrawOTag(const uint32_t *ot); +int DrawOTagEnv(const uint32_t *ot, DRAWENV *env); void DrawOTag2(const uint32_t *ot); -void DrawOTagEnv(const uint32_t *ot, DRAWENV *env); void DrawPrim(const uint32_t *pri); void AddPrim(uint32_t *ot, const void *pri); diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h index 1888c69..f0753c1 100644 --- a/libpsn00b/include/stdlib.h +++ b/libpsn00b/include/stdlib.h @@ -12,6 +12,16 @@ #define RAND_MAX 0x7fff +/* Structure definitions */ + +typedef struct _HeapUsage { + size_t total; // Total size of heap + stack + size_t heap; // Amount of memory currently reserved for heap + size_t stack; // Amount of memory currently reserved for stack + size_t alloc; // Amount of memory currently allocated + size_t alloc_max; // Maximum amount of memory ever allocated +} HeapUsage; + /* API */ #ifdef __cplusplus @@ -33,11 +43,12 @@ long double strtold(const char *nptr, char **endptr); double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); -void _mem_init(size_t ram_size, size_t stack_max_size); void InitHeap(void *addr, size_t size); -//int SetHeapSize(size_t size); void *sbrk(ptrdiff_t incr); +void TrackHeapUsage(ptrdiff_t alloc_incr); +void GetHeapUsage(HeapUsage *usage); + void *malloc(size_t size); void *calloc(size_t num, size_t size); void *realloc(void *ptr, size_t size); diff --git a/libpsn00b/libc/abort.c b/libpsn00b/libc/abort.c index de4323d..2db5016 100644 --- a/libpsn00b/libc/abort.c +++ b/libpsn00b/libc/abort.c @@ -1,10 +1,10 @@ -#include <stdio.h> +#include <psxetc.h> /* Standard abort */ -void abort() { - printf("abort()\n"); +void abort(void) { + _sdk_log("abort()\n"); for (;;) __asm__ volatile(""); @@ -13,7 +13,7 @@ void abort() { /* Internal function used by assert() macro */ void _assert_abort(const char *file, int line, const char *expr) { - printf("%s:%d: assert(%s)\n", file, line, expr); + _sdk_log("%s:%d: assert(%s)\n", file, line, expr); for (;;) __asm__ volatile(""); @@ -22,7 +22,7 @@ void _assert_abort(const char *file, int line, const char *expr) { /* Pure virtual function call (C++) */ void __cxa_pure_virtual(void) { - printf("__cxa_pure_virtual()\n"); + _sdk_log("__cxa_pure_virtual()\n"); for (;;) __asm__ volatile(""); diff --git a/libpsn00b/libc/malloc.c b/libpsn00b/libc/malloc.c index 9d538cd..e9fd6f4 100644 --- a/libpsn00b/libc/malloc.c +++ b/libpsn00b/libc/malloc.c @@ -9,6 +9,8 @@ * latter being built on top of the former. This makes it possible to override * only InitHeap() and sbrk() while still using the default allocator, or * override malloc()/realloc()/free() while using the default heap manager. + * Custom allocators should call TrackHeapUsage() to let the heap manager know + * how much memory is allocated at a given time. */ #include <stddef.h> @@ -25,11 +27,13 @@ typedef struct _BlockHeader { size_t size; } BlockHeader; -/* Data */ +/* Internal globals */ static void *_heap_start, *_heap_end, *_heap_limit; -static void *_alloc_start = 0; -static BlockHeader *_alloc_head = 0, *_alloc_tail = 0; +static size_t _heap_alloc, _heap_alloc_max; + +static void *_alloc_start; +static BlockHeader *_alloc_head, *_alloc_tail; /* Heap management API */ @@ -37,6 +41,13 @@ __attribute__((weak)) void InitHeap(void *addr, size_t size) { _heap_start = addr; _heap_end = addr; _heap_limit = (void *) ((uintptr_t) addr + size); + + _heap_alloc = 0; + _heap_alloc_max = 0; + + _alloc_start = addr; + _alloc_head = 0; + _alloc_tail = 0; } __attribute__((weak)) void *sbrk(ptrdiff_t incr) { @@ -50,6 +61,22 @@ __attribute__((weak)) void *sbrk(ptrdiff_t incr) { return old_end; } +__attribute__((weak)) void TrackHeapUsage(ptrdiff_t alloc_incr) { + _heap_alloc += alloc_incr; + + if (_heap_alloc > _heap_alloc_max) + _heap_alloc_max = _heap_alloc; +} + +__attribute__((weak)) void GetHeapUsage(HeapUsage *usage) { + usage->total = _heap_limit - _heap_start; + usage->heap = _heap_end - _heap_start; + usage->stack = _heap_limit - _heap_end; + + usage->alloc = _heap_alloc; + usage->alloc_max = _heap_alloc_max; +} + /* Memory allocator */ static BlockHeader *_find_fit(BlockHeader *head, size_t size) { @@ -69,13 +96,16 @@ static BlockHeader *_find_fit(BlockHeader *head, size_t size) { } __attribute__((weak)) void *malloc(size_t size) { + if (!size) + return 0; + size_t _size = _align(size + sizeof(BlockHeader), 8); // Nothing's initialized yet? Let's just initialize the bottom of our heap, // flag it as allocated. if (!_alloc_head) { - if (!_alloc_start) - _alloc_start = sbrk(0); + //if (!_alloc_start) + //_alloc_start = sbrk(0); BlockHeader *new = (BlockHeader *) sbrk(_size); if (!new) @@ -89,6 +119,8 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_head = new; _alloc_tail = new; + + TrackHeapUsage(size); return ptr; } @@ -106,6 +138,8 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_head->prev = new; _alloc_head = new; + + TrackHeapUsage(size); return ptr; } @@ -122,6 +156,8 @@ __attribute__((weak)) void *malloc(size_t size) { (new->next)->prev = new; prev->next = new; + + TrackHeapUsage(size); return ptr; } @@ -138,6 +174,8 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_tail->next = new; _alloc_tail = new; + + TrackHeapUsage(size); return ptr; } @@ -153,13 +191,14 @@ __attribute__((weak)) void *realloc(void *ptr, size_t size) { if (!ptr) return malloc(size); - size_t _size = _align(size + sizeof(BlockHeader), 8); - + size_t _size = _align(size + sizeof(BlockHeader), 8); BlockHeader *prev = (BlockHeader *) ((uintptr_t) ptr - sizeof(BlockHeader)); // New memory block shorter? if (prev->size >= _size) { + TrackHeapUsage(size - prev->size); prev->size = _size; + if (!prev->next) sbrk((ptr - sbrk(0)) + _size); @@ -172,12 +211,14 @@ __attribute__((weak)) void *realloc(void *ptr, size_t size) { if (!new) return 0; + TrackHeapUsage(size - prev->size); prev->size = _size; return ptr; } // Do we have free memory after it? if (((prev->next)->ptr - ptr) > _size) { + TrackHeapUsage(size - prev->size); prev->size = _size; return ptr; } @@ -209,11 +250,13 @@ __attribute__((weak)) void free(void *ptr) { sbrk(-size); } + TrackHeapUsage(-(_alloc_head->size)); return; } // Finding the proper block BlockHeader *cur = _alloc_head; + for (cur = _alloc_head; ptr != cur->ptr; cur = cur->next) { if (!cur->next) return; @@ -221,15 +264,16 @@ __attribute__((weak)) void free(void *ptr) { if (cur->next) { // In the middle, just unlink it - cur->next->prev = cur->prev; + (cur->next)->prev = cur->prev; } else { // At the end, shrink heap - _alloc_tail = cur->prev; - void *top = sbrk(0); size_t size = (top - (cur->prev)->ptr) - (cur->prev)->size; + _alloc_tail = cur->prev; + sbrk(-size); } + TrackHeapUsage(-(cur->size)); (cur->prev)->next = cur->next; } diff --git a/libpsn00b/libc/memset.s b/libpsn00b/libc/memset.s index b3a3af3..5a1589d 100644 --- a/libpsn00b/libc/memset.s +++ b/libpsn00b/libc/memset.s @@ -1,25 +1,117 @@ -# High speed ASM memset implementation by Lameguy64 -# -# Part of PSn00bSDK +# PSn00bSDK optimized memset +# (C) 2022 spicyjpeg - MPL licensed .set noreorder -.section .text - -# Arguments: -# a0 - address to buffer -# a1 - value to set -# a2 - bytes to set +.section .text.memset .global memset -.type memset,@function +.type memset, @function memset: - move $v0, $a0 - blez $a2, .Lexit - addi $a2, -1 - sb $a1, 0($a0) - b memset - addiu $a0, 1 -.Lexit: - jr $ra - nop -
\ No newline at end of file + # If more than 16 bytes have to be written then take the "large" path, + # otherwise use the code below. + addiu $t0, $a2, -16 + bgtz $t0, .Llarge_fill + move $v0, $a0 # return_value = dest + + # Jump to one of the sb opcodes below. This is basically a cut-down Duff's + # device implementation with no looping. + la $t0, .Lsmall_duff + 0x40 # jump_addr = &small_duff[(16 - count) * 4] + sll $t1, $a2, 2 + subu $t0, $t1 + addu $a0, $a2 # dest -= 16 - count + jr $t0 + addiu $a0, -16 + +.Lsmall_duff: + sb $a1, 0x0($a0) + sb $a1, 0x1($a0) + sb $a1, 0x2($a0) + sb $a1, 0x3($a0) + sb $a1, 0x4($a0) + sb $a1, 0x5($a0) + sb $a1, 0x6($a0) + sb $a1, 0x7($a0) + sb $a1, 0x8($a0) + sb $a1, 0x9($a0) + sb $a1, 0xa($a0) + sb $a1, 0xb($a0) + sb $a1, 0xc($a0) + sb $a1, 0xd($a0) + sb $a1, 0xe($a0) + jr $ra + sb $a1, 0xf($a0) + +.Llarge_fill: + # Initialize fast filling by repeating the fill byte 4 times, so it can be + # written 32 bits at a time. + andi $a1, 0xff # ch &= 0xff + sll $t0, $a1, 8 # ch |= (ch << 8) | (ch << 16) | (ch << 24) + or $a1, $t0 + sll $t0, $a1, 16 + or $a1, $t0 + + # Fill the first 1-4 bytes (here the swr instruction does all the magic) + # and update dest and count accordingly. + swr $a1, 0($a0) + andi $t0, $a0, 3 # align = 4 - (dest % 4) + addiu $t0, -4 + addu $a2, $t0 # count -= align + subu $a0, $t0 # dest += align + + la $t1, .Llarge_duff + andi $t2, $a2, 3 # remainder = count % 4 + subu $a2, $t2 # count -= remainder + +.Llarge_fill_loop: + # If 128 bytes or more still have to be written, skip calculating the jump + # offset and execute the whole block of sw opcodes. + addiu $a2, -0x80 # count -= 0x80 + bgez $a2, .Llarge_duff + #nop + + # Jump to one of the sw opcodes below. This is the "full" Duff's device. + subu $t0, $t1, $a2 # jump_addr = &large_duff[0x80 - (count + 0x80)] + jr $t0 + addu $a0, $a2 # dest -= 0x80 - (count + 0x80) + +.Llarge_duff: + sw $a1, 0x00($a0) + sw $a1, 0x04($a0) + sw $a1, 0x08($a0) + sw $a1, 0x0c($a0) + sw $a1, 0x10($a0) + sw $a1, 0x14($a0) + sw $a1, 0x18($a0) + sw $a1, 0x1c($a0) + sw $a1, 0x20($a0) + sw $a1, 0x24($a0) + sw $a1, 0x28($a0) + sw $a1, 0x2c($a0) + sw $a1, 0x30($a0) + sw $a1, 0x34($a0) + sw $a1, 0x38($a0) + sw $a1, 0x3c($a0) + sw $a1, 0x40($a0) + sw $a1, 0x44($a0) + sw $a1, 0x48($a0) + sw $a1, 0x4c($a0) + sw $a1, 0x50($a0) + sw $a1, 0x54($a0) + sw $a1, 0x58($a0) + sw $a1, 0x5c($a0) + sw $a1, 0x60($a0) + sw $a1, 0x64($a0) + sw $a1, 0x68($a0) + sw $a1, 0x6c($a0) + sw $a1, 0x70($a0) + sw $a1, 0x74($a0) + sw $a1, 0x78($a0) + sw $a1, 0x7c($a0) + + bgtz $a2, .Llarge_fill_loop + addiu $a0, 0x80 # dest += 0x80 + + # Fill the remaining 1-4 bytes, using (again) an unaligned store. + addu $a0, $t2 # last_byte = dest + remainder - 1 + jr $ra + swl $a1, -1($a0) diff --git a/libpsn00b/libc/start.c b/libpsn00b/libc/start.c index 87ac951..9ff09c8 100644 --- a/libpsn00b/libc/start.c +++ b/libpsn00b/libc/start.c @@ -21,7 +21,7 @@ const char **__argv; static const char *_argv_buffer[ARGC_MAX]; static char _arg_string_buffer[132]; -static void _parse_kernel_args() { +static void _parse_kernel_args(void) { // Copy the argument string from kernel memory into a private buffer (which // won't be cleared or deallocated) and trim it at the first newline. memset(_arg_string_buffer, 0, 132); @@ -48,7 +48,7 @@ static void _parse_kernel_args() { } } -/* Heap initialization */ +/* Main */ // These are defined by the linker script. Note that these are *NOT* pointers, // they are virtual symbols whose location matches their value. The simplest @@ -58,20 +58,6 @@ extern uint8_t __bss_start[]; extern uint8_t _end[]; //extern uint8_t _gp[]; -// This function should not be called manually in most cases. It might be -// useful though to change the stack size and/or reinitialize the heap on -// systems that have more than 2 MB of RAM (e.g. emulators, devkits, PS1-based -// arcade boards). -void _mem_init(size_t ram_size, size_t stack_max_size) { - void *exe_end = _end + 4; - size_t exe_size = (size_t) exe_end - (size_t) __text_start; - size_t ram_used = (0x10000 + exe_size + stack_max_size) & 0xfffffffc; - - InitHeap(exe_end, ram_size - ram_used); -} - -/* Main */ - extern void (*__CTOR_LIST__[])(void); extern void (*__DTOR_LIST__[])(void); @@ -88,10 +74,9 @@ void _start_inner(int32_t override_argc, const char **override_argv) { for (uint32_t *i = (uint32_t *) __bss_start; i < (uint32_t *) _end; i++) *i = 0; - // Initialize the heap, assuming 2 MB of RAM and reserving 128 KB for the - // stack. Note that _mem_init() can be called again in main() to change - // these values. - _mem_init(0x200000, 0x20000); + // Initialize the heap and place it after the executable, assuming 2 MB of + // RAM. Note that InitHeap() can be called again in main(). + InitHeap((void *) _end + 4, (void *) 0x801ffff8 - (void *) _end); if (override_argv) { __argc = override_argc; diff --git a/libpsn00b/psxapi/drivers.s b/libpsn00b/psxapi/drivers.s index 1cf5050..d991f90 100644 --- a/libpsn00b/psxapi/drivers.s +++ b/libpsn00b/psxapi/drivers.s @@ -90,26 +90,26 @@ ListDev: jr $t2 li $t1, 0x49 -.section .text.InitCard -.global InitCard -.type InitCard, @function -InitCard: +.section .text.InitCARD +.global InitCARD +.type InitCARD, @function +InitCARD: li $t2, 0xb0 jr $t2 li $t1, 0x4a -.section .text.StartCard -.global StartCard -.type StartCard, @function -StartCard: +.section .text.StartCARD +.global StartCARD +.type StartCARD, @function +StartCARD: li $t2, 0xb0 jr $t2 li $t1, 0x4b -.section .text.StopCard -.global StopCard -.type StopCard, @function -StopCard: +.section .text.StopCARD +.global StopCARD +.type StopCARD, @function +StopCARD: li $t2, 0xb0 jr $t2 li $t1, 0x4c diff --git a/libpsn00b/psxapi/stubs.json b/libpsn00b/psxapi/stubs.json index 200cbc7..50ffb55 100644 --- a/libpsn00b/psxapi/stubs.json +++ b/libpsn00b/psxapi/stubs.json @@ -362,19 +362,19 @@ { "type": "b", "id": 74, - "name": "InitCard", + "name": "InitCARD", "file": "drivers.s" }, { "type": "b", "id": 75, - "name": "StartCard", + "name": "StartCARD", "file": "drivers.s" }, { "type": "b", "id": 76, - "name": "StopCard", + "name": "StopCARD", "file": "drivers.s" }, { diff --git a/libpsn00b/psxcd/cdgetsector.s b/libpsn00b/psxcd/cdgetsector.s deleted file mode 100644 index 6a29069..0000000 --- a/libpsn00b/psxcd/cdgetsector.s +++ /dev/null @@ -1,56 +0,0 @@ -.set noreorder - -.include "hwregs_a.inc" - -.section .text - -.global CdGetSector -.type CdGetSector, @function -CdGetSector: - - lui $a2, IOBASE - -#.Lwait_fifo: # Probably redundant as the BIOS CD-ROM -# lbu $v0, CD_REG0($a2) # routines do not not wait for this -# nop -# andi $v0, 0x40 -# beqz $v0, .Lwait_fifo -# nop - - lui $v0, 0x1 -# srl $a1, 2 # (the official implementation expects $a1/size - # to be in 32-bit words rather than bytes) - or $v0, $a1 - sw $a0, DMA3_MADR($a2) # Set DMA base address and transfer length - sw $v0, DMA3_BCR($a2) - - lui $v0, 0x1100 # Start DMA transfer - sw $v0, DMA3_CHCR($a2) - nop - nop - -.Ldma_wait: # Ensure DMA transfer has completed - lw $v0, DMA3_CHCR($a2) - nop - srl $v0, 24 - andi $v0, 0x1 - - bnez $v0, .Ldma_wait - nop - -# Not stable -# sb $0 , CD_REG0($a2) -#.Lflush_fifo: # Read out any remaining bytes in the buffer -# lbu $v1, CD_REG0($a2) -# li $v0, 0x40 -# and $v1, $v0 -# beqz $v1, .Lend_flush -# nop -# lbu $v0, CD_REG2($a2) -# b .Lflush_fifo -# nop -#.Lend_flush: - - jr $ra - li $v0, 1 - diff --git a/libpsn00b/psxcd/getsector.c b/libpsn00b/psxcd/getsector.c new file mode 100644 index 0000000..31d0ac7 --- /dev/null +++ b/libpsn00b/psxcd/getsector.c @@ -0,0 +1,51 @@ +/* + * PSn00bSDK CD drive library (sector DMA API) + * (C) 2022 spicyjpeg - MPL licensed + */ + +#include <stdint.h> +#include <psxetc.h> +#include <psxcd.h> +#include <hwregs_c.h> + +#define DATA_SYNC_TIMEOUT 0x100000 + +/* DMA transfer functions */ + +int CdGetSector(void *madr, int size) { + //while (!(CD_STAT & (1 << 6))) + //__asm__ volatile(""); + + DMA_MADR(3) = (uint32_t) madr; + DMA_BCR(3) = size | (1 << 16); + DMA_CHCR(3) = 0x11000000; + + while (DMA_CHCR(3) & (1 << 24)) + __asm__ volatile(""); + + return 1; +} + +int CdGetSector2(void *madr, int size) { + //while (!(CD_STAT & (1 << 6))) + //__asm__ volatile(""); + + DMA_MADR(3) = (uint32_t) madr; + DMA_BCR(3) = size | (1 << 16); + DMA_CHCR(3) = 0x11400100; // Transfer 1 word every 16 CPU cycles + + return 1; +} + +int CdDataSync(int mode) { + if (mode) + return (DMA_CHCR(3) >> 24) & 1; + + for (int i = DATA_SYNC_TIMEOUT; i; i--) { + if (!(DMA_CHCR(3) & (1 << 24))) + return 0; + } + + _sdk_log("psxcd: CdDataSync() timeout\n"); + return -1; +} diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index 582b8d9..0425c0d 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -1,15 +1,12 @@ #include <stdint.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> #include <psxgpu.h> -#include <psxsio.h> +#include <psxapi.h> +#include <psxetc.h> #include "psxcd.h" #include "isofs.h" -// Uncommend to enable debug output -//#define DEBUG - #define DEFAULT_PATH_SEP '\\' #define IS_PATH_SEP(ch) (((ch) == '/') || ((ch) == '\\')) @@ -46,9 +43,8 @@ static int _CdReadIsoDescriptor(int session_offs) CdControl(CdlNop, 0, 0); if( (CdStatus()&0x10) ) { -#ifdef DEBUG - printf("psxcd: Lid is still open.\n"); -#endif + _sdk_log("psxcd: Lid is still open.\n"); + _cd_iso_error = CdlIsoLidOpen; return -1; } @@ -61,61 +57,47 @@ static int _CdReadIsoDescriptor(int session_offs) { return 0; } - -#ifdef DEBUG - printf("psxcd: Parsing ISO file system.\n"); -#endif + + _sdk_log("psxcd: Parsing ISO file system.\n"); // Seek to volume descriptor CdIntToPos(16+session_offs, &loc); if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { -#ifdef DEBUG - printf("psxcd: Could not set seek destination.\n"); -#endif + _sdk_log("psxcd: Could not set seek destination.\n"); + _cd_iso_error = CdlIsoSeekError; return -1; } -#ifdef DEBUG - printf("psxcd: Set seek target.\n"); -#endif - -#ifdef DEBUG - printf("psxcd: Read sectors.\n"); -#endif + _sdk_log("psxcd: Read sectors.\n"); + // Read volume descriptor CdRead(1, (uint32_t*)_cd_iso_descriptor_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading ISO volume descriptor.\n"); -#endif + _sdk_log("psxcd: Error reading ISO volume descriptor.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } - -#ifdef DEBUG - printf("psxcd: Read complete.\n"); -#endif - + + _sdk_log("psxcd: Read complete.\n"); + // Verify if volume descriptor is present descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; if( strncmp("CD001", descriptor->header.id, 5) ) { -#ifdef DEBUG - printf("psxcd: Disc does not contain a ISO9660 file system.\n"); -#endif + _sdk_log("psxcd: Disc does not contain a ISO9660 file system.\n"); + _cd_iso_error = CdlIsoInvalidFs; return -1; } - -#ifdef DEBUG - printf("psxcd_dbg: Path table LBA = %d\n", descriptor->pathTable1Offs); - printf("psxcd_dbg: Path table len = %d\n", descriptor->pathTableSize.lsb); -#endif - + + _sdk_log("psxcd: Path table LBA = %d\n", descriptor->pathTable1Offs); + _sdk_log("psxcd: Path table len = %d\n", descriptor->pathTableSize.lsb); + // Allocate path table buffer i = ((2047+descriptor->pathTableSize.lsb)>>11)<<11; if( _cd_iso_pathtable_buff ) @@ -123,20 +105,17 @@ static int _CdReadIsoDescriptor(int session_offs) free(_cd_iso_pathtable_buff); } _cd_iso_pathtable_buff = (uint8_t*)malloc(i); - -#ifdef DEBUG - printf("psxcd_dbg: Allocated %d bytes for path table.\n", i); -#endif - + + _sdk_log("psxcd: Allocated %d bytes for path table.\n", i); + // Read path table CdIntToPos(descriptor->pathTable1Offs, &loc); CdControl(CdlSetloc, (uint8_t*)&loc, 0); CdRead(i>>11, (uint32_t*)_cd_iso_pathtable_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading ISO path table.\n"); -#endif + _sdk_log("psxcd: Error reading ISO path table.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } @@ -162,14 +141,13 @@ static int _CdReadIsoDirectory(int lba) CdIntToPos(lba, &loc); i = CdPosToInt(&loc); -#ifdef DEBUG - printf("psxcd_dbg: Seek to sector %d\n", i); -#endif + + _sdk_log("psxcd: Seek to sector %d\n", i); + if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { -#ifdef DEBUG - printf("psxcd: Could not set seek destination.\n"); -#endif + _sdk_log("psxcd: Could not set seek destination.\n"); + _cd_iso_error = CdlIsoSeekError; return -1; } @@ -184,28 +162,24 @@ static int _CdReadIsoDirectory(int lba) CdRead(1, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading initial directory record.\n"); -#endif + _sdk_log("psxcd: Error reading initial directory record.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } direntry = (ISO_DIR_ENTRY*)_cd_iso_directory_buff; _cd_iso_directory_len = direntry->entrySize.lsb; - -#ifdef DEBUG - printf("psxcd_dbg: Location of directory record = %d\n", direntry->entryOffs.lsb); - printf("psxcd_dbg: Size of directory record = %d\n", _cd_iso_directory_len); -#endif + + _sdk_log("psxcd: Location of directory record = %d\n", direntry->entryOffs.lsb); + _sdk_log("psxcd: Size of directory record = %d\n", _cd_iso_directory_len); if( _cd_iso_directory_len > 2048 ) { if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { -#ifdef DEBUG - printf("psxcd: Could not set seek destination.\n"); -#endif + _sdk_log("psxcd: Could not set seek destination.\n"); + _cd_iso_error = CdlIsoSeekError; return -1; } @@ -213,16 +187,14 @@ static int _CdReadIsoDirectory(int lba) free(_cd_iso_directory_buff); i = ((2047+_cd_iso_directory_len)>>11)<<11; _cd_iso_directory_buff = (uint8_t*)malloc(i); -#ifdef DEBUG - printf("psxcd_dbg: Allocated %d bytes for directory record.\n", i); -#endif + + _sdk_log("psxcd: Allocated %d bytes for directory record.\n", i); CdRead(i>>11, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading remaining directory record.\n"); -#endif + _sdk_log("psxcd: Error reading remaining directory record.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } @@ -234,7 +206,7 @@ static int _CdReadIsoDirectory(int lba) return 0; } -#ifdef DEBUG +#ifndef NDEBUG static void dump_directory(void) { @@ -243,7 +215,7 @@ static void dump_directory(void) ISO_DIR_ENTRY *dir_entry; char namebuff[16]; - printf("psxcd_dbg: Cached directory record contents:\n"); + _sdk_log("psxcd: Cached directory record contents:\n"); i = 0; dir_pos = 0; @@ -254,7 +226,7 @@ static void dump_directory(void) strncpy(namebuff, _cd_iso_directory_buff+dir_pos+sizeof(ISO_DIR_ENTRY), dir_entry->identifierLen); - printf("P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff); + _sdk_log("psxcd: P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff); dir_pos += dir_entry->entryLength; i++; @@ -273,7 +245,7 @@ static void dump_directory(void) } } - printf("--\n"); + _sdk_log("psxcd: --\n"); } @@ -284,7 +256,7 @@ static void dump_pathtable(void) ISO_DESCRIPTOR *descriptor; char namebuff[16]; - printf("psxcd_dbg: Path table entries:\n"); + _sdk_log("psxcd: Path table entries:\n"); descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; @@ -298,7 +270,7 @@ static void dump_pathtable(void) tbl_pos+sizeof(ISO_PATHTABLE_ENTRY), tbl_entry->nameLength); - printf("psxcd_dbg: %s\n", namebuff); + _sdk_log("psxcd: %s\n", namebuff); // Advance to next entry tbl_pos += sizeof(ISO_PATHTABLE_ENTRY) @@ -393,10 +365,8 @@ static int find_dir_entry(const char *name, ISO_DIR_ENTRY *dirent) int dir_pos; ISO_DIR_ENTRY *dir_entry; char namebuff[16]; - -#ifdef DEBUG - printf( "psxcd_dbg: Locating file %s.\n", name ); -#endif + + _sdk_log("psxcd: Locating file %s.\n", name); i = 0; dir_pos = 0; @@ -434,8 +404,8 @@ static int find_dir_entry(const char *name, ISO_DIR_ENTRY *dirent) static char* get_pathname(char *path, const char *filename) { - char *c = 0; - for (char *i = filename; *i; i++) { + const char *c = 0; + for (const char *i = filename; *i; i++) { if (IS_PATH_SEP(*i)) c = i; } @@ -453,8 +423,8 @@ static char* get_pathname(char *path, const char *filename) static char* get_filename(char *name, const char *filename) { - char *c = 0; - for (char *i = filename; *i; i++) { + const char *c = 0; + for (const char *i = filename; *i; i++) { if (IS_PATH_SEP(*i)) c = i; } @@ -489,40 +459,35 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) // Read ISO descriptor and path table if( _CdReadIsoDescriptor(0) ) { -#ifdef DEBUG - printf("psxcd: Could not read ISO file system.\n"); -#endif + _sdk_log("psxcd: Could not read ISO file system.\n"); return NULL; } -#ifdef DEBUG - // printf("psxcd: ISO file system cache updated.\n"); -#endif + + // _sdk_log("psxcd: ISO file system cache updated.\n"); // _cd_media_changed = 0; //} // Get number of directories in path table num_dirs = get_pathtable_entry(0, NULL, NULL); -#ifdef DEBUG - printf("psxcd_dbg: Directories in path table: %d\n", num_dirs); +#ifndef NDEBUG + _sdk_log("psxcd: Directories in path table: %d\n", num_dirs); rbuff = resolve_pathtable_path(num_dirs-1, tpath_rbuff+127); if( !rbuff ) { - printf("psxcd_dbg: Could not resolve path.\n"); + _sdk_log("psxcd: Could not resolve path.\n"); } else { - printf("psxcd_dbg: Longest path: %s|\n", rbuff); + _sdk_log("psxcd: Longest path: %s|\n", rbuff); } #endif if( get_pathname(search_path, filename) ) { -#ifdef DEBUG - printf("psxcd_dbg: Search path = %s|\n", search_path); -#endif + _sdk_log("psxcd: Search path = %s|\n", search_path); } // Search the pathtable for a matching path @@ -530,9 +495,8 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) for(i=1; i<num_dirs; i++) { rbuff = resolve_pathtable_path(i, tpath_rbuff+127); -#ifdef DEBUG - printf("psxcd_dbg: Found = %s|\n", rbuff); -#endif + _sdk_log("psxcd: Found = %s|\n", rbuff); + if( rbuff ) { if( strcmp(search_path, rbuff) == 0 ) @@ -545,24 +509,16 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) if( !found_dir ) { -#ifdef DEBUG - printf("psxcd_dbg: Directory path not found.\n"); -#endif + _sdk_log("psxcd: Directory path not found.\n"); return NULL; } - -#ifdef DEBUG - printf("psxcd_dbg: Found directory at record %d!\n", found_dir); -#endif - get_pathtable_entry(found_dir, &tbl_entry, NULL); + _sdk_log("psxcd: Found directory at record %d!\n", found_dir); -#ifdef DEBUG - printf("psxcd_dbg: Directory LBA = %d\n", tbl_entry.dirOffs); -#endif + get_pathtable_entry(found_dir, &tbl_entry, NULL); + _sdk_log("psxcd: Directory LBA = %d\n", tbl_entry.dirOffs); _CdReadIsoDirectory(tbl_entry.dirOffs); - get_filename(fp->name, filename); // Add version number if not specified @@ -571,21 +527,18 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) strcat(fp->name, ";1"); } -#ifdef DEBUG - dump_directory(); +#ifndef NDEBUG + //dump_directory(); #endif if( find_dir_entry(fp->name, &dir_entry) ) { -#ifdef DEBUG - printf("psxcd: Could not find file.\n"); -#endif + _sdk_log("psxcd: Could not find file.\n"); + return NULL; } - -#ifdef DEBUG - printf("psxcd_dbg: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); -#endif + + _sdk_log("psxcd: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); CdIntToPos(dir_entry.entryOffs.lsb, &fp->pos); fp->size = dir_entry.entrySize.lsb; @@ -609,14 +562,11 @@ CdlDIR *CdOpenDir(const char* path) // Read ISO descriptor and path table if( _CdReadIsoDescriptor( 0 ) ) { -#ifdef DEBUG - printf( "psxcd: Could not read ISO file system.\n" ); -#endif + _sdk_log( "psxcd: Could not read ISO file system.\n" ); return NULL; } -#ifdef DEBUG -// printf( "psxcd: ISO file system cache updated.\n" ); -#endif + +// _sdk_log( "psxcd: ISO file system cache updated.\n" ); // _cd_media_changed = 0; // } @@ -626,9 +576,8 @@ CdlDIR *CdOpenDir(const char* path) for( i=1; i<num_dirs; i++ ) { rbuff = resolve_pathtable_path( i, tpath_rbuff+127 ); -#ifdef DEBUG - printf( "psxcd_dbg: Found = %s|\n", rbuff ); -#endif + _sdk_log( "psxcd: Found = %s|\n", rbuff ); + if( rbuff ) { if( strcmp( path, rbuff ) == 0 ) @@ -641,21 +590,14 @@ CdlDIR *CdOpenDir(const char* path) if( !found_dir ) { -#ifdef DEBUG - printf( "psxcd_dbg: Directory path not found.\n" ); -#endif + _sdk_log( "psxcd: Directory path not found.\n" ); return NULL; } - -#ifdef DEBUG - printf( "psxcd_dbg: Found directory at record %d!\n", found_dir ); -#endif + + _sdk_log( "psxcd: Found directory at record %d!\n", found_dir ); get_pathtable_entry( found_dir, &tbl_entry, NULL ); - -#ifdef DEBUG - printf( "psxcd_dbg: Directory LBA = %d\n", tbl_entry.dirOffs ); -#endif + _sdk_log( "psxcd: Directory LBA = %d\n", tbl_entry.dirOffs ); _CdReadIsoDirectory( tbl_entry.dirOffs ); @@ -720,15 +662,11 @@ int CdReadDir(CdlDIR *dir, CdlFILE* file) file->size = dir_entry->entrySize.lsb; -#ifdef DEBUG - printf("dir_entry->entryLength = %d, ", dir_entry->entryLength); -#endif - + _sdk_log("psxcd: dir_entry->entryLength = %d, ", dir_entry->entryLength); + d_dir->_pos += dir_entry->entryLength; - -#ifdef DEBUG - printf("d_dir->_pos = %d\n", d_dir->_pos); -#endif + + _sdk_log("psxcd: d_dir->_pos = %d\n", d_dir->_pos); // Check if padding is reached (end of record sector) if( d_dir->_dir[d_dir->_pos] == 0 ) @@ -832,19 +770,13 @@ int CdLoadSession(int session) int i; // Seek to specified session -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Seeking to session %d...\n", session); -#endif + _sdk_log("psxcd: CdLoadSession(): Seeking to session %d...\n", session); CdControl(CdlSetsession, (unsigned char*)&session, (unsigned char*)&resultbuff); if( CdSync(0, 0) == CdlDiskError ) { -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Session seek failed, " - "session does not exist.\n"); - printf("psxcd: CdLoadSession(): Restarting CD-ROM...\n"); -#endif + _sdk_log("psxcd: CdLoadSession(): Session seek failed, session does not exist. Restarting CD-ROM...\n"); // Restart CD-ROM on session seek failure CdControl(CdlNop, 0, 0); @@ -855,39 +787,46 @@ int CdLoadSession(int session) } // Set search routine callback + EnterCriticalSection(); ready_oldcb = CdReadyCallback(_scan_callback); - + ExitCriticalSection(); + _ses_scanfound = 0; _ses_scancount = 0; _ses_scancomplete = 0; _ses_scanbuff = scanbuff; // Begin scan for an ISO volume descriptor -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Scanning for ISO9660 volume descriptor.\n"); -#endif + _sdk_log("psxcd: CdLoadSession(): Scanning for ISO9660 volume descriptor.\n"); + i = CdlModeSpeed; CdControl(CdlSetmode, (unsigned char*)&i, 0); CdControl(CdlReadN, 0, (unsigned char*)resultbuff); // Wait until scan complete while(!_ses_scancomplete); - + + EnterCriticalSection(); CdReadyCallback((void*)_ready_oldcb); - + ExitCriticalSection(); + if( !_ses_scanfound ) { -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); -#endif + _sdk_log("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); + _cd_iso_error = CdlIsoInvalidFs; + EnterCriticalSection(); CdReadyCallback((CdlCB)ready_oldcb); + ExitCriticalSection(); + return -1; } // Restore old callback if any + EnterCriticalSection(); CdReadyCallback((CdlCB)ready_oldcb); - + ExitCriticalSection(); + // Wait until CD-ROM has completely stopped reading, to get a consistent // fix of the CD-ROM pickup's current location do @@ -901,16 +840,12 @@ int CdLoadSession(int session) CdSync(0, 0); loc = (CdlLOC*)resultbuff; - -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Session found in %02d:%02d:%02d (LBA=%d)\n", + + _sdk_log("psxcd: CdLoadSession(): Session found in %02d:%02d:%02d (LBA=%d)\n", btoi(loc->minute), btoi(loc->second), btoi(loc->sector), CdPosToInt(loc)); -#endif - + i = CdPosToInt(loc)-17; -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Session starting at LBA=%d\n", i); -#endif + _sdk_log("psxcd: CdLoadSession(): Session starting at LBA=%d\n", i); _cd_media_changed = 1; diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index 6340638..b914b5e 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -1,6 +1,7 @@ #include <stdint.h> -#include <stdio.h> #include <psxgpu.h> +#include <psxetc.h> +#include <psxapi.h> #include "psxcd.h" #define READ_TIMEOUT 600 // 10 seconds for NTSC @@ -25,8 +26,7 @@ void _cd_control(unsigned char com, const void *param, int plen); void _cd_wait_ack(void); void _cd_wait(void); -int CdInit(void) -{ +int CdInit(void) { // Sets up CD-ROM hardware and low-level subsystem _cd_init(); @@ -37,14 +37,11 @@ int CdInit(void) CdControl(CdlNop, 0, 0); CdControl(CdlInit, 0, 0); - if( CdSync(0, 0) != CdlDiskError ) - { + if(CdSync(0, 0) != CdlDiskError) { CdControl(CdlDemute, 0, 0); - printf("psxcd: Init Ok!\n"); - } - else - { - printf("psxcd: Error initializing. Bad disc/drive or no disc inserted.\n"); + _sdk_log("psxcd: setup done\n"); + } else { + _sdk_log("psxcd: setup error, bad disc/drive or no disc inserted\n"); } return 1; @@ -86,7 +83,7 @@ int CdControlB(unsigned char com, const void *param, unsigned char *result) int CdControlF(unsigned char com, const void *param) { int param_len=0; - + // Command specific parameters switch(com) { @@ -104,31 +101,26 @@ int CdControlF(unsigned char com, const void *param) param_len = 2; break; case CdlSetmode: - param_len = 1; - break; case CdlSetsession: - param_len = 1; - break; case CdlTest: - param_len = 1; - break; case CdlGetTD: param_len = 1; + break; + case CdlReadN: + case CdlReadS: + case CdlSeekL: + case CdlSeekP: + if( param ) + { + _cd_control(CdlSetloc, param, 3); + _cd_last_setloc = *((CdlLOC*)param); + } + break; } - - // Issue Setloc if parameters are specified on CdlReadN and CdlReadS - if( ( com == CdlReadN ) || ( com == CdlReadS ) ) - { - if( param ) - { - _cd_control(CdlSetloc, param, 3); - _cd_last_setloc = *((CdlLOC*)param); - } - } - + // Issue CD command _cd_control(com, param, param_len); - + return 1; } @@ -288,24 +280,18 @@ int CdRead(int sectors, uint32_t *buf, int mode) _cd_read_addr = buf; // Determine sector based on mode flags - if( mode & CdlModeSize0 ) - { - _cd_read_sector_sz = 2328 / 4; - } - else if( mode & CdlModeSize1 ) - { + if( mode & CdlModeSize ) _cd_read_sector_sz = 2340 / 4; - } else - { _cd_read_sector_sz = 2048 / 4; - } _cd_read_counter = VSync(-1); // Set read callback + EnterCriticalSection(); _cd_read_oldcb = CdReadyCallback(_CdReadReadyCallback); - + ExitCriticalSection(); + // Set specified mode CdControl(CdlSetmode, (uint8_t*)&mode, 0); @@ -319,7 +305,7 @@ static void CdDoRetry() { int cb; - printf( "CdRead: Retrying...\n" ); + _sdk_log("psxcd: retrying read...\n"); // Stop reading CdControl(CdlPause, 0, 0); @@ -331,9 +317,11 @@ static void CdDoRetry() // Reset timeout _cd_read_counter = VSync(-1); - + + EnterCriticalSection(); CdReadyCallback(_CdReadReadyCallback); - + ExitCriticalSection(); + // Retry read CdControl(CdlSetloc, (void*)&_cd_last_setloc, 0); CdControl(CdlReadN, 0, (uint8_t*)_cd_read_result); diff --git a/libpsn00b/psxcd/psxcd_asm.s b/libpsn00b/psxcd/psxcd_asm.s index 906ab32..c0a5312 100644 --- a/libpsn00b/psxcd/psxcd_asm.s +++ b/libpsn00b/psxcd/psxcd_asm.s @@ -413,17 +413,11 @@ CdAutoPauseCallback: lw $v0, 0($v1) la $v1, _cd_callback_int4 - - jal EnterCriticalSection - nop - + lw $a0, 4($sp) nop sw $a0, 0($v1) - - jal ExitCriticalSection - nop - + lw $ra, 0($sp) addiu $sp, 8 jr $ra @@ -443,17 +437,11 @@ CdReadyCallback: la $v1, _cd_callback_int1_data sw $v0, 8($sp) - - jal EnterCriticalSection - nop - + lw $a0, 4($sp) nop sw $a0, 0($v1) - - jal ExitCriticalSection - nop - + lw $ra, 0($sp) lw $v0, 8($sp) jr $ra @@ -472,17 +460,11 @@ CdSyncCallback: la $v1, _cd_sync_cb sw $v0, 8($sp) - - jal EnterCriticalSection - nop - + lw $a0, 4($sp) nop sw $a0, 0($v1) - - jal ExitCriticalSection - nop - + lw $ra, 0($sp) lw $v0, 8($sp) jr $ra @@ -490,13 +472,7 @@ CdSyncCallback: .section .data - -.global psxcd_credits -.type psxcd_credits, @object -psxgpu_credits: - .ascii "psxcd library programs by Lameguy64\n" - .asciiz "2020 PSn00bSDK Project / Meido-Tek Productions\n" - + .comm _cd_last_cmd, 1, 1 .comm _cd_last_mode, 1, 1 .comm _cd_ack_wait, 1, 1 diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c index 6d37605..b85a7df 100644 --- a/libpsn00b/psxetc/dl.c +++ b/libpsn00b/psxetc/dl.c @@ -30,13 +30,11 @@ #include <elf.h> #include <dlfcn.h> #include <string.h> +#include <psxetc.h> #include <psxapi.h> /* Compile options */ -// Uncomment before building to enable debug logging (via printf()). -//#define DEBUG - // Comment before building to disable functions that rely on BIOS file APIs, // i.e. DL_LoadSymbolMapFromFile() and DL_LoadDLLFromFile(). // FIXME: those seem to be broken currently, and shouldn't be used anyway @@ -69,12 +67,6 @@ void *(*_dl_resolve_callback)(DLL *, const char *) = 0; /* Private utilities */ -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else -#define _LOG(...) -#endif - #define _ERROR(code, ret) { \ _error_code = code; \ return ret; \ @@ -95,7 +87,7 @@ void *_dl_resolve_helper(DLL *dll, uint32_t index) { address = DL_GetSymbolByName(_name); if (!address) { - _LOG("psxetc: FATAL! Can't resolve %s, locking up\n", _name); + _sdk_log("psxetc: FATAL! can't resolve %s, locking up\n", _name); while (1) __asm__ volatile("nop"); } @@ -136,7 +128,7 @@ static uint32_t _elf_hash(const char *str) { static uint8_t *_dl_load_file(const char *filename, size_t *size_output) { int32_t fd = open(filename, 1); if (fd < 0) { - _LOG("psxetc: Can't open %s, error = %d\n", filename, fd); + _sdk_log("psxetc: can't open %s, error = %d\n", filename, fd); _ERROR(RTLD_E_FILE_OPEN, 0); } @@ -147,11 +139,11 @@ static uint8_t *_dl_load_file(const char *filename, size_t *size_output) { uint8_t *buffer = malloc(size); if (!buffer) { - _LOG("psxetc: Unable to allocate %d bytes for %s\n", size, filename); + _sdk_log("psxetc: unable to allocate %d bytes for %s\n", size, filename); _ERROR(RTLD_E_FILE_ALLOC, 0); } - _LOG("psxetc: Loading %s (%d bytes)..", filename, size); + //_sdk_log("psxetc: loading %s (%d bytes)..", filename, size); for (uint32_t offset = 0; offset < size; ) { int32_t length = read(fd, &(buffer[offset]), 0x800); @@ -160,16 +152,16 @@ static uint8_t *_dl_load_file(const char *filename, size_t *size_output) { close(fd); free(buffer); - _LOG("failed, error = %d\n", length); + _sdk_log("failed, error = %d\n", length); _ERROR(RTLD_E_FILE_READ, 0); } - _LOG("."); + //_sdk_log("."); offset += length; } close(fd); - _LOG(" done\n"); + _sdk_log(" done\n"); if (size_output) *size_output = size; @@ -195,8 +187,8 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { // in order to minimize hash table size _symbol_map.nbucket = entries; _symbol_map.nchain = entries; - _LOG( - "psxetc: Allocating nbucket = %d, nchain = %d\n", + _sdk_log( + "psxetc: allocating nbucket = %d, nchain = %d\n", _symbol_map.nbucket, entries ); @@ -208,7 +200,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { _symbol_map.chain = malloc(sizeof(uint32_t) * entries); if (!_symbol_map.entries || !_symbol_map.bucket || !_symbol_map.chain) { - _LOG("psxetc: Unable to allocate symbol map table\n"); + _sdk_log("psxetc: unable to allocate symbol map table\n"); _ERROR(RTLD_E_MAP_ALLOC, -1); } @@ -251,13 +243,10 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { (_type == 'D') || // .data (_type == 'B') // .bss )) { - _LOG( - "psxetc: Map sym: %08x,%08x [%c %s]\n", - address, - _size, - _type, - name - ); + //_sdk_log( + //"psxetc: map sym: %08x,%08x [%c %s]\n", + //address, _size, _type, name + //); MapEntry *entry = &(_symbol_map.entries[index]); entry->hash = hash; @@ -280,7 +269,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { pos++; } - _LOG("psxetc: Parsed %d symbols\n", entries); + _sdk_log("psxetc: parsed %d symbols\n", entries); if (!entries) _ERROR(RTLD_E_NO_SYMBOLS, -1); @@ -313,7 +302,7 @@ void DL_UnloadSymbolMap(void) { void *DL_GetSymbolByName(const char *name) { if (!_symbol_map.entries) { - _LOG("psxetc: Attempted lookup with no map loaded\n"); + _sdk_log("psxetc: attempted lookup with no map loaded\n"); _ERROR(RTLD_E_NO_MAP, 0); } @@ -325,10 +314,9 @@ void *DL_GetSymbolByName(const char *name) { // calculated. for (uint32_t i = _symbol_map.bucket[hash_mod]; i != 0xffffffff;) { if (i >= _symbol_map.nchain) { - _LOG( - "psxetc: GetSymbolByName() index out of bounds (i = %d, n = %d)\n", - i, - _symbol_map.nchain + _sdk_log( + "psxetc: GetSymbolByName() index out of bounds (%d >= %d)\n", + i, _symbol_map.nchain ); _ERROR(RTLD_E_HASH_LOOKUP, 0); } @@ -336,14 +324,14 @@ void *DL_GetSymbolByName(const char *name) { MapEntry *entry = &(_symbol_map.entries[i]); if (hash == entry->hash) { - _LOG("psxetc: Map lookup [%s = %08x]\n", name, entry->ptr); + //_sdk_log("psxetc: map lookup [%s = %08x]\n", name, entry->ptr); return entry->ptr; } i = _symbol_map.chain[i]; } - _LOG("psxetc: Map lookup [%s not found]\n", name); + _sdk_log("psxetc: map lookup [%s not found]\n", name); _ERROR(RTLD_E_MAP_SYMBOL, 0); } @@ -359,14 +347,14 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { DLL *dll = malloc(sizeof(DLL)); if (!dll) { - _LOG("psxetc: Unable to allocate DLL struct\n"); + _sdk_log("psxetc: unable to allocate DLL struct\n"); _ERROR(RTLD_E_DLL_ALLOC, 0); } dll->ptr = ptr; dll->malloc_ptr = (mode & RTLD_FREE_ON_DESTROY) ? ptr : 0; dll->size = size; - _LOG("psxetc: Initializing DLL at %08x\n", ptr); + _sdk_log("psxetc: initializing DLL at %08x\n", ptr); // Interpret the key-value pairs in the .dynamic section to obtain info // about all the other sections. The pairs are null-terminated, which makes @@ -375,128 +363,128 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { uint32_t first_got_sym = 0; for (Elf32_Dyn *dyn = (Elf32_Dyn *) ptr; dyn->d_tag; dyn++) { - _LOG("psxetc: .dynamic %08x=%08x ", dyn->d_tag, dyn->d_un.d_val); + //_sdk_log("psxetc: .dynamic %08x=%08x ", dyn->d_tag, dyn->d_un.d_val); switch (dyn->d_tag) { // Offset of .got section case DT_PLTGOT: - _LOG("[PLTGOT]\n"); + //_sdk_log("[PLTGOT]\n"); dll->got = (void *) (ptr + dyn->d_un.d_val); break; // Offset of .hash section case DT_HASH: - _LOG("[HASH]\n"); + //_sdk_log("[HASH]\n"); dll->hash = (void *) (ptr + dyn->d_un.d_val); break; // Offset of .dynstr (NOT .strtab) section case DT_STRTAB: - _LOG("[STRTAB]\n"); + //_sdk_log("[STRTAB]\n"); dll->strtab = (void *) (ptr + dyn->d_un.d_val); break; // Offset of .dynsym (NOT .symtab) section case DT_SYMTAB: - _LOG("[SYMTAB]\n"); + //_sdk_log("[SYMTAB]\n"); dll->symtab = (void *) (ptr + dyn->d_un.d_val); break; // Length of .dynstr section //case DT_STRSZ: - //_LOG("[STRSZ]\n"); + //_sdk_log("[STRSZ]\n"); //break; // Length of each .dynsym entry case DT_SYMENT: - _LOG("[SYMENT]\n"); + //_sdk_log("[SYMENT]\n"); // Only 16-byte symbol table entries are supported. if (dyn->d_un.d_val != sizeof(Elf32_Sym)) { free(dll); - _LOG("psxetc: Invalid symtab entry size %d\n", dyn->d_un.d_val); + _sdk_log("psxetc: invalid DLL symtab entry size %d\n", dyn->d_un.d_val); _ERROR(RTLD_E_DLL_FORMAT, 0); } break; // MIPS ABI (?) version case DT_MIPS_RLD_VERSION: - _LOG("[MIPS_RLD_VERSION]\n"); + //_sdk_log("[MIPS_RLD_VERSION]\n"); // Versions other than 1 are unsupported (do they even exist?). if (dyn->d_un.d_val != 1) { free(dll); - _LOG("psxetc: Invalid DLL version %d\n", dyn->d_un.d_val); + _sdk_log("psxetc: invalid DLL version %d\n", dyn->d_un.d_val); _ERROR(RTLD_E_DLL_FORMAT, 0); } break; // DLL/ABI flags case DT_MIPS_FLAGS: - _LOG("[MIPS_FLAGS]\n"); + //_sdk_log("[MIPS_FLAGS]\n"); // Shortcut pointers (whatever they are) are not supported. if (dyn->d_un.d_val & RHF_QUICKSTART) { free(dll); - _LOG("psxetc: Invalid flags\n"); + _sdk_log("psxetc: invalid DLL flags\n"); _ERROR(RTLD_E_DLL_FORMAT, 0); } break; // Number of local (not to resolve) GOT entries case DT_MIPS_LOCAL_GOTNO: - _LOG("[MIPS_LOCAL_GOTNO]\n"); + //_sdk_log("[MIPS_LOCAL_GOTNO]\n"); local_got_len = dyn->d_un.d_val; break; // Base address DLL was compiled for case DT_MIPS_BASE_ADDRESS: - _LOG("[MIPS_BASE_ADDRESS]\n"); + //_sdk_log("[MIPS_BASE_ADDRESS]\n"); // Base addresses other than zero are not supported. It would // be easy enough to support them, but why? if (dyn->d_un.d_val) { free(dll); - _LOG("psxetc: Invalid base address %08x\n", dyn->d_un.d_val); + _sdk_log("psxetc: invalid DLL base address %08x\n", dyn->d_un.d_val); _ERROR(RTLD_E_DLL_FORMAT, 0); } break; // Number of symbol table entries case DT_MIPS_SYMTABNO: - _LOG("[MIPS_SYMTABNO]\n"); + //_sdk_log("[MIPS_SYMTABNO]\n"); dll->symbol_count = dyn->d_un.d_val; break; // Index of first unresolved symbol table entry //case DT_MIPS_UNREFEXTNO: - //_LOG("[MIPS_UNREFEXTNO]\n"); + //_sdk_log("[MIPS_UNREFEXTNO]\n"); //break; // Index of first symbol table entry which has a matching GOT entry case DT_MIPS_GOTSYM: - _LOG("[MIPS_GOTSYM]\n"); + //_sdk_log("[MIPS_GOTSYM]\n"); first_got_sym = dyn->d_un.d_val; break; // Number of pages the GOT is split into (does not apply to PS1) //case DT_MIPS_HIPAGENO: - //_LOG("[MIPS_HIPAGENO]\n"); + //_sdk_log("[MIPS_HIPAGENO]\n"); //break; - default: - _LOG("[ignored]\n"); + //default: + //_sdk_log("[ignored]\n"); } } @@ -508,10 +496,9 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { ((uint32_t) ptr + size - (uint32_t) dll->got) / sizeof(uint32_t) - 2; dll->got_length = local_got_len + (dll->symbol_count - first_got_sym) - 2; - _LOG( + _sdk_log( "psxetc: %d symbols, %d GOT entries\n", - dll->symbol_count, - dll->got_length + dll->symbol_count, dll->got_length ); // Relocate the DLL by adding its base address to all pointers in the GOT @@ -538,12 +525,10 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { continue; sym->st_value += (uint32_t) ptr; - _LOG( - "psxetc: DLL sym: %08x,%08x [%s]\n", - sym->st_value, - sym->st_size, - _name - ); + //_sdk_log( + //"psxetc: DLL sym: %08x,%08x [%s]\n", + //sym->st_value, sym->st_size, _name + //); // If RTLD_NOW was passed, resolve GOT entries ahead of time by // cross-referencing them with the symbol table. @@ -651,7 +636,7 @@ void *DL_GetDLLSymbol(const DLL *dll, const char *name) { // provided. for (uint32_t i = bucket[hash_mod]; i != 0xffffffff;) { if (i >= nchain) { - _LOG("psxetc: DL_GetDLLSymbol() index out of bounds (i = %d, n = %d)\n", i, nchain); + _sdk_log("psxetc: DL_GetDLLSymbol() index out of bounds (%d >= %d)\n", i, nchain); _ERROR(RTLD_E_HASH_LOOKUP, 0); } @@ -659,14 +644,14 @@ void *DL_GetDLLSymbol(const DLL *dll, const char *name) { const char *_name = &(dll->strtab[sym->st_name]); if (!strcmp(name, _name)) { - _LOG("psxetc: DLL lookup [%s = %08x]\n", name, sym->st_value); + //_sdk_log("psxetc: DLL lookup [%s = %08x]\n", name, sym->st_value); return sym->st_value; } i = chain[i]; } - _LOG("psxetc: DLL lookup [%s not found]\n", name); + _sdk_log("psxetc: DLL lookup [%s not found]\n", name); _ERROR(RTLD_E_DLL_SYMBOL, 0); } diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c index 859209a..cc9d12c 100644 --- a/libpsn00b/psxetc/interrupts.c +++ b/libpsn00b/psxetc/interrupts.c @@ -53,44 +53,50 @@ static const struct JMP_BUF _isr_jmp_buf = { /* Internal IRQ and DMA handlers */ static void _global_isr(void) { - uint16_t stat = IRQ_STAT, mask = IRQ_MASK; + uint16_t stat = IRQ_STAT & IRQ_MASK; - // Clear all IRQ flags in one shot. This is not the "proper" way to do it - // but it's much faster than clearing one flag at a time. - IRQ_STAT = ~mask; + for (; stat; stat = IRQ_STAT & IRQ_MASK) { + //for (int i = 0; i < NUM_IRQ_CHANNELS; i++) { + for (int i = 0, mask = 1; stat; i++, stat >>= 1, mask <<= 1) { + if (!(stat & 1)) + continue; - //for (int i = 0; i < NUM_IRQ_CHANNELS; i++) { - for (int i = 0; stat; i++, stat >>= 1) { - if (!(stat & 1)) - continue; + // Acknowledge the current IRQ. Note that clearing all IRQ flags in one + // shot would result in hard-to-debug race conditions (been there, done + // that). + IRQ_STAT = (uint16_t) (mask ^ 0xffff); - if (_irq_handlers[i]) - _irq_handlers[i](); + if (_irq_handlers[i]) + _irq_handlers[i](); + } } ReturnFromException(); } static void _global_dma_handler(void) { - uint32_t stat = DMA_DICR; + uint32_t dicr = DMA_DICR; + uint32_t stat = (dicr >> 24) & 0x7f; + + for (; stat; dicr = DMA_DICR, stat = (dicr >> 24) & 0x7f) { + uint32_t base = dicr & 0x00ffffff; - // Clear all DMA IRQ flags in one shot (note that flags are cleared by - // writing 1 to them rather than 0). - stat &= 0x7fff0000; - DMA_DICR = stat; - stat >>= 24; + //for (int i = 0; i < NUM_DMA_CHANNELS; i++) { + for (int i = 0, mask = (1 << 24); stat; i++, stat >>= 1, mask <<= 1) { + if (!(stat & 1)) + continue; - //for (int i = 0; i < NUM_DMA_CHANNELS; i++) { - for (int i = 0; stat; i++, stat >>= 1) { - if (!(stat & 1)) - continue; + // Acknowledge the current DMA channel's IRQ. For whatever reason + // DMA IRQ flags are cleared by writing 1 to them rather than 0. + DMA_DICR = base | mask; - if (_dma_handlers[i]) - _dma_handlers[i](); + if (_dma_handlers[i]) + _dma_handlers[i](); + } } } -/* Callback registration API */ +/* IRQ and DMA handler API */ void *InterruptCallback(int irq, void (*func)(void)) { if ((irq < 0) || (irq >= NUM_IRQ_CHANNELS)) @@ -127,12 +133,12 @@ void *DMACallback(int dma, void (*func)(void)) { // the callback is being registered or removed. The main DMA IRQ dispatcher // is also registered if this is the first DMA callback being configured, // or disabled if it's the last one being removed. - if (func) { + if (!old_callback && func) { DMA_DICR |= (0x10000 << dma) | (1 << 23); if (!(_num_dma_handlers++)) InterruptCallback(3, &_global_dma_handler); - } else { + } else if (old_callback && !func) { if (--_num_dma_handlers) { DMA_DICR &= ~(0x10000 << dma); } else { @@ -158,7 +164,7 @@ int ResetCallback(void) { return -1; EnterCriticalSection(); - _saved_irq_mask = 1 << 3; // Enable DMA IRQ by default + _saved_irq_mask = 0; _saved_dma_dpcr = 0x03333333; _saved_dma_dicr = 0; @@ -167,10 +173,6 @@ int ResetCallback(void) { for (int i = 0; i < NUM_DMA_CHANNELS; i++) _dma_handlers[i] = (void *) 0; - // Set up the DMA IRQ handler. This handler shall *not* be overridden using - // InterruptCallback(). - _irq_handlers[3] = &_global_dma_handler; - _96_remove(); RestartCallback(); return 0; diff --git a/libpsn00b/psxetc/logging.c b/libpsn00b/psxetc/logging.c new file mode 100644 index 0000000..5199190 --- /dev/null +++ b/libpsn00b/psxetc/logging.c @@ -0,0 +1,50 @@ +/* + * PSn00bSDK internal debug logger + * (C) 2022 spicyjpeg - MPL licensed + * + * This file provides the (admittedly minimal) logging system used by all + * PSn00bSDK libraries. Log messages and warnings are issued using the + * _sdk_log() macro and collected into a buffer, whose contents can be flushed + * by calling _sdk_dump_log() (by default this is done by VSync()). Logging is + * only enabled in debug builds of libpsn00b. + */ + +#include <stddef.h> +#include <stdarg.h> +#include <stdio.h> +#include <psxapi.h> +#include <psxetc.h> + +#define LOG_BUFFER_SIZE 256 + +#ifndef NDEBUG + +/* Internal globals */ + +static char _log_buffer[LOG_BUFFER_SIZE]; +static size_t _log_buffer_length = 0; + +/* Internal logging API */ + +void _sdk_log_inner(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + _log_buffer_length += vsnprintf( + &_log_buffer[_log_buffer_length], + LOG_BUFFER_SIZE - _log_buffer_length, + fmt, + ap + ); + va_end(ap); +} + +void _sdk_dump_log_inner(void) { + if (!_log_buffer_length) + return; + + write(1, _log_buffer, _log_buffer_length); + _log_buffer_length = 0; +} + +#endif diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index cef1508..a262472 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -4,7 +4,6 @@ */ #include <stdint.h> -#include <stdio.h> #include <psxetc.h> #include <psxapi.h> #include <psxgpu.h> @@ -16,6 +15,13 @@ static void _default_vsync_halt(void); +/* Private types */ + +typedef struct { + void (*func)(uint32_t, uint32_t, uint32_t); + uint32_t arg1, arg2, arg3; +} QueueEntry; + /* Internal globals */ GPU_VideoMode _gpu_video_mode; @@ -24,12 +30,12 @@ static void (*_vsync_halt_func)(void) = &_default_vsync_halt; static void (*_vsync_callback)(void) = (void *) 0; static void (*_drawsync_callback)(void) = (void *) 0; -static const uint32_t *volatile _draw_queue[QUEUE_LENGTH]; -static volatile uint8_t _queue_head, _queue_tail, _queue_length; -static volatile uint32_t _vblank_counter; -static volatile uint16_t _last_hblank; +static volatile QueueEntry _draw_queue[QUEUE_LENGTH]; +static volatile uint8_t _queue_head, _queue_tail, _queue_length; +static volatile uint32_t _vblank_counter; +static volatile uint16_t _last_hblank; -/* Interrupt handlers */ +/* Private interrupt handlers */ static void _vblank_handler(void) { _vblank_counter++; @@ -43,11 +49,11 @@ static void _gpu_dma_handler(void) { while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); - if (_queue_length) { - DrawOTag2(_draw_queue[_queue_head++]); - - _queue_length--; + if (--_queue_length) { + volatile QueueEntry *entry = &_draw_queue[_queue_head++]; _queue_head %= QUEUE_LENGTH; + + entry->func(entry->arg1, entry->arg2, entry->arg3); } else { GPU_GP1 = 0x04000000; // Disable DMA request @@ -69,7 +75,7 @@ void ResetGraph(int mode) { _gpu_video_mode = (GPU_GP1 >> 20) & 1; ExitCriticalSection(); - printf("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); + _sdk_log("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } if (mode == 3) { @@ -97,18 +103,18 @@ void ResetGraph(int mode) { _last_hblank = 0; } -/* Syncing API */ +/* VSync() API */ // TODO: add support for no$psx's "halt" register static void _default_vsync_halt(void) { int counter = _vblank_counter; - for (int i = VSYNC_TIMEOUT; i; i--) { if (counter != _vblank_counter) return; } - printf("psxgpu: VSync() timeout\n"); + _sdk_log("psxgpu: VSync() timeout\n"); + _sdk_dump_log(); ChangeClearPAD(0); ChangeClearRCnt(3, 0); } @@ -124,6 +130,7 @@ int VSync(int mode) { // Wait for at least one vertical blank event to occur. do { + _sdk_dump_log(); _vsync_halt_func(); // If interlaced mode is enabled, wait until the GPU starts displaying @@ -138,27 +145,6 @@ int VSync(int mode) { return delta; } -int DrawSync(int mode) { - if (mode) - return (DMA_BCR(2) >> 16); - - // Wait for the queue to become empty. - // TODO: add a timeout - while (_queue_length) - __asm__ volatile(""); - - // Wait for any DMA transfer to finish if DMA is enabled. - if (GPU_GP1 & (3 << 29)) { - while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(2) & (1 << 24))) - __asm__ volatile(""); - } - - while (!(GPU_GP1 & (1 << 26))) - __asm__ volatile(""); - - return 0; -} - void *VSyncHaltFunction(void (*func)(void)) { void *old_callback = _vsync_halt_func; _vsync_halt_func = func; @@ -176,6 +162,81 @@ void *VSyncCallback(void (*func)(void)) { return old_callback; } +/* Command queue API */ + +// This function is normally only used internally, but it is exposed for +// advanced use cases. +int EnqueueDrawOp( + void (*func)(uint32_t, uint32_t, uint32_t), + uint32_t arg1, + uint32_t arg2, + uint32_t arg3 +) { + // If GPU DMA is currently busy, append the command to the queue instead of + // executing it immediately. Note that interrupts must be disabled *prior* + // to checking if DMA is busy; disabling them afterwards would create a + // race condition where the DMA transfer could end while interrupts are + // being disabled. Interrupts are disabled through the IRQ_MASK register + // rather than by calling EnterCriticalSection() for performance reasons. + uint16_t mask = IRQ_MASK; + IRQ_MASK = 0; + + if (_queue_length) { + if (_queue_length >= QUEUE_LENGTH) { + IRQ_MASK = mask; + _sdk_log("psxgpu: draw queue overflow, dropping commands\n"); + return -1; + } + + int length = _queue_length; + _queue_length = length + 1; + + volatile QueueEntry *entry = &_draw_queue[_queue_tail++]; + _queue_tail %= QUEUE_LENGTH; + + entry->func = func; + entry->arg1 = arg1; + entry->arg2 = arg2; + entry->arg3 = arg3; + + IRQ_MASK = mask; + return length; + } + + _queue_length = 1; + + IRQ_MASK = mask; + func(arg1, arg2, arg3); + return 0; +} + +int DrawSync(int mode) { + if (mode) + return _queue_length; + + // Wait for the queue to become empty. + for (int i = VSYNC_TIMEOUT; i; i--) { + if (!_queue_length) + break; + } + + if (!_queue_length) { + // Wait for any DMA transfer to finish if DMA is enabled. + if (GPU_GP1 & (3 << 29)) { + while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(2) & (1 << 24))) + __asm__ volatile(""); + } + + while (!(GPU_GP1 & (1 << 26))) + __asm__ volatile(""); + } else { + _sdk_log("psxgpu: DrawSync() timeout\n"); + _sdk_dump_log(); + } + + return _queue_length; +} + void *DrawSyncCallback(void (*func)(void)) { EnterCriticalSection(); @@ -208,45 +269,8 @@ void ClearOTag(uint32_t *ot, size_t length) { ot[length - 1] = 0x00ffffff; } -void DrawOTag(const uint32_t *ot) { - // If GPU DMA is currently busy, append the OT to the queue instead of - // drawing it immediately. Note that interrupts must be disabled *prior* to - // checking if DMA is busy; disabling them afterwards would create a race - // condition where the DMA transfer could end while interrupts are being - // disabled. Interrupts are disabled through the IRQ_MASK register rather - // than by calling EnterCriticalSection() for performance reasons. - uint16_t mask = IRQ_MASK; - IRQ_MASK = 0; - - if (DMA_CHCR(2) & (1 << 24)) { - if (_queue_length < QUEUE_LENGTH) { - _draw_queue[_queue_tail++] = ot; - - _queue_length++; - _queue_tail %= QUEUE_LENGTH; - - IRQ_MASK = mask; - return; - } - - IRQ_MASK = mask; - printf("psxgpu: DrawOTag() failed, draw queue full\n"); - return; - } - - IRQ_MASK = mask; - DrawOTag2(ot); -} - -void DrawOTag2(const uint32_t *ot) { - GPU_GP1 = 0x04000002; - - while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24))) - __asm__ volatile(""); - - DMA_MADR(2) = (uint32_t) ot; - DMA_BCR(2) = 0; - DMA_CHCR(2) = 0x01000401; +void AddPrim(uint32_t *ot, const void *pri) { + addPrim(ot, pri); } void DrawPrim(const uint32_t *pri) { @@ -267,8 +291,19 @@ void DrawPrim(const uint32_t *pri) { DMA_CHCR(2) = 0x01000201; } -void AddPrim(uint32_t *ot, const void *pri) { - addPrim(ot, pri); +int DrawOTag(const uint32_t *ot) { + return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) ot, 0, 0); +} + +void DrawOTag2(const uint32_t *ot) { + GPU_GP1 = 0x04000002; + + while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24))) + __asm__ volatile(""); + + DMA_MADR(2) = (uint32_t) ot; + DMA_BCR(2) = 0; + DMA_CHCR(2) = 0x01000401; } /* Misc. functions */ diff --git a/libpsn00b/psxgpu/dbugfont.png b/libpsn00b/psxgpu/dbugfont.png Binary files differnew file mode 100644 index 0000000..ed84268 --- /dev/null +++ b/libpsn00b/psxgpu/dbugfont.png diff --git a/libpsn00b/psxgpu/dbugfont.tim b/libpsn00b/psxgpu/dbugfont.tim Binary files differindex 4e6cce2..1edd4af 100644 --- a/libpsn00b/psxgpu/dbugfont.tim +++ b/libpsn00b/psxgpu/dbugfont.tim diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index 5642ad4..f513727 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -37,7 +37,7 @@ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { return env; } -void DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { +int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { DR_ENV *prim = &(env->dr_env); // All commands are grouped into a single display list packet for @@ -85,7 +85,7 @@ void DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { //while (!(GPU_GP1 & (1 << 26))) //__asm__ volatile(""); - DrawOTag((const uint32_t *) prim); + return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) prim, 0, 0); } void PutDrawEnv(DRAWENV *env) { diff --git a/libpsn00b/psxgpu/font.c b/libpsn00b/psxgpu/font.c index 2d4105f..b1c3c7a 100644 --- a/libpsn00b/psxgpu/font.c +++ b/libpsn00b/psxgpu/font.c @@ -27,16 +27,16 @@ void FntLoad(int x, int y) { RECT pos; TIM_IMAGE tim; - GetTimInfo( (const uint32_t *) _gpu_debug_font, &tim ); + GetTimInfo((const uint32_t *) _gpu_debug_font, &tim); // Load font image pos = *tim.prect; pos.x = x; pos.y = y; - _font_tpage = getTPage( 0, 0, pos.x, pos.y ); + _font_tpage = getTPage(0, 0, pos.x, pos.y); - LoadImage( &pos, tim.paddr ); + LoadImage(&pos, tim.paddr); DrawSync(0); // Load font clut @@ -44,9 +44,9 @@ void FntLoad(int x, int y) { pos.x = x; pos.y = y+tim.prect->h; - _font_clut = getClut( pos.x, pos.y ); + _font_clut = getClut(pos.x, pos.y); - LoadImage( &pos, tim.caddr ); + LoadImage(&pos, tim.caddr); DrawSync(0); // Clear previously opened text streams @@ -193,10 +193,11 @@ char *FntFlush(int id) { if( i > 0 ) { i--; - setSprt8( sprt ); - setRGB0( sprt, 128, 128, 128 ); - setXY0( sprt, sx, sy ); - setUV0( sprt, (i%16)<<3, (i>>4)<<3 ); + setSprt8(sprt); + setShadeTex(sprt, 1); + setSemiTrans(sprt, 1); + setXY0(sprt, sx, sy); + setUV0(sprt, (i % 16) * 8, (i / 16) * 8); sprt->clut = _font_clut; setaddr(opri, sprt); opri = (char*)sprt; @@ -237,12 +238,13 @@ char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { if( i > 0 ) { i--; - setSprt8( sprt ); - setRGB0( sprt, 128, 128, 128 ); - setXY0( sprt, x, y ); - setUV0( sprt, (i%16)<<3, (i>>4)<<3 ); + setSprt8(sprt); + setShadeTex(sprt, 1); + setSemiTrans(sprt, 1); + setXY0(sprt, x, y); + setUV0(sprt, (i % 16) * 8, (i / 16) * 8); sprt->clut = _font_clut; - addPrim( ot, sprt ); + addPrim(ot, sprt); sprt++; } @@ -256,9 +258,9 @@ char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { tpage = (DR_TPAGE*)pri; tpage->code[0] = _font_tpage; - setlen( tpage, 1 ); - setcode( tpage, 0xe1 ); - addPrim( ot, pri ); + setlen(tpage, 1); + setcode(tpage, 0xe1); + addPrim(ot, pri); pri += sizeof(DR_TPAGE); return pri; diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index da51e7d..968dde5 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -4,42 +4,36 @@ */ #include <stdint.h> -#include <stdio.h> +#include <psxetc.h> #include <psxgpu.h> #include <hwregs_c.h> #define DMA_CHUNK_LENGTH 8 -/* VRAM transfer API */ +/* Private utilities */ -static void _load_store_image( - uint32_t command, - int mode, - const RECT *rect, - uint32_t *data -) { +static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { size_t length = rect->w * rect->h; if (length % 2) - printf("psxgpu: can't transfer an odd number of pixels\n"); + _sdk_log("psxgpu: can't transfer an odd number of pixels\n"); length /= 2; if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } - DrawSync(0); GPU_GP1 = 0x04000000; // Disable DMA request GPU_GP0 = 0x01000000; // Flush cache - GPU_GP0 = command; + GPU_GP0 = write ? 0xa0000000 : 0xc0000000; //GPU_GP0 = rect->x | (rect->y << 16); GPU_GP0 = *((const uint32_t *) &(rect->x)); //GPU_GP0 = rect->w | (rect->h << 16); GPU_GP0 = *((const uint32_t *) &(rect->w)); // Enable DMA request, route to GP0 (2) or from GPU_READ (3) - GPU_GP1 = 0x04000000 | mode; + GPU_GP1 = 0x04000002 | (write ^ 1); DMA_MADR(2) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) @@ -47,15 +41,42 @@ static void _load_store_image( else DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); - DMA_CHCR(2) = 0x01000200 | ((mode & 1) ^ 1); + DMA_CHCR(2) = 0x01000200 | write; +} + +/* VRAM transfer API */ + +int LoadImage(const RECT *rect, const uint32_t *data) { + return EnqueueDrawOp( + (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 1 + ); +} + +int StoreImage(const RECT *rect, uint32_t *data) { + return EnqueueDrawOp( + (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 0 + ); } -void LoadImage(const RECT *rect, const uint32_t *data) { - _load_store_image(0xa0000000, 2, rect, (uint32_t *) data); +int MoveImage(const RECT *rect, int x, int y) { + return EnqueueDrawOp((void *) &MoveImage2, (uint32_t) rect, x, y); } -void StoreImage(const RECT *rect, uint32_t *data) { - _load_store_image(0xc0000000, 3, rect, data); +void LoadImage2(const RECT *rect, const uint32_t *data) { + _dma_transfer(rect, (uint32_t *) data, 1); +} + +void StoreImage2(const RECT *rect, uint32_t *data) { + _dma_transfer(rect, data, 0); +} + +void MoveImage2(const RECT *rect, int x, int y) { + GPU_GP0 = 0x80000000; + //GPU_GP0 = rect->x | (rect->y << 16); + GPU_GP0 = *((const uint32_t *) &(rect->x)); + GPU_GP0 = (x & 0xffff) | (y << 16); + //GPU_GP0 = rect->w | (rect->h << 16); + GPU_GP0 = *((const uint32_t *) &(rect->w)); } /* .TIM image parsers */ diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index 9c82d6b..d43436f 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -4,13 +4,13 @@ */ #include <stdint.h> -#include <stdio.h> +#include <psxetc.h> #include <psxapi.h> #include <psxpress.h> #include <hwregs_c.h> #define DMA_CHUNK_LENGTH 32 -#define MDEC_SYNC_TIMEOUT 0x1000000 +#define MDEC_SYNC_TIMEOUT 0x100000 /* Default IDCT matrix and quantization tables */ @@ -127,7 +127,7 @@ void DecDCTin(const uint32_t *data, int mode) { // the stream. void DecDCTinRaw(const uint32_t *data, size_t length) { if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxmdec: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } @@ -149,13 +149,19 @@ int DecDCTinSync(int mode) { return 0; } - printf("psxpress: DecDCTinSync() timeout\n"); + _sdk_log("psxpress: DecDCTinSync() timeout\n"); + _sdk_dump_log(); return -1; } void DecDCTout(uint32_t *data, size_t length) { DecDCToutSync(0); + if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { + _sdk_log("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + length += DMA_CHUNK_LENGTH - 1; + } + DMA_MADR(1) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) DMA_BCR(1) = 0x00010000 | length; @@ -174,6 +180,7 @@ int DecDCToutSync(int mode) { return 0; } - printf("psxpress: DecDCToutSync() timeout\n"); + _sdk_log("psxpress: DecDCToutSync() timeout\n"); + _sdk_dump_log(); return -1; } diff --git a/libpsn00b/psxpress/vlc.s b/libpsn00b/psxpress/vlc.s index fe51642..885a3f7 100644 --- a/libpsn00b/psxpress/vlc.s +++ b/libpsn00b/psxpress/vlc.s @@ -131,10 +131,12 @@ _vlc_skip_context_load: #nop .Lprocess_dc_v2_coefficient: # if (!coeff_index && !is_v3) - # The DC coefficient in version 2 frames is not compressed. - srl $v0, $t0, 22 # *output = (window >> (32 - 10)) | quant_scale - or $v0, $t3 - addiu $t7, 1 # coeff_index++ + # The DC coefficient in version 2 frames is not compressed. Value 0x1ff is + # used to signal the end of the bitstream. + srl $v0, $t0, 22 # prefix = (window >> (32 - 10)) + li $v1, 0x01ff + beq $v0, $v1, .Lstop_processing # if (prefix == 0x1ff) break + or $v0, $t3 # *output = prefix | quant_scale sll $t0, 10 # window <<= 10 addiu $t5, -10 # bit_offset -= 10 b .Lwrite_value diff --git a/libpsn00b/psxpress/vlc2.c b/libpsn00b/psxpress/vlc2.c index 73b54b2..9eb99bf 100644 --- a/libpsn00b/psxpress/vlc2.c +++ b/libpsn00b/psxpress/vlc2.c @@ -141,7 +141,10 @@ int __attribute__((optimize(3))) DecDCTvlcContinue2( // TODO: version 3 is currently not supported. return -1; } else { - value = _get_bits_unsigned(10); + value = _get_bits_unsigned(10); + if (value == 0x1ff) + break; + *output = value | quant_scale; _advance_window(10); } diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index 55a3dba..7d90858 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -4,7 +4,7 @@ */ #include <stdint.h> -#include <stdio.h> +#include <psxetc.h> #include <psxspu.h> #include <hwregs_c.h> @@ -17,7 +17,7 @@ static SPU_TransferMode _transfer_mode = SPU_TRANSFER_BY_DMA; static uint16_t _transfer_addr = WRITABLE_AREA_ADDR; -/* SPU initialization */ +/* Private utilities */ static void _wait_status(uint16_t mask, uint16_t value) { for (int i = STATUS_TIMEOUT; i; i--) { @@ -25,9 +25,38 @@ static void _wait_status(uint16_t mask, uint16_t value) { return; } - printf("psxspu: status register timeout (0x%04x)\n", SPU_STAT); + _sdk_log("psxspu: status register timeout (0x%04x)\n", SPU_STAT); } +static void _dma_transfer(uint32_t *data, size_t length, int write) { + if (length % 4) + _sdk_log("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); + + length /= 4; + if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { + _sdk_log("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + length += DMA_CHUNK_LENGTH - 1; + } + + SPU_CTRL &= 0xffcf; // Disable DMA request + _wait_status(0x0030, 0x0000); + + // Enable DMA request for writing (2) or reading (3) + SPU_ADDR = _transfer_addr; + SPU_CTRL |= write ? 0x0020 : 0x0030; + _wait_status(0x0400, 0x0000); + + DMA_MADR(4) = (uint32_t) data; + if (length < DMA_CHUNK_LENGTH) + DMA_BCR(4) = 0x00010000 | length; + else + DMA_BCR(4) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); + + DMA_CHCR(4) = 0x01000200 | write; +} + +/* Public API */ + void SpuInit(void) { SPU_CTRL = 0x0000; // SPU disabled _wait_status(0x001f, 0x0000); @@ -75,41 +104,12 @@ void SpuInit(void) { SPU_KEY_ON = 0x00ffffff; SPU_MASTER_VOL_L = 0x3fff; SPU_MASTER_VOL_R = 0x3fff; - SPU_CD_VOL_L = 0x3fff; - SPU_CD_VOL_R = 0x3fff; -} - -/* SPU RAM transfer API */ - -static void _load_store_data(uint32_t *data, size_t length, int mode) { - if (length % 4) - printf("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); - - length /= 4; - if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); - length += DMA_CHUNK_LENGTH - 1; - } - - SPU_CTRL &= 0xffcf; // Disable DMA request - _wait_status(0x0030, 0x0000); - - // Enable DMA request for writing (2) or reading (3) - SPU_ADDR = _transfer_addr; - SPU_CTRL |= mode << 4; - _wait_status(0x0400, 0x0000); - - DMA_MADR(4) = (uint32_t) data; - if (length < DMA_CHUNK_LENGTH) - DMA_BCR(4) = 0x00010000 | length; - else - DMA_BCR(4) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); - - DMA_CHCR(4) = 0x01000200 | ((mode & 1) ^ 1); + SPU_CD_VOL_L = 0x7fff; + SPU_CD_VOL_R = 0x7fff; } void SpuRead(uint32_t *data, size_t size) { - _load_store_data(data, size, 3); + _dma_transfer(data, size, 0); } void SpuWrite(const uint32_t *data, size_t size) { @@ -132,7 +132,7 @@ void SpuWrite(const uint32_t *data, size_t size) { return; } - _load_store_data((uint32_t *) data, size, 2); + _dma_transfer((uint32_t *) data, size, 1); } SPU_TransferMode SpuSetTransferMode(SPU_TransferMode mode) { |
