aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2022-10-19 17:57:06 +0800
committerGitHub <noreply@github.com>2022-10-19 17:57:06 +0800
commite08a3d9366f8ca14a76b3dd569dac1fb9f569748 (patch)
tree33654513b0b184c27f8035dbc405640fcbeb44ab /libpsn00b
parentc4a2533d21dfd05cde841ea48c67b05e0e6a853f (diff)
parent9b2ffc6078a850b7d354855cca7622090b41f30c (diff)
downloadpsn00bsdk-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')
-rw-r--r--libpsn00b/CMakeLists.txt68
-rw-r--r--libpsn00b/cmake/flags.cmake161
-rw-r--r--libpsn00b/cmake/internal_setup.cmake285
-rw-r--r--libpsn00b/cmake/sdk.cmake23
-rw-r--r--libpsn00b/include/assert.h6
-rw-r--r--libpsn00b/include/psxcd.h12
-rw-r--r--libpsn00b/include/psxetc.h15
-rw-r--r--libpsn00b/include/psxgpu.h22
-rw-r--r--libpsn00b/include/stdlib.h15
-rw-r--r--libpsn00b/libc/abort.c10
-rw-r--r--libpsn00b/libc/malloc.c64
-rw-r--r--libpsn00b/libc/memset.s132
-rw-r--r--libpsn00b/libc/start.c25
-rw-r--r--libpsn00b/psxapi/drivers.s24
-rw-r--r--libpsn00b/psxapi/stubs.json6
-rw-r--r--libpsn00b/psxcd/cdgetsector.s56
-rw-r--r--libpsn00b/psxcd/getsector.c51
-rw-r--r--libpsn00b/psxcd/isofs.c285
-rw-r--r--libpsn00b/psxcd/psxcd.c72
-rw-r--r--libpsn00b/psxcd/psxcd_asm.s38
-rw-r--r--libpsn00b/psxetc/dl.c123
-rw-r--r--libpsn00b/psxetc/interrupts.c62
-rw-r--r--libpsn00b/psxetc/logging.c50
-rw-r--r--libpsn00b/psxgpu/common.c187
-rw-r--r--libpsn00b/psxgpu/dbugfont.pngbin0 -> 1090 bytes
-rw-r--r--libpsn00b/psxgpu/dbugfont.timbin2112 -> 2112 bytes
-rw-r--r--libpsn00b/psxgpu/env.c4
-rw-r--r--libpsn00b/psxgpu/font.c36
-rw-r--r--libpsn00b/psxgpu/image.c57
-rw-r--r--libpsn00b/psxpress/mdec.c17
-rw-r--r--libpsn00b/psxpress/vlc.s10
-rw-r--r--libpsn00b/psxpress/vlc2.c5
-rw-r--r--libpsn00b/psxspu/common.c72
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
new file mode 100644
index 0000000..ed84268
--- /dev/null
+++ b/libpsn00b/psxgpu/dbugfont.png
Binary files differ
diff --git a/libpsn00b/psxgpu/dbugfont.tim b/libpsn00b/psxgpu/dbugfont.tim
index 4e6cce2..1edd4af 100644
--- a/libpsn00b/psxgpu/dbugfont.tim
+++ b/libpsn00b/psxgpu/dbugfont.tim
Binary files differ
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) {