aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2021-11-22 14:40:59 +0800
committerGitHub <noreply@github.com>2021-11-22 14:40:59 +0800
commit45123e1b968d1883fed9b8526157ce2c4bffc4a7 (patch)
treed20c80fbd4f5a5d1d3972669625972cea6b3684d
parent538f28cfbbbb8163ab8a96de77d6887123856c81 (diff)
parent9b00e5f7ff163a8fc6f341dbf237d90c61dadddc (diff)
downloadpsn00bsdk-45123e1b968d1883fed9b8526157ce2c4bffc4a7.tar.gz
Merge pull request #43 from spicyjpeg/cmake
Even more CMake fixes, submodules, pads example
-rw-r--r--.gitmodules7
-rw-r--r--CMakeLists.txt84
-rw-r--r--CMakePresets.json29
-rw-r--r--INSTALL.md116
-rw-r--r--TOOLCHAIN.md5
-rw-r--r--changelog.txt28
-rw-r--r--cpack/fakeroot_fix.cmake2
-rw-r--r--cpack/setup.cmake6
-rw-r--r--doc/dev notes.txt70
-rw-r--r--examples/CMakeLists.txt24
-rw-r--r--examples/beginner/cppdemo/CMakeLists.txt4
-rw-r--r--examples/beginner/cppdemo/main.cpp2
-rw-r--r--examples/beginner/hello/CMakeLists.txt4
-rw-r--r--examples/cdrom/cdbrowse/CMakeLists.txt4
-rw-r--r--examples/cdrom/cdbrowse/main.c1
-rw-r--r--examples/cdrom/cdxa/CMakeLists.txt4
-rw-r--r--examples/cdrom/cdxa/main.c1
-rw-r--r--examples/demos/n00bdemo/CMakeLists.txt4
-rw-r--r--examples/demos/n00bdemo/logo.c1
-rw-r--r--examples/demos/n00bdemo/main.c9
-rw-r--r--examples/graphics/balls/CMakeLists.txt4
-rw-r--r--examples/graphics/billboard/CMakeLists.txt4
-rw-r--r--examples/graphics/fpscam/CMakeLists.txt6
-rw-r--r--examples/graphics/gte/CMakeLists.txt6
-rw-r--r--examples/graphics/hdtv/CMakeLists.txt4
-rw-r--r--examples/graphics/render2tex/CMakeLists.txt4
-rw-r--r--examples/graphics/rgb24/CMakeLists.txt4
-rw-r--r--examples/io/pads/CMakeLists.txt22
-rw-r--r--examples/io/pads/main.c279
-rw-r--r--examples/io/pads/spi.c218
-rw-r--r--examples/io/pads/spi.h61
-rw-r--r--examples/lowlevel/cartrom/CMakeLists.txt36
-rw-r--r--examples/lowlevel/cartrom/makefile14
-rw-r--r--examples/sound/vagsample/CMakeLists.txt4
-rw-r--r--examples/system/childexec/CMakeLists.txt4
-rw-r--r--examples/system/console/CMakeLists.txt4
-rw-r--r--examples/system/dynlink/CMakeLists.txt4
-rw-r--r--examples/system/dynlink/display.c8
-rw-r--r--examples/system/dynlink/library/balls.c2
-rw-r--r--examples/system/dynlink/library/cube.c2
-rw-r--r--examples/system/dynlink/library/dll_common.h1
-rw-r--r--examples/system/dynlink/main.c3
-rw-r--r--examples/system/timer/CMakeLists.txt4
-rw-r--r--examples/system/tty/CMakeLists.txt4
-rw-r--r--indev/README.md4
-rw-r--r--indev/psxmdec/main.c2
-rw-r--r--indev/psxpad/main.c1
-rw-r--r--libpsn00b/CMakeLists.txt2
-rw-r--r--libpsn00b/cmake/internal_setup.cmake8
-rw-r--r--libpsn00b/cmake/sdk.cmake2
-rw-r--r--libpsn00b/cmake/virtual_targets.cmake4
-rw-r--r--libpsn00b/include/malloc.h14
-rw-r--r--libpsn00b/include/psxapi.h32
-rw-r--r--libpsn00b/include/psxpad.h203
-rw-r--r--libpsn00b/include/stdint.h16
-rw-r--r--libpsn00b/include/stdlib.h28
-rw-r--r--libpsn00b/include/sys/types.h16
-rw-r--r--libpsn00b/libc/c++-support.cxx3
-rw-r--r--libpsn00b/libc/start.c42
-rw-r--r--libpsn00b/libc/string.c2
-rw-r--r--libpsn00b/libc/vsprintf.c14
-rw-r--r--libpsn00b/lzp/compress.c1
-rw-r--r--libpsn00b/psxapi/sys/getsysteminfo.s10
-rw-r--r--libpsn00b/psxcd/isofs.c2
-rw-r--r--libpsn00b/psxetc/dl.c4
-rw-r--r--libpsn00b/psxgpu/font.c2
-rw-r--r--template/CMakeLists.txt2
-rw-r--r--tools/CMakeLists.txt46
m---------tools/mkpsxiso0
m---------tools/tinyxml20
-rw-r--r--tools/util/elf2cpe.c2
71 files changed, 1220 insertions, 349 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..734dafd
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,7 @@
+[submodule "tools/tinyxml2"]
+ path = tools/tinyxml2
+ url = https://github.com/leethomason/tinyxml2
+[submodule "tools/mkpsxiso"]
+ path = tools/mkpsxiso
+ url = https://github.com/spicyjpeg/mkpsxiso
+ branch = cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 431e95b..87980a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,13 +6,12 @@
# workaround is to use ExternalProject_Add() to launch multiple independent
# CMake instances, creating what's known as a "superbuild".
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
include(ExternalProject)
project(
PSn00bSDK
LANGUAGES NONE
- # IMPORTANT TODO: set a version number
VERSION 0.1.0
DESCRIPTION "Open source PlayStation 1 SDK"
HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
@@ -36,14 +35,6 @@ set(
)
set(
- SKIP_TINYXML2 OFF
- CACHE BOOL "Skip downloading and building tinyxml2 (if already installed)"
-)
-set(
- SKIP_MKPSXISO OFF
- CACHE BOOL "Skip downloading and building mkpsxiso (if already installed)"
-)
-set(
SKIP_EXAMPLES OFF
CACHE BOOL "Skip building SDK examples (not required for installation)"
)
@@ -61,12 +52,6 @@ set(
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
)
set(
- EXT_LIBRARY_ARGS
- -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}
- -DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/install_temp
- -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=MultiThreaded$<$<CONFIG:Debug>:Debug>
-)
-set(
SUBPROJECT_ARGS
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/install_tree
@@ -77,50 +62,30 @@ set(
-DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/examples
)
-## External dependencies
-
-if(NOT SKIP_TINYXML2)
- list(APPEND SUBPROJECT_ARGS -Dtinyxml2_ROOT:PATH=${PROJECT_BINARY_DIR}/install_temp)
-
- ExternalProject_Add(
- tinyxml2
- GIT_REPOSITORY "https://github.com/leethomason/tinyxml2"
- CMAKE_CACHE_ARGS ${COMMON_ARGS} ${EXT_LIBRARY_ARGS}
- INSTALL_DIR install_temp
- )
-else()
- list(APPEND SUBPROJECT_ARGS -Dtinyxml2_ROOT:PATH=${tinyxml2_ROOT})
-
- # Create a dummy target so CMake doesn't throw missing dependency errors.
- add_library(tinyxml2 INTERFACE)
-endif()
+## Subprojects
-if(NOT SKIP_MKPSXISO)
- ExternalProject_Add(
- mkpsxiso
- GIT_REPOSITORY "https://github.com/Lameguy64/mkpsxiso"
- CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
- INSTALL_DIR install_tree
- DEPENDS tinyxml2
- )
-else()
- add_library(mkpsxiso INTERFACE)
+if(NOT EXISTS ${PROJECT_SOURCE_DIR}/tools/mkpsxiso/CMakeLists.txt)
+ message(FATAL_ERROR "The mkpsxiso directory is empty. Run 'git submodule update --init --recursive' to populate it.")
endif()
-## Subprojects
-
ExternalProject_Add(
- libpsn00b
- SOURCE_DIR ${PROJECT_SOURCE_DIR}/libpsn00b
+ tools
+ SOURCE_DIR ${PROJECT_SOURCE_DIR}/tools
CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
INSTALL_DIR install_tree
)
ExternalProject_Add(
- tools
- SOURCE_DIR ${PROJECT_SOURCE_DIR}/tools
+ mkpsxiso
+ SOURCE_DIR ${PROJECT_SOURCE_DIR}/tools/mkpsxiso
CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
INSTALL_DIR install_tree
- DEPENDS tinyxml2
+)
+ExternalProject_Add(
+ libpsn00b
+ SOURCE_DIR ${PROJECT_SOURCE_DIR}/libpsn00b
+ CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
+ INSTALL_DIR install_tree
+ #DEPENDS tools
)
ExternalProject_Add(
examples
@@ -133,12 +98,21 @@ ExternalProject_Add(
# Install all files in the temporary installation tree, as well as static files
# from the source tree, when "cmake --install" is invoked.
-install(
- DIRECTORY ${PROJECT_BINARY_DIR}/install_tree/ # THE TRAILING SLASH IS IMPORTANT
- DESTINATION .
- COMPONENT sdk
- USE_SOURCE_PERMISSIONS
+foreach(
+ _subdir IN ITEMS
+ ${CMAKE_INSTALL_BINDIR}
+ ${CMAKE_INSTALL_LIBDIR}
+ ${CMAKE_INSTALL_DATADIR}
)
+ install(
+ # THE TRAILING SLASH IS IMPORTANT
+ DIRECTORY ${PROJECT_BINARY_DIR}/install_tree/${_subdir}/
+ DESTINATION ${_subdir}
+ COMPONENT sdk
+ USE_SOURCE_PERMISSIONS
+ )
+endforeach()
+
install(
DIRECTORY doc template
DESTINATION ${CMAKE_INSTALL_DATADIR}/psn00bsdk
diff --git a/CMakePresets.json b/CMakePresets.json
new file mode 100644
index 0000000..f550e82
--- /dev/null
+++ b/CMakePresets.json
@@ -0,0 +1,29 @@
+{
+ "version": 2,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 20,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "default",
+ "displayName": "Default configuration",
+ "description": "Use this preset when building the SDK for local installation.",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "package",
+ "displayName": "Installer package",
+ "description": "Use this preset to build installer packages via CPack.",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Release",
+ "SKIP_EXAMPLES": "ON",
+ "BUNDLE_TOOLCHAIN": "ON"
+ }
+ }
+ ]
+}
diff --git a/INSTALL.md b/INSTALL.md
index 6fac934..5ae56f5 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -4,35 +4,53 @@
## Building and installing
The instructions below are for Windows and Linux. Building on macOS hasn't been
-tested but should work.
+tested extensively yet, however it should work once the GCC toolchain is built
+and installed properly.
-1. Set up a host compiler. Most Linux distros provide a `build-essential`,
- `base-devel` or similar all-in-one package. You'll also need to install the
- [Ninja](https://ninja-build.org) build engine (it's usually in a package
- called `ninja-build`). On Windows install [MSys2](https://www.msys2.org),
- then run the following command in the MSys2 shell to install MinGW and Ninja:
+1. Install prerequisites and a host compiler toolchain. On Linux (most distros)
+ install the following packages from your distro's package manager:
+
+ - `git`
+ - `build-essential`, `base-devel` or similar
+ - `make` or `ninja-build`
+ - `cmake` (3.20+ is required, download it from
+ [here](https://cmake.org/download) if your package manager only provides
+ older versions)
+
+ On Windows install [MSys2](https://www.msys2.org), then open the "MSys2
+ MSYS" shell and run this command:
```bash
- pacman -Syu mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja
+ pacman -Syu git mingw-w64-x86_64-make mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc
```
- Add `C:\msys64\mingw64\bin` (replace `C:\msys64` if you installed MSys2 to a
+ If you are prompted to close the shell, you may have to reopen it afterwards
+ and rerun the command to finish installation.
+ **Do not use the MSys2 shell for the next steps**, use a regular command
+ prompt or PowerShell instead.
+
+ Add these directories (replace `C:\msys64` if you installed MSys2 to a
different location) to the `PATH` environment variable using System
- Properties.
+ Properties:
-2. Install Git and CMake. Note that MSys2 and some Linux distros ship relatively
- old versions (PSn00bSDK requires 3.21+), so grab the latest CMake release
- from [here](https://cmake.org) instead of through your package manager.
+ - `C:\msys64\mingw64\bin`
+ - `C:\msys64\usr\bin`
-3. Build and install a GCC toolchain for `mipsel-unknown-elf`, as detailed in
+2. Build and install a GCC toolchain for `mipsel-unknown-elf`, as detailed in
[TOOLCHAIN.md](TOOLCHAIN.md). On Windows, you may download a precompiled
version from [Lameguy64's website](http://lameguy64.net?page=psn00bsdk) and
extract it into one of the directories listed below instead.
-4. If you chose a non-standard install location for the toolchain, add the `bin`
- subfolder (inside the top-level toolchain directory) to the `PATH`
- environment variable. This step is unnecessary if you installed/extracted the
- toolchain into any of these directories:
+ **NOTE**: PSn00bSDK is also compatible with toolchains that target
+ `mipsel-none-elf`. If you already have such a toolchain (e.g. because you
+ have another PS1 SDK installed) you can skip this step. Make sure you pass
+ `-DPSN00BSDK_TARGET=mipsel-none-elf` to CMake when configuring the SDK
+ though (see step 5).
+
+3. If you chose a non-standard install location for the toolchain, add the
+ `bin` subfolder (inside the top-level toolchain directory) to the `PATH`
+ environment variable. This step is unnecessary if you installed/extracted
+ the toolchain into any of these directories:
- `C:\Program Files\mipsel-unknown-elf`
- `C:\Program Files (x86)\mipsel-unknown-elf`
@@ -41,25 +59,33 @@ tested but should work.
- `/usr/mipsel-unknown-elf`
- `/opt/mipsel-unknown-elf`
-5. Clone/download the PSn00bSDK repo and run the following commands from its
- directory:
+4. Clone the PSn00bSDK repo, then run the following command from the PSn00bSDK
+ repository to download additional dependencies:
```bash
- cmake -S . -B ./build -G Ninja
+ git submodule update --init --recursive --remote
+ ```
+
+5. Compile the libraries, tools and examples using CMake:
+
+ ```bash
+ cmake --preset default .
cmake --build ./build
```
If you want to install the SDK to a custom location rather than the default
one (`C:\Program Files\PSn00bSDK` or `/usr/local` depending on your OS), add
- `--install-prefix <INSTALL_PATH>` to the first command. Remove `-G Ninja` to
- use `make` instead of Ninja (slower, not recommended).
+ `--install-prefix <INSTALL_PATH>` to the first command. Add
+ `-DPSN00BSDK_TARGET=mipsel-none-elf` if your toolchain targets
+ `mipsel-none-elf` rather than `mipsel-unknown-elf`.
- If you run into errors, try passing `-DSKIP_TINYXML2=ON` to the first command
- after installing `tinyxml2` manually. [See below](#advanced-build-options)
- for more details.
+ **NOTE**: Ninja is used by default to build the SDK. If you can't get it to
+ work or don't have it installed, pass `-G "Unix Makefiles"` (or
+ `-G "MSYS Makefiles"` on Windows) to the first command to build using `make`
+ instead.
-6. Install the SDK to the path you chose by running this command (add `sudo` if
- necessary):
+6. Install the SDK to the path you chose (add `sudo` or run it from a command
+ prompt with admin privileges if necessary):
```bash
cmake --install ./build
@@ -81,23 +107,7 @@ with debugging capabilities such as [no$psx](https://problemkaputt.de/psx.htm)
[pcsx-redux](https://github.com/grumpycoders/pcsx-redux).
**Avoid ePSXe and anything based on MAME** as they are inaccurate.
-## Advanced build options
-
-### Skipping external dependency downloads
-
-By default [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) (required for
-building CD images) and [tinyxml2](https://github.com/leethomason/tinyxml2)
-(required to build mkpsxiso and other SDK tools) are automatically cloned from
-their respective repos and built as part of the PSn00bSDK build process,
-*even if they are already installed*.
-
-If you wish to disable this behavior (e.g. because it leads to errors, or to
-perform an offline build), invoke CMake with the `-DSKIP_MKPSXISO=ON` and/or
-`-DSKIP_TINYXML2=ON` options when configuring the SDK. Note that you must have
-`mkpsxiso` and/or `tinyxml2` already installed (either manually or via vcpkg or
-your distro's package manager) to be able to skip them.
-
-### Building installer packages
+## Building installer packages
CPack can be used to build NSIS-based installers, DEB/RPM packages and zipped
releases that include built SDK libraries, headers as well as the GCC toolchain.
@@ -108,27 +118,25 @@ far from being feature-complete.
[NSIS](https://nsis.sourceforge.io/Download) on Windows or `dpkg` and `rpm`
on Linux.
-2. Run the following commands from the PSn00bSDK directory:
+2. Run the following commands from the PSn00bSDK directory (pass the
+ appropriate options to the first command if necessary):
```bash
- cmake -S . -B ./build -G Ninja -DBUNDLE_TOOLCHAIN=ON
+ cmake --preset package .
cmake --build ./build -t package
```
All built packages will be copied to the `build/packages` folder.
- **NOTE**: do not use `-DSKIP_MKPSXISO=ON`, otherwise the mkpsxiso binary will
- not be included in the packages.
-
## Creating a project
-1. Copy the contents of `INSTALL_PATH/share/psn00bsdk/template` (or the
+1. Copy the contents of `<INSTALL_PATH>/share/psn00bsdk/template` (or the
`template` folder within the repo) to your new project's root directory.
2. Configure and build the template by running:
```bash
- cmake -S . -B ./build -G Ninja
+ cmake -S . -B ./build
cmake --build ./build
```
@@ -138,11 +146,11 @@ far from being feature-complete.
Note that, even though the template relies on the `PSN00BSDK_LIBS` environment
variable to locate the SDK by default, you can also specify the path directly
on the CMake command line by adding
-`-DCMAKE_TOOLCHAIN_FILE=INSTALL_PATH/lib/libpsn00b/cmake/sdk.cmake` (replace
-`INSTALL_PATH`) to the first command.
+`-DCMAKE_TOOLCHAIN_FILE=<INSTALL_PATH>/lib/libpsn00b/cmake/sdk.cmake` to the
+CMake command line.
The toolchain script defines a few CMake macros to create PS1 executables, DLLs
and CD images. See the [reference](doc/cmake_reference.md) for details.
-----------------------------------------
-_Last updated on 2021-10-18 by spicyjpeg_
+_Last updated on 2021-11-19 by spicyjpeg_
diff --git a/TOOLCHAIN.md b/TOOLCHAIN.md
index 8ecee38..2a78ccb 100644
--- a/TOOLCHAIN.md
+++ b/TOOLCHAIN.md
@@ -25,7 +25,8 @@ the latest stable release of GCC and binutils. If for some reason you are having
problems you may try building one of the following versions, which have been
tested extensively:
-- GCC **7.4.0** with binutils **2.31**
+- ~~GCC 7.4.0 with binutils 2.31~~ (the linker fails to build PS1 DLLs)
+- GCC **11.1.0** with binutils **2.36**
- GCC **11.2.0** with binutils **2.37**
If you wish to pick an older GCC release but don't know which binutils version
@@ -220,4 +221,4 @@ implemented due to bloat concerns that it may introduce. Besides, the official
SDK lacks full C++ support as well.
-----------------------------------------
-_Last updated on 2021-10-18 by spicyjpeg_
+_Last updated on 2021-10-31 by spicyjpeg_
diff --git a/changelog.txt b/changelog.txt
index a7861b9..3efa7a0 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -2,6 +2,34 @@ PSn00bSDK changelog
Items that are lower in the log are more recently implemented.
+11-19-2021 by spicyjpeg:
+
+* libc: Removed STACK_MAX_SIZE and added _mem_init() back. RAM and stack size
+ can now be set by calling _mem_init() manually before allocating any memory.
+
+* libc: sprintf() now supports fixed padding when using %@ (binary integer).
+
+* psxapi: Added wrapper around BIOS function GetSystemInfo().
+
+* examples: Added pads example. Also added CMake build script to cartrom, which
+ is now built alongside all other examples.
+
+* Deprecated malloc.h and removed all references to it (stdlib.h should be used
+ instead). Moved int*_t and uint*_t types to stdint.h.
+
+* Fixed file permission errors when attempting to install the SDK on macOS.
+ Made some small updates to INSTALL.md.
+
+
+10-31-2021 by spicyjpeg:
+
+* Added tinyxml2 and mkpsxiso as git submodules and removed the (admittedly
+ short-lived) SKIP_* options completely. CMake's ExternalProject is no longer
+ used to download dependencies at build time.
+
+* Added CMake presets file with presets for building installer packages.
+
+
10-25-2021 by Lameguy64:
* Made a very tiny change in the readme file.
diff --git a/cpack/fakeroot_fix.cmake b/cpack/fakeroot_fix.cmake
index e34baa0..1c1430d 100644
--- a/cpack/fakeroot_fix.cmake
+++ b/cpack/fakeroot_fix.cmake
@@ -7,7 +7,7 @@
# script does is simply finding and deleting all directories that do not match
# the installation prefix before CPack generates the package.
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
set(_prefix ${CPACK_TEMPORARY_INSTALL_DIRECTORY}${CPACK_PACKAGING_INSTALL_PREFIX})
diff --git a/cpack/setup.cmake b/cpack/setup.cmake
index a483462..33f127e 100644
--- a/cpack/setup.cmake
+++ b/cpack/setup.cmake
@@ -2,7 +2,7 @@
# rules to bundle the GCC toolchain and CMake in packages. It is included by
# the main CMakeLists.txt script.
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
## Settings
@@ -111,11 +111,11 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY PSn00bSDK)
## DEB/RPM variables
-set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), cmake (>= 3.21)")
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), cmake (>= 3.20)")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "ninja-build (>= 1.10)")
set(CPACK_DEBIAN_PACKAGE_SUGGESTS "git (>= 2.25)")
set(CPACK_DEBIAN_PACKAGE_SECTION devel)
-set(CPACK_RPM_PACKAGE_REQUIRES "cmake >= 3.21")
+set(CPACK_RPM_PACKAGE_REQUIRES "cmake >= 3.20")
set(CPACK_RPM_PACKAGE_SUGGESTS "ninja-build >= 1.10, git >= 2.25")
#set(CPACK_RPM_PACKAGE_RELOCATABLE ON)
diff --git a/doc/dev notes.txt b/doc/dev notes.txt
index 1bc9ccd..3aa2db5 100644
--- a/doc/dev notes.txt
+++ b/doc/dev notes.txt
@@ -53,6 +53,44 @@ IRQs are only triggered on transfer completion.
Additional notes by spicyjpeg:
+* The controller/memory card SPI interface is poorly implemented in most
+emulators, making custom controller polling code insanely hard to write and
+debug. The only emulator that comes close to real hardware is no$psx, which
+seems to correctly implement all features of the SPI port (even those not used
+by the BIOS pad driver, such as TX/RX interrupts). DuckStation only emulates
+the bare minimum required by the BIOS and Sony libraries, and pcsx-redux has
+major bugs that break most custom polling implementations. This pretty much
+means TX/RX IRQs and many flags in the JOY_* registers should not be used
+unless you are willing to break compatibility with emulators.
+
+* As if communicating with controllers wasn't difficult enough already,
+DualShock pads also have a built-in watchdog timer that gets enabled when first
+putting them in configuration mode (and is NOT disabled after exiting config
+mode). If no polling commands are sent to the controller for about 1 second,
+vibration motors are switched off and analog mode is disabled; the same happens
+if the analog button is pressed while in analog mode. In order to always keep
+the pad in analog mode you must:
+
+ * Poll both controller ports at least once per frame by sending command 42h.
+ Polling at a higher rate might be desirable in some cases (such as rhythm
+ games) to increase timing accuracy.
+ * If a digital pad response (type = 4) is received from a port that hasn't
+ previously been flagged as digital-only, attempt to put the pad into config
+ mode using command 43h *twice* (as the proper response is delayed).
+ * If the pad doesn't recognize the config command, flag it as digital-only
+ and treat all further digital pad responses from it as valid.
+ * If the pad recognizes the command, it will reply by identifying as an
+ analog pad in config mode (type = 15). Send command 44h immediately
+ (without sending 42h first, otherwise the pad will exit config mode) to
+ enable analog mode and turn on the LED.
+ * Pressing the analog button will result in the controller identifying as
+ digital even though it is not flagged as such, thus re-triggering the
+ configuration process and putting it back into analog mode.
+ * All analog pad responses (type = 7) can be treated as valid, as they will
+ come from controllers that have already been configured.
+ * If no valid response is received, assume no controller is connected and
+ reset the port's digital-only flag.
+
* The SDK provides no support yet for replacing the BIOS exception handler with
a custom one, however it can be done (if you are ok with losing all BIOS
controller, memory card and file functionality). In order not to break anything
@@ -128,6 +166,38 @@ cache or something like that (?). The only workaround I know of is to use
CPACK_PRE_BUILD_SCRIPTS to trigger a custom script that deletes anything other
than the actual files to be packaged (see cpack/fakeroot_fix.cmake).
+* Project installation might fail on macOS (and possibly some Linux distros) if
+CMake attempts to set permissions on system directories such as /usr/local.
+This is usually caused by install() commands that copy files to the root
+installation directory rather than to a subfolder, like this:
+
+ install(
+ DIRECTORY install_tree/
+ DESTINATION .
+ USE_SOURCE_PERMISSIONS
+ )
+
+If the USE_SOURCE_PERMISSIONS flag is specified CMake will attempt to set
+permissions on the DESTINATION folder, which in this case would be the root
+prefix (/usr/local by default on macOS), to match the source directory. This
+will however fail as macOS restricts top-level system directories from having
+their permissions changed. The simplest workaround is to avoid using
+"DESTINATION ." and install each subdirectory explicitly instead, like this:
+
+ foreach(
+ _dir IN ITEMS
+ ${CMAKE_INSTALL_BINDIR}
+ ${CMAKE_INSTALL_LIBDIR}
+ ${CMAKE_INSTALL_INCLUDEDIR}
+ ${CMAKE_INSTALL_DATADIR}
+ )
+ install(
+ DIRECTORY install_tree/${_dir}/
+ DESTINATION ${_dir}
+ USE_SOURCE_PERMISSIONS
+ )
+ endforeach()
+
* Depending on how you find external dependencies (find_package(), vcpkg,
pkg-config...), CMake may end up outputting an executable that relies on a DLL
installed system-wide. To correctly install the DLL alongside the executable
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 7cd7e98..15212c8 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK examples build script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
project(
PSn00bSDK-examples
@@ -10,16 +10,32 @@ project(
HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
)
+include(GNUInstallDirs)
+
+# Find all subdirectories that contain a CMake build script. This includes the
+# top-level examples directory and this file as well, however we're going to
+# skip it.
file(
GLOB_RECURSE _examples
+ RELATIVE ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/CMakeLists.txt
)
foreach(_script IN LISTS _examples)
- cmake_path(GET _script PARENT_PATH _dir)
- if(_dir STREQUAL PROJECT_SOURCE_DIR)
+ if(_script STREQUAL "CMakeLists.txt")
continue()
endif()
- add_subdirectory(${_dir})
+ # CMake provides no way to override the install prefix of a subdirectory,
+ # as it "imports" its targets into the main project rather than treating it
+ # as a separate project. However, as the example subdirectories use
+ # install(... TYPE BIN) to install executables, it is possible to override
+ # CMAKE_INSTALL_BINDIR temporarily to place them in any directory within
+ # the install prefix. This is a hack, but it allows us to preserve the
+ # examples' folder hierarchy in the installation directory (it is already
+ # preserved by CMake in the build tree!) with minimal effort.
+ cmake_path(GET _script PARENT_PATH _dir)
+ cmake_path(GET _dir PARENT_PATH CMAKE_INSTALL_BINDIR)
+
+ add_subdirectory(${PROJECT_SOURCE_DIR}/${_dir})
endforeach()
diff --git a/examples/beginner/cppdemo/CMakeLists.txt b/examples/beginner/cppdemo/CMakeLists.txt
index 83f0f0a..becf464 100644
--- a/examples/beginner/cppdemo/CMakeLists.txt
+++ b/examples/beginner/cppdemo/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.cpp)
psn00bsdk_add_executable(cppdemo STATIC ${_sources})
#psn00bsdk_add_cd_image(cppdemo_iso cppdemo iso.xml DEPENDS cppdemo)
-install(FILES ${PROJECT_BINARY_DIR}/cppdemo.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/cppdemo.exe TYPE BIN)
diff --git a/examples/beginner/cppdemo/main.cpp b/examples/beginner/cppdemo/main.cpp
index 58bfcda..fd2e3a8 100644
--- a/examples/beginner/cppdemo/main.cpp
+++ b/examples/beginner/cppdemo/main.cpp
@@ -13,7 +13,7 @@
#include <sys/types.h>
#include <stdio.h>
-#include <malloc.h>
+#include <stdlib.h>
#include <psxgte.h>
#include <psxgpu.h>
diff --git a/examples/beginner/hello/CMakeLists.txt b/examples/beginner/hello/CMakeLists.txt
index 40e30b0..7fb7c22 100644
--- a/examples/beginner/hello/CMakeLists.txt
+++ b/examples/beginner/hello/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(hello STATIC ${_sources})
#psn00bsdk_add_cd_image(hello_iso hello iso.xml DEPENDS hello)
-install(FILES ${PROJECT_BINARY_DIR}/hello.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/hello.exe TYPE BIN)
diff --git a/examples/cdrom/cdbrowse/CMakeLists.txt b/examples/cdrom/cdbrowse/CMakeLists.txt
index 6eb4cbb..e5ec759 100644
--- a/examples/cdrom/cdbrowse/CMakeLists.txt
+++ b/examples/cdrom/cdbrowse/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -23,5 +23,5 @@ install(
FILES
${PROJECT_BINARY_DIR}/cdbrowse.bin
${PROJECT_BINARY_DIR}/cdbrowse.cue
- DESTINATION .
+ TYPE BIN
)
diff --git a/examples/cdrom/cdbrowse/main.c b/examples/cdrom/cdbrowse/main.c
index ead2df0..9a1dbd0 100644
--- a/examples/cdrom/cdbrowse/main.c
+++ b/examples/cdrom/cdbrowse/main.c
@@ -67,7 +67,6 @@
#include <psxspu.h>
#include <psxcd.h>
-#include <malloc.h>
#include "ball16c.h"
diff --git a/examples/cdrom/cdxa/CMakeLists.txt b/examples/cdrom/cdxa/CMakeLists.txt
index b0c8d90..18dcc69 100644
--- a/examples/cdrom/cdxa/CMakeLists.txt
+++ b/examples/cdrom/cdxa/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -25,5 +25,5 @@ install(
#${PROJECT_BINARY_DIR}/cdxa.bin
#${PROJECT_BINARY_DIR}/cdxa.cue
${PROJECT_BINARY_DIR}/cdxa.exe
- DESTINATION .
+ TYPE BIN
)
diff --git a/examples/cdrom/cdxa/main.c b/examples/cdrom/cdxa/main.c
index 16f1c82..5f11d8d 100644
--- a/examples/cdrom/cdxa/main.c
+++ b/examples/cdrom/cdxa/main.c
@@ -129,7 +129,6 @@
#include <psxspu.h>
#include <psxcd.h>
-#include <malloc.h>
#include "ball16c.h"
diff --git a/examples/demos/n00bdemo/CMakeLists.txt b/examples/demos/n00bdemo/CMakeLists.txt
index 0b51beb..c62c4ef 100644
--- a/examples/demos/n00bdemo/CMakeLists.txt
+++ b/examples/demos/n00bdemo/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -47,4 +47,4 @@ target_include_directories(n00bdemo PRIVATE ${PROJECT_SOURCE_DIR})
add_custom_target(n00bdemo_data DEPENDS data.lzp)
add_dependencies(n00bdemo n00bdemo_data)
-install(FILES ${PROJECT_BINARY_DIR}/n00bdemo.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/n00bdemo.exe TYPE BIN)
diff --git a/examples/demos/n00bdemo/logo.c b/examples/demos/n00bdemo/logo.c
index d10b5b4..40160e7 100644
--- a/examples/demos/n00bdemo/logo.c
+++ b/examples/demos/n00bdemo/logo.c
@@ -5,7 +5,6 @@
#include <psxgte.h>
#include <psxgpu.h>
#include <inline_c.h>
-#include "malloc.h"
#include "smd.h"
#include <lzp/lzp.h>
diff --git a/examples/demos/n00bdemo/main.c b/examples/demos/n00bdemo/main.c
index ba21d88..d2fe317 100644
--- a/examples/demos/n00bdemo/main.c
+++ b/examples/demos/n00bdemo/main.c
@@ -32,7 +32,6 @@
#include <lzp/lzp.h>
#include <lzp/lzqlp.h>
-#include "malloc.h"
#include "smd.h"
#include "data.h"
#include "disp.h"
@@ -617,7 +616,13 @@ void transition() {
if( comp >= 16 )
break;
-
+
+ // FIXME: for some reason this loop glitches out and hangs indefinitely
+ // in no$psx, *unless* there's a function somewhere that gets called
+ // with a pointer/string as first argument... wtf. It works fine in
+ // other emulators. If you are reading this, please help and enlighten
+ // me. -- spicyjpeg
+ puts(".");
}
DrawSync(0);
diff --git a/examples/graphics/balls/CMakeLists.txt b/examples/graphics/balls/CMakeLists.txt
index b063425..5886484 100644
--- a/examples/graphics/balls/CMakeLists.txt
+++ b/examples/graphics/balls/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(balls STATIC ${_sources})
#psn00bsdk_add_cd_image(balls_iso balls iso.xml DEPENDS balls)
-install(FILES ${PROJECT_BINARY_DIR}/balls.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/balls.exe TYPE BIN)
diff --git a/examples/graphics/billboard/CMakeLists.txt b/examples/graphics/billboard/CMakeLists.txt
index bf73297..8cd31a9 100644
--- a/examples/graphics/billboard/CMakeLists.txt
+++ b/examples/graphics/billboard/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -25,4 +25,4 @@ psn00bsdk_add_executable(
)
#psn00bsdk_add_cd_image(billboard_iso billboard iso.xml DEPENDS billboard)
-install(FILES ${PROJECT_BINARY_DIR}/billboard.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/billboard.exe TYPE BIN)
diff --git a/examples/graphics/fpscam/CMakeLists.txt b/examples/graphics/fpscam/CMakeLists.txt
index 8fa66f2..791f6c2 100644
--- a/examples/graphics/fpscam/CMakeLists.txt
+++ b/examples/graphics/fpscam/CMakeLists.txt
@@ -1,14 +1,14 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
endif()
project(
- hello
+ fpscam
LANGUAGES C
VERSION 1.0.0
DESCRIPTION "PSn00bSDK 3D camera controls example"
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(fpscam STATIC ${_sources})
#psn00bsdk_add_cd_image(fpscam_iso fpscam iso.xml DEPENDS fpscam)
-install(FILES ${PROJECT_BINARY_DIR}/fpscam.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/fpscam.exe TYPE BIN)
diff --git a/examples/graphics/gte/CMakeLists.txt b/examples/graphics/gte/CMakeLists.txt
index 3cdf2ff..85b2942 100644
--- a/examples/graphics/gte/CMakeLists.txt
+++ b/examples/graphics/gte/CMakeLists.txt
@@ -1,14 +1,14 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
endif()
project(
- hello
+ gte
LANGUAGES C
VERSION 1.0.0
DESCRIPTION "PSn00bSDK GTE 3D cube example"
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(gte STATIC ${_sources})
#psn00bsdk_add_cd_image(gte_iso gte iso.xml DEPENDS gte)
-install(FILES ${PROJECT_BINARY_DIR}/gte.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/gte.exe TYPE BIN)
diff --git a/examples/graphics/hdtv/CMakeLists.txt b/examples/graphics/hdtv/CMakeLists.txt
index 98a0b3f..f92faeb 100644
--- a/examples/graphics/hdtv/CMakeLists.txt
+++ b/examples/graphics/hdtv/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(hdtv STATIC ${_sources})
#psn00bsdk_add_cd_image(hdtv_iso hdtv iso.xml DEPENDS hdtv)
-install(FILES ${PROJECT_BINARY_DIR}/hdtv.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/hdtv.exe TYPE BIN)
diff --git a/examples/graphics/render2tex/CMakeLists.txt b/examples/graphics/render2tex/CMakeLists.txt
index 42a063b..360840d 100644
--- a/examples/graphics/render2tex/CMakeLists.txt
+++ b/examples/graphics/render2tex/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -25,4 +25,4 @@ psn00bsdk_add_executable(
)
#psn00bsdk_add_cd_image(render2tex_iso render2tex iso.xml DEPENDS render2tex)
-install(FILES ${PROJECT_BINARY_DIR}/render2tex.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/render2tex.exe TYPE BIN)
diff --git a/examples/graphics/rgb24/CMakeLists.txt b/examples/graphics/rgb24/CMakeLists.txt
index c66ae69..bf8a8fa 100644
--- a/examples/graphics/rgb24/CMakeLists.txt
+++ b/examples/graphics/rgb24/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -25,4 +25,4 @@ psn00bsdk_add_executable(
)
#psn00bsdk_add_cd_image(rgb24_iso rgb24 iso.xml DEPENDS rgb24)
-install(FILES ${PROJECT_BINARY_DIR}/rgb24.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/rgb24.exe TYPE BIN)
diff --git a/examples/io/pads/CMakeLists.txt b/examples/io/pads/CMakeLists.txt
new file mode 100644
index 0000000..5bd7f5d
--- /dev/null
+++ b/examples/io/pads/CMakeLists.txt
@@ -0,0 +1,22 @@
+# PSn00bSDK example CMake script
+# (C) 2021 spicyjpeg - MPL licensed
+
+cmake_minimum_required(VERSION 3.20)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
+ set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
+endif()
+
+project(
+ pads
+ LANGUAGES C ASM
+ VERSION 1.0.0
+ DESCRIPTION "PSn00bSDK controller polling example"
+ HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
+)
+
+file(GLOB _sources *.c *.s)
+psn00bsdk_add_executable(pads STATIC ${_sources})
+#psn00bsdk_add_cd_image(pads_iso pads iso.xml DEPENDS pads)
+
+install(FILES ${PROJECT_BINARY_DIR}/pads.exe TYPE BIN)
diff --git a/examples/io/pads/main.c b/examples/io/pads/main.c
new file mode 100644
index 0000000..92beb1c
--- /dev/null
+++ b/examples/io/pads/main.c
@@ -0,0 +1,279 @@
+/*
+ * PSn00bSDK controller polling example
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * This example shows how to poll controllers at high speeds (250 Hz) by using
+ * timer interrupts and communicating with devices on the SPI controller bus
+ * manually rather than relying on the BIOS pad driver, which is limited to
+ * 50/60 Hz and does not support custom commands. The example also demonstrates
+ * using configuration mode commands to force DualShock pads into analog mode
+ * and enable button pressure sensing on DualShock 2 (PS2) controllers.
+ *
+ * See spi.c for details on how the low-level SPI communication driver works.
+ * The DualShock handshaking logic is implemented here (see poll_cb() and
+ * dualshock_init_cb()). There is no support for memory cards in this example,
+ * but the code in spi.c can be used to read/write sectors on a memory card and
+ * combined with a higher-level filesystem driver for full support.
+ *
+ * IMPORTANT: this example hasn't yet been tested on real hardware and/or with
+ * unofficial controllers, which might behave differently at higher poll rates.
+ * Also keep in mind that many emulators emulate controllers and memory cards
+ * inaccurately. It is thus recommended to test controller I/O code extensively
+ * and handle as many edge cases as possible (e.g. partial but valid responses,
+ * zerofilled responses, slow replies) for maximum compatibility.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <psxetc.h>
+#include <psxgpu.h>
+#include <psxpad.h>
+
+#include "spi.h"
+
+static const char *const PAD_TYPEIDS[] = {
+ "[UNKNOWN]",
+ "MOUSE",
+ "NEGCON",
+ "IRQ10_GUN",
+ "DIGITAL",
+ "ANALOG_STICK",
+ "GUNCON",
+ "ANALOG",
+ "MULTITAP",
+ "[UNKNOWN]",
+ "[UNKNOWN]",
+ "[UNKNOWN]",
+ "[UNKNOWN]",
+ "[UNKNOWN]",
+ "JOGCON",
+ "CONFIG_MODE"
+};
+
+/* Display/GPU context utilities */
+
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+#define BGCOLOR_R 48
+#define BGCOLOR_G 24
+#define BGCOLOR_B 0
+
+typedef struct {
+ DISPENV disp;
+ DRAWENV draw;
+} DB;
+
+typedef struct {
+ DB db[2];
+ uint32_t db_active;
+} CONTEXT;
+
+void init_context(CONTEXT *ctx) {
+ DB *db;
+
+ ResetGraph(0);
+ ctx->db_active = 0;
+
+ db = &(ctx->db[0]);
+ SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES);
+ SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES);
+ setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B);
+ db->draw.isbg = 1;
+ db->draw.dtd = 1;
+
+ db = &(ctx->db[1]);
+ SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES);
+ SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES);
+ setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B);
+ db->draw.isbg = 1;
+ db->draw.dtd = 1;
+
+ PutDrawEnv(&(db->draw));
+ //PutDispEnv(&(db->disp));
+
+ // Create a text stream at the top of the screen.
+ FntLoad(960, 0);
+ FntOpen(8, 16, 304, 208, 2, 512);
+}
+
+void display(CONTEXT *ctx) {
+ DB *db;
+
+ DrawSync(0);
+ VSync(0);
+ ctx->db_active ^= 1;
+
+ db = &(ctx->db[ctx->db_active]);
+ PutDrawEnv(&(db->draw));
+ PutDispEnv(&(db->disp));
+ SetDispMask(1);
+}
+
+/* Pad buffers and callback */
+
+static volatile uint8_t pad_buff[2][34];
+static volatile size_t pad_buff_len[2];
+static volatile uint32_t pad_digital_only[2] = { 0, 0 };
+
+// Just a wrapper around spi_new_request(). This does not send the command
+// immediately but adds it to the driver's request queue.
+void send_pad_cmd(
+ uint32_t port,
+ PAD_COMMAND cmd,
+ uint8_t arg1,
+ uint8_t arg2,
+ SPICALLBACK callback
+) {
+ SPIREQUEST *req = spi_new_request();
+
+ req->len = 9;
+ req->port = port;
+ req->callback = callback;
+ req->pad_req.addr = 0x01;
+ req->pad_req.cmd = cmd;
+ req->pad_req.tap_mode = 0x00;
+ req->pad_req.motor_r = arg1;
+ req->pad_req.motor_l = arg2;
+
+ // The padding bytes must be 0xff when unlocking vibration motors.
+ memset(
+ req->pad_req.dummy,
+ (cmd == PAD_CMD_REQUEST_CONFIG) ? 0xff : 0x00,
+ 4
+ );
+}
+
+// This callback determines whether a pad that identified as digital is
+// actually a DualShock in digital mode by checking if it started identifying
+// as CONFIG_MODE after receiving a configuration command.
+void dualshock_init_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) {
+ PADTYPE *pad = (PADTYPE *) buff;
+
+ if (
+ (rx_len < 2) ||
+ (pad->raw.prefix != 0x5a) ||
+ (pad->raw.type != PAD_ID_CONFIG_MODE)
+ ) {
+ printf("no, pad is digital-only (len = %d)\n", rx_len);
+
+ pad_digital_only[port] = 1;
+ return;
+ }
+
+ printf("yes, forcing analog mode (len = %d)\n", rx_len);
+
+ // Issue further commands to force analog mode on, unlock rumble (not used
+ // in this example) and enable longer responses containing button pressure
+ // readings.
+ // TODO: find out if passing 0x03 instead of 0x02 in PAD_CMD_SET_ANALOG
+ // locks the analog button, as emulated by DuckStation...
+ // https://gist.github.com/scanlime/5042071
+ send_pad_cmd(port, PAD_CMD_SET_ANALOG, 0x01, 0x02, 0);
+ send_pad_cmd(port, PAD_CMD_INIT_PRESSURE, 0x00, 0x00, 0); // Ignored by DualShock 1
+ send_pad_cmd(port, PAD_CMD_REQUEST_CONFIG, 0x00, 0x01, 0);
+ send_pad_cmd(port, PAD_CMD_RESPONSE_CONFIG, 0xff, 0xff, 0); // Ignored by DualShock 1
+ send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x00, 0x00, 0);
+}
+
+// This function is called by the pad timer ISR each time a pad is polled and a
+// response (even an invalid/incomplete one) is received.
+void poll_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) {
+ // Copy the response to a persistent buffer so it can be accessed from the
+ // main loop and displayed on screen.
+ pad_buff_len[port] = rx_len;
+ if (rx_len)
+ memcpy((void *) pad_buff[port], (void *) buff, rx_len);
+
+ PADTYPE *pad = (PADTYPE *) buff;
+
+ // If this pad identifies as a digital pad and hasn't been flagged as a
+ // digital-only pad already, attempt to put it into analog mode by entering
+ // configuration mode. It this fails, it will be flagged as digital-only.
+ // The digital-only flag is reset when the controller is unplugged or stops
+ // returning digital pad responses.
+ if (
+ rx_len &&
+ (pad->raw.prefix == 0x5a) &&
+ (pad->raw.type == PAD_ID_DIGITAL)
+ ) {
+ if (!pad_digital_only[port]) {
+ printf("Detecting if pad %d supports config mode... ", port + 1);
+
+ // The pad only identifies as CONFIG_MODE after at least another
+ // command is sent.
+ send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, 0);
+ send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, &dualshock_init_cb);
+ }
+
+ } else {
+ //printf("Clearing digital-only flag for pad %d\n", port + 1);
+
+ pad_digital_only[port] = 0;
+ }
+}
+
+/* Main */
+
+static CONTEXT ctx;
+
+int main(int argc, const char* argv[]) {
+ init_context(&ctx);
+ spi_init(&poll_cb);
+
+ uint32_t counter = 0;
+
+ while (1) {
+ FntPrint(-1, "COUNTER=%d", counter++);
+
+ for (uint32_t port = 0; port < 2; port++) {
+ // TODO.
+ if (!pad_buff_len[port]) {
+ FntPrint(-1, "\n\nPORT %d: NO DEVICE FOUND\n", port + 1);
+ if ((counter % 64) < 32)
+ FntPrint(-1, " CONNECT PAD NOW...");
+
+ continue;
+ }
+
+ PADTYPE *pad = (PADTYPE *) pad_buff[port];
+ PAD_TYPEID type = pad->raw.type;
+
+ // According to nocash docs, there is a hardware bug in DualShock
+ // controllers that causes the prefix byte (normally 0x5a) to turn
+ // into 0x00 if the analog button is pressed after configuration
+ // commands have been used. Thus making sure the prefix is 0x5a
+ // isn't enough to reliably detect pads.
+ /*if ((pad->raw.prefix != 0x5a) && (type != PAD_ID_ANALOG)) {
+ FntPrint(-1, "\n\nPORT %d: INVALID RESPONSE\n", port + 1);
+ if ((counter % 64) < 32)
+ FntPrint(-1, " CHECK CONNECTION...");
+
+ continue;
+ }*/
+
+ FntPrint(
+ -1,
+ "\n\nPORT %d: %s (TYPE=%d)\n",
+ port + 1,
+ PAD_TYPEIDS[type],
+ type
+ );
+
+ // Print a hexdump of the payload returned by the pad.
+ for (uint32_t i = 0; i < pad_buff_len[port]; i++)
+ FntPrint(
+ -1,
+ ((i - 2) % 8) ? " %02x" : "\n %02x",
+ pad_buff[port][i]
+ );
+ }
+
+ FntFlush(-1);
+ display(&ctx);
+ }
+
+ return 0;
+}
diff --git a/examples/io/pads/spi.c b/examples/io/pads/spi.c
new file mode 100644
index 0000000..e01b3f6
--- /dev/null
+++ b/examples/io/pads/spi.c
@@ -0,0 +1,218 @@
+/*
+ * PSn00bSDK controller polling example (SPI driver)
+ * (C) 2021 spicyjpeg - MPL licensed
+ *
+ * This is a fairly complete timer driven, asynchronous high-speed SPI driver,
+ * with support for sending custom commands (including memory card access), in
+ * about 200 lines of code. Feel free to copypaste and adapt it.
+ *
+ * The way this works is by maintaining a queue of requests to send, each with
+ * its own payload and callback. Timer 2 is configured to trigger an IRQ at
+ * regular intervals. On each tick, the next request in the queue (or a poll
+ * command if no request is pending) is prepared and the first byte is
+ * sent; if the controller asks for more data by pulling /ACK low, the next
+ * byte is sent and the received byte is placed into a buffer. This goes on
+ * until the last byte is exchanged and the controller stops asserting /ACK.
+ *
+ * On the next tick, the response buffer is passed to the request's callback
+ * and reset, and the next request in the queue is sent. This blindly assumes
+ * it only takes one tick for a request/response to be sent, which is the case
+ * for controllers' very small packets but not for memory cards. It is
+ * advisable to call spi_set_poll_rate() to temporarily reduce poll rate while
+ * accessing memory cards.
+ *
+ * Note that this driver completely takes over the SPI bus, so you won't be
+ * able to use any BIOS functions that rely on SPI access (i.e. pad and memory
+ * card APIs) alongside it.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <psxetc.h>
+#include <psxapi.h>
+#include <psxpad.h>
+
+#include "spi.h"
+
+/* Register definitions */
+
+#define F_CPU 33868800UL
+
+#define TIM_VALUE(N) *((volatile uint32_t *) 0x1f801100 + 4 * (N))
+#define TIM_CTRL(N) *((volatile uint32_t *) 0x1f801104 + 4 * (N))
+#define TIM_RELOAD(N) *((volatile uint32_t *) 0x1f801108 + 4 * (N))
+
+// IMPORTANT: even though JOY_TXRX is a 32-bit register, it should only be
+// accessed as 8-bit. Reading it as 16 or 32-bit works fine on real hardware,
+// but leads to problems in some emulators.
+#define JOY_TXRX *((volatile uint8_t *) 0x1f801040)
+#define JOY_STAT *((volatile uint16_t *) 0x1f801044)
+#define JOY_MODE *((volatile uint16_t *) 0x1f801048)
+#define JOY_CTRL *((volatile uint16_t *) 0x1f80104a)
+#define JOY_BAUD *((volatile uint16_t *) 0x1f80104e)
+
+/* Internal structures and globals */
+
+typedef struct _SPICONTEXT {
+ uint8_t tx_buff[SPI_BUFF_LEN];
+ uint8_t rx_buff[SPI_BUFF_LEN];
+ uint32_t tx_len, rx_len, port;
+ SPICALLBACK callback;
+} SPICONTEXT;
+
+static volatile SPICONTEXT ctx;
+static volatile SPIREQUEST volatile *current_req;
+static SPICALLBACK default_cb;
+
+/* Request queue management */
+
+static void prepare_poll_req(void) {
+ PADREQUEST *req = (PADREQUEST *) ctx.tx_buff;
+
+ req->addr = 0x01;
+ req->cmd = PAD_CMD_READ;
+ req->tap_mode = 0x00; // 0x01 to enable extended multitap response
+ req->motor_l = 0x00;
+ req->motor_r = 0x00;
+
+ ctx.tx_len = 4;
+ ctx.rx_len = 0;
+ ctx.port ^= 1;
+ ctx.callback = default_cb;
+}
+
+static void prepare_next_req(void) {
+ // Copy the contents of the first request in the queue into the TX buffer.
+ memcpy((void *) ctx.tx_buff, (void *) current_req->data, current_req->len);
+
+ ctx.tx_len = current_req->len;
+ ctx.rx_len = 0;
+ ctx.port = current_req->port;
+ ctx.callback = current_req->callback;
+
+ // Pop the first request from the queue by deallocating it and adjusting
+ // the pointer to the first queue item.
+ SPIREQUEST *next = current_req->next;
+
+ free((void *) current_req);
+ current_req = next;
+}
+
+/* Interrupt handlers */
+
+static void poll_timer_tick(void) {
+ // Fetch the last response byte, which wasn't followed by a pulse on /ACK,
+ // from the RX FIFO.
+ if (JOY_STAT & 0x0002)
+ ctx.rx_buff[ctx.rx_len - 1] = (uint8_t) JOY_TXRX;
+
+ if (ctx.callback)
+ ctx.callback(ctx.port, ctx.rx_buff, ctx.rx_len);
+
+ // If the request queue is empty, create a pad polling request.
+ if (current_req)
+ prepare_next_req();
+ else
+ prepare_poll_req();
+
+ // Prepare the SPI port by clearing any pending IRQ, pulling /CS high and
+ // enabling the /ACK IRQ. In order to communicate with controllers, /CS has
+ // to be driven low again for about 20 us before sending the first byte.
+ JOY_CTRL = 0x0010;
+ for (uint32_t i = 0; i < 50; i++)
+ __asm__("nop");
+
+ JOY_CTRL = 0x1003 | (ctx.port << 13);
+ for (uint32_t i = 0; i < 500; i++)
+ __asm__("nop");
+
+ // Send the first byte indicating which device to address. If the matching
+ // device is connected, it will reply by triggering the /ACK IRQ.
+ JOY_TXRX = ctx.tx_buff[0];
+}
+
+static void spi_ack_handler(void) {
+ // Wait until /ACK is pulled up by the controller before sending the next
+ // byte. According to nocash docs, this has to be done before resetting the
+ // IRQ.
+ while (JOY_STAT & 0x0080)
+ __asm__("nop");
+
+ // Keep /CS pulled low and acknowledge the IRQ (bit 4) to ensure it can be
+ // triggered again.
+ JOY_CTRL = 0x1013 | (ctx.port << 13);
+
+ if (!ctx.rx_len) {
+ // We just sent the first address byte. Obviously the response we
+ // received was read from an open bus, so the SPI port's internal FIFO
+ // must be flushed (by performing dummy reads) to ensure we are only
+ // going to read valid data from now on.
+ JOY_TXRX;
+
+ } else if (ctx.rx_len <= SPI_BUFF_LEN) {
+ // If this is not the first byte, put it in the RX buffer.
+ ctx.rx_buff[ctx.rx_len - 1] = (uint8_t) JOY_TXRX;
+ }
+
+ // Send the next byte, or a null byte if there is no more data to send and
+ // we're just reading a response.
+ ctx.rx_len++;
+ if (ctx.rx_len < ctx.tx_len)
+ JOY_TXRX = (uint32_t) ctx.tx_buff[ctx.rx_len];
+ else
+ JOY_TXRX = 0x00;
+}
+
+/* Public API */
+
+SPIREQUEST *spi_new_request(void) {
+ SPIREQUEST *req = malloc(sizeof(SPIREQUEST));
+
+ req->len = 0;
+ req->port = 0;
+ req->callback = 0;
+ req->next = 0;
+
+ // Find the last queued request by traversing the linked list and append a
+ // pointer to the new request.
+ if (!current_req) {
+ current_req = req;
+ } else {
+ volatile SPIREQUEST *volatile last = current_req;
+ while (last->next)
+ last = last->next;
+
+ last->next = req;
+ }
+
+ return req;
+}
+
+void spi_set_poll_rate(uint32_t value) {
+ TIM_CTRL(2) = 0x0258; // CLK/8 input, IRQ on reload, disable one-shot IRQ
+
+ if (value < 65)
+ TIM_RELOAD(2) = 0xffff;
+ else
+ TIM_RELOAD(2) = (F_CPU / 8) / value;
+}
+
+void spi_init(SPICALLBACK callback) {
+ // Disable the BIOS timer handler (which for some stupid reason is enabled
+ // by default, even though it does nothing) and set up custom interrupt
+ // handlers.
+ EnterCriticalSection();
+ ChangeClearRCnt(2, 0);
+ InterruptCallback(6, &poll_timer_tick);
+ InterruptCallback(7, &spi_ack_handler);
+ ExitCriticalSection();
+
+ JOY_CTRL = 0x0040; // Reset all registers
+ JOY_MODE = 0x000d; // 1x multiplier, 8 data bits, no parity
+ JOY_BAUD = 0x0088; // 250000 bps
+
+ spi_set_poll_rate(250);
+ current_req = 0;
+ default_cb = callback;
+}
diff --git a/examples/io/pads/spi.h b/examples/io/pads/spi.h
new file mode 100644
index 0000000..1c473cd
--- /dev/null
+++ b/examples/io/pads/spi.h
@@ -0,0 +1,61 @@
+/*
+ * PSn00bSDK controller polling example (SPI driver)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#ifndef __SPI_H
+#define __SPI_H
+
+#include <stdint.h>
+#include <psxpad.h>
+
+//#define SPI_BUFF_LEN 34
+#define SPI_BUFF_LEN 140
+
+/* Request structures */
+
+typedef void (*SPICALLBACK)(uint32_t port, const volatile uint8_t *buff, size_t rx_len);
+
+typedef struct _SPIREQUEST {
+ union {
+ uint8_t data[SPI_BUFF_LEN];
+ PADREQUEST pad_req;
+ MCDREQUEST mcd_req;
+ };
+ uint32_t len, port;
+ SPICALLBACK callback;
+ struct _SPIREQUEST *next;
+} SPIREQUEST;
+
+/* Public API */
+
+/**
+ * @brief Allocates a new request object and adds it to the request queue. The
+ * object must be populated afterwards by setting the length, callback and
+ * filling in the TX data buffer.
+ */
+SPIREQUEST *spi_new_request(void);
+
+/**
+ * @brief Changes the controller polling rate. The lowest supported rate is 65
+ * Hz (requests sent every 1/65th of a second, each port polled at 32.5 Hz when
+ * no request is pending).
+ *
+ * @param value
+ */
+void spi_set_poll_rate(uint32_t value);
+
+/**
+ * @brief Installs the SPI and timer 2 interrupt handlers and starts the poll
+ * timer. By default the polling rate is set to 250 Hz (125 Hz per port),
+ * however it can be changed at any time by calling spi_set_poll_rate().
+ *
+ * The provided callback (if any) is called to report the result of poll
+ * requests, which are issued automatically when no other request is in the
+ * queue. Passing NULL as callback does not disable auto-polling.
+ *
+ * @param callback
+ */
+void spi_init(SPICALLBACK callback);
+
+#endif
diff --git a/examples/lowlevel/cartrom/CMakeLists.txt b/examples/lowlevel/cartrom/CMakeLists.txt
new file mode 100644
index 0000000..3e807a3
--- /dev/null
+++ b/examples/lowlevel/cartrom/CMakeLists.txt
@@ -0,0 +1,36 @@
+# PSn00bSDK example CMake script
+# (C) 2021 spicyjpeg - MPL licensed
+
+cmake_minimum_required(VERSION 3.21)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
+ set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
+endif()
+
+project(
+ cartrom
+ LANGUAGES C ASM
+ VERSION 1.0.0
+ DESCRIPTION "PSn00bSDK expansion port ROM example"
+ HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
+)
+
+file(GLOB _sources *.c *.s)
+
+# This example only uses the toolchain (without the rest of the SDK), so the
+# executable has to be created manually and converted into raw binary format
+# (for testing on emulators or flashing to a cheat cartridge).
+add_executable (cartrom ${_sources})
+target_link_libraries(cartrom psn00bsdk_static_exe)
+set_target_properties(cartrom PROPERTIES PREFIX "" SUFFIX ".elf")
+target_link_options (cartrom PRIVATE -T${PROJECT_SOURCE_DIR}/rom.ld)
+
+target_include_directories(cartrom PRIVATE ${PROJECT_SOURCE_DIR})
+
+add_custom_command(
+ TARGET cartrom POST_BUILD
+ COMMAND ${CMAKE_OBJCOPY} -O binary cartrom.elf cartrom.bin
+ BYPRODUCTS cartrom.bin
+)
+
+install(FILES ${PROJECT_BINARY_DIR}/cartrom.bin TYPE BIN)
diff --git a/examples/lowlevel/cartrom/makefile b/examples/lowlevel/cartrom/makefile
deleted file mode 100644
index 2434685..0000000
--- a/examples/lowlevel/cartrom/makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-PREFIX = mipsel-unknown-elf-
-
-CC = $(PREFIX)gcc
-AS = $(PREFIX)as
-LD = $(PREFIX)ld
-
-all: rom.o
- $(LD) --oformat binary -T rom.ld -o cartrom.rom rom.o
-
-%.o: %.s
- $(AS) -msoft-float --warn $< -o $@
-
-clean:
- rm -f rom.o cartrom.rom \ No newline at end of file
diff --git a/examples/sound/vagsample/CMakeLists.txt b/examples/sound/vagsample/CMakeLists.txt
index 1f42608..1a15d9c 100644
--- a/examples/sound/vagsample/CMakeLists.txt
+++ b/examples/sound/vagsample/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(vagsample STATIC ${_sources})
#psn00bsdk_add_cd_image(vagsample_iso vagsample iso.xml DEPENDS vagsample)
-install(FILES ${PROJECT_BINARY_DIR}/vagsample.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/vagsample.exe TYPE BIN)
diff --git a/examples/system/childexec/CMakeLists.txt b/examples/system/childexec/CMakeLists.txt
index c9983c4..88168e0 100644
--- a/examples/system/childexec/CMakeLists.txt
+++ b/examples/system/childexec/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -38,4 +38,4 @@ target_link_options(child PRIVATE -Ttext=0x80030000)
# embedded via child_exe.s).
add_dependencies(parent child)
-install(FILES ${PROJECT_BINARY_DIR}/parent.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/parent.exe TYPE BIN)
diff --git a/examples/system/console/CMakeLists.txt b/examples/system/console/CMakeLists.txt
index acae08f..6dc6154 100644
--- a/examples/system/console/CMakeLists.txt
+++ b/examples/system/console/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(console STATIC ${_sources})
#psn00bsdk_add_cd_image(console_iso console iso.xml DEPENDS console)
-install(FILES ${PROJECT_BINARY_DIR}/console.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/console.exe TYPE BIN)
diff --git a/examples/system/dynlink/CMakeLists.txt b/examples/system/dynlink/CMakeLists.txt
index 3af5d4b..5834647 100644
--- a/examples/system/dynlink/CMakeLists.txt
+++ b/examples/system/dynlink/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -28,5 +28,5 @@ install(
FILES
${PROJECT_BINARY_DIR}/dynlink.bin
${PROJECT_BINARY_DIR}/dynlink.cue
- DESTINATION .
+ TYPE BIN
)
diff --git a/examples/system/dynlink/display.c b/examples/system/dynlink/display.c
index d8ad3ed..573f17c 100644
--- a/examples/system/dynlink/display.c
+++ b/examples/system/dynlink/display.c
@@ -10,6 +10,10 @@
#define SCREEN_XRES 320
#define SCREEN_YRES 240
+#define BGCOLOR_R 48
+#define BGCOLOR_G 24
+#define BGCOLOR_B 0
+
/* Display/GPU context utilities */
void init_context(CONTEXT *ctx) {
@@ -23,14 +27,14 @@ void init_context(CONTEXT *ctx) {
db = &(ctx->db[0]);
SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES);
SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES);
- setRGB0(&(db->draw), 63, 0, 127);
+ setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B);
db->draw.isbg = 1;
db->draw.dtd = 1;
db = &(ctx->db[1]);
SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES);
SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES);
- setRGB0(&(db->draw), 63, 0, 127);
+ setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B);
db->draw.isbg = 1;
db->draw.dtd = 1;
diff --git a/examples/system/dynlink/library/balls.c b/examples/system/dynlink/library/balls.c
index 2a4d9f4..ef6993e 100644
--- a/examples/system/dynlink/library/balls.c
+++ b/examples/system/dynlink/library/balls.c
@@ -3,7 +3,7 @@
* (C) 2021 spicyjpeg - MPL licensed
*/
-#include <sys/types.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <psxgpu.h>
diff --git a/examples/system/dynlink/library/cube.c b/examples/system/dynlink/library/cube.c
index 57f3e56..84fe552 100644
--- a/examples/system/dynlink/library/cube.c
+++ b/examples/system/dynlink/library/cube.c
@@ -3,7 +3,7 @@
* (C) 2021 spicyjpeg - MPL licensed
*/
-#include <sys/types.h>
+#include <stdint.h>
#include <stdio.h>
#include <psxgpu.h>
#include <psxgte.h>
diff --git a/examples/system/dynlink/library/dll_common.h b/examples/system/dynlink/library/dll_common.h
index 4f9314b..315a993 100644
--- a/examples/system/dynlink/library/dll_common.h
+++ b/examples/system/dynlink/library/dll_common.h
@@ -6,6 +6,7 @@
#ifndef __DLL_COMMON_H
#define __DLL_COMMON_H
+#include <stdint.h>
#include <psxgpu.h>
/* Common structures shared by the main executable and DLLs */
diff --git a/examples/system/dynlink/main.c b/examples/system/dynlink/main.c
index 33f6f44..6d93e71 100644
--- a/examples/system/dynlink/main.c
+++ b/examples/system/dynlink/main.c
@@ -36,12 +36,11 @@
* as plugins/mods/patches stored on a memory card.
*/
-#include <sys/types.h>
+#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <dlfcn.h>
#include <psxapi.h>
#include <psxetc.h>
diff --git a/examples/system/timer/CMakeLists.txt b/examples/system/timer/CMakeLists.txt
index 189bf87..58daf9b 100644
--- a/examples/system/timer/CMakeLists.txt
+++ b/examples/system/timer/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(timer STATIC ${_sources})
#psn00bsdk_add_cd_image(timer_iso timer iso.xml DEPENDS timer)
-install(FILES ${PROJECT_BINARY_DIR}/timer.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/timer.exe TYPE BIN)
diff --git a/examples/system/tty/CMakeLists.txt b/examples/system/tty/CMakeLists.txt
index 024ccd4..4e0ca36 100644
--- a/examples/system/tty/CMakeLists.txt
+++ b/examples/system/tty/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
@@ -19,4 +19,4 @@ file(GLOB _sources *.c)
psn00bsdk_add_executable(tty STATIC ${_sources})
#psn00bsdk_add_cd_image(tty_iso tty iso.xml DEPENDS tty)
-install(FILES ${PROJECT_BINARY_DIR}/tty.exe DESTINATION .)
+install(FILES ${PROJECT_BINARY_DIR}/tty.exe TYPE BIN)
diff --git a/indev/README.md b/indev/README.md
index 2064a36..8263487 100644
--- a/indev/README.md
+++ b/indev/README.md
@@ -23,6 +23,10 @@ also go into this directory.
The Github release of this work-in-progress component includes delay
corrections for PAL consoles.
+ **NOTE**: the `io/pads` example also shows how to poll controllers manually
+ in a slightly different way (using a timer), and includes a reusable
+ low-level pad driver.
+
Work-in-progress components such as psxcd, interlace-exp, xptest and partest
are not included, as the former was completed while the remaining latter are
merely scrap test programs. \ No newline at end of file
diff --git a/indev/psxmdec/main.c b/indev/psxmdec/main.c
index c9fd678..f4f0f51 100644
--- a/indev/psxmdec/main.c
+++ b/indev/psxmdec/main.c
@@ -1,7 +1,7 @@
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
-#include <malloc.h>
+#include <stdlib.h>
#include <psxgte.h>
#include <psxgpu.h>
diff --git a/indev/psxpad/main.c b/indev/psxpad/main.c
index e8a6181..afd801e 100644
--- a/indev/psxpad/main.c
+++ b/indev/psxpad/main.c
@@ -1,7 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <malloc.h>
#include <psxetc.h>
#include <psxgte.h>
#include <psxgpu.h>
diff --git a/libpsn00b/CMakeLists.txt b/libpsn00b/CMakeLists.txt
index 083208a..7b5f7a5 100644
--- a/libpsn00b/CMakeLists.txt
+++ b/libpsn00b/CMakeLists.txt
@@ -1,7 +1,7 @@
# libpsn00b build script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
# ${PROJECT_SOURCE_DIR} is not available until project() is called.
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/sdk.cmake)
diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake
index 377afbc..b0c4591 100644
--- a/libpsn00b/cmake/internal_setup.cmake
+++ b/libpsn00b/cmake/internal_setup.cmake
@@ -4,7 +4,7 @@
# This script is included automatically when using the toolchain file and
# defines helper functions.
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
include(GNUInstallDirs)
# IMPORTANT TODO: set a version number
@@ -86,16 +86,14 @@ function(psn00bsdk_add_executable name type)
endif()
add_executable (${name} ${ARGN})
- target_link_libraries(${name} psn00bsdk_${_type}_exe)
+ 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})
# Add post-build steps to generate the .exe and symbol map once the
- # executable is built. CMake 3.21 added support for target-dependent
- # generator expressions (catchy name lol) in add_custom_command(), so I'm
- # making heavy use of those here.
+ # executable is built.
add_custom_command(
TARGET ${name} POST_BUILD
COMMAND ${ELF2X} -q ${name}.elf ${name}${PSN00BSDK_EXECUTABLE_SUFFIX}
diff --git a/libpsn00b/cmake/sdk.cmake b/libpsn00b/cmake/sdk.cmake
index 4c2f330..ae23a06 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
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
set(
PSN00BSDK_TC $ENV{PSN00BSDK_TC}
diff --git a/libpsn00b/cmake/virtual_targets.cmake b/libpsn00b/cmake/virtual_targets.cmake
index df1df79..9afcebd 100644
--- a/libpsn00b/cmake/virtual_targets.cmake
+++ b/libpsn00b/cmake/virtual_targets.cmake
@@ -72,7 +72,7 @@ set(_cflags -mno-abicalls -mgpopt -mno-extern-sdata)
set(_cxxflags)
set(_ldflags -G8 -static)
-_add_interface_target(psn00bsdk_static_exe psn00bsdk_common ${PSN00BSDK_LIBRARIES})
+_add_interface_target(psn00bsdk_static_exe psn00bsdk_common)
# Options for executables with support for dynamic linking:
# - Position-independent code disabled
@@ -83,7 +83,7 @@ set(_cflags -mno-abicalls -mno-gpopt)
set(_cxxflags)
set(_ldflags -G0 -static)
-_add_interface_target(psn00bsdk_dynamic_exe psn00bsdk_common ${PSN00BSDK_LIBRARIES})
+_add_interface_target(psn00bsdk_dynamic_exe psn00bsdk_common)
# Options for static libraries:
# - GP-relative addressing disabled
diff --git a/libpsn00b/include/malloc.h b/libpsn00b/include/malloc.h
index d94823f..75c3711 100644
--- a/libpsn00b/include/malloc.h
+++ b/libpsn00b/include/malloc.h
@@ -1,18 +1,8 @@
#ifndef _MALLOC_H
#define _MALLOC_H
-#ifdef __cplusplus
-extern "C" {
-#endif
+#warning "<malloc.h> is deprecated, include <stdlib.h> instead"
-unsigned int *GetBSSend();
-void InitHeap(unsigned int *addr, int size);
-int SetHeapSize(int size);
-void *malloc(int size);
-void free(void *ptr);
-
-#ifdef __cplusplus
-}
-#endif
+#include <stdlib.h>
#endif // _MALLOC_H \ No newline at end of file
diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h
index 9e92568..ec0dfea 100644
--- a/libpsn00b/include/psxapi.h
+++ b/libpsn00b/include/psxapi.h
@@ -32,6 +32,35 @@
#define RCntMdFR 0x0000
#define RCntMdGATE 0x0010
+typedef struct { // Thread control block
+ int status;
+ int mode;
+ union {
+ unsigned int reg[37];
+ struct {
+ unsigned int zero, at;
+ unsigned int v0, v1;
+ unsigned int a0, a1, a2, a3;
+ unsigned int t0, t1, t2, t3, t4, t5, t6, t7;
+ unsigned int s0, s1, s2, s3, s4, s5, s6, s7;
+ unsigned int t8, t9;
+ unsigned int k0, k1;
+ unsigned int gp, sp, fp, ra;
+
+ unsigned int cop0r14;
+ unsigned int hi;
+ unsigned int lo;
+ unsigned int cop0r12;
+ unsigned int cop0r13;
+ };
+ };
+ int _reserved[9];
+} TCB;
+
+typedef struct { // Process control block
+ TCB *thread;
+} PCB;
+
typedef struct { // Device control block
char *name;
int flags;
@@ -182,6 +211,9 @@ void ChangeClearRCnt(int t, int m);
int Exec(struct EXEC *exec, int argc, char **argv);
void FlushCache(void);
+// Misc functions
+int GetSystemInfo(int index);
+
void _boot(void);
#ifdef __cplusplus
diff --git a/libpsn00b/include/psxpad.h b/libpsn00b/include/psxpad.h
index 01aff06..d152896 100644
--- a/libpsn00b/include/psxpad.h
+++ b/libpsn00b/include/psxpad.h
@@ -3,10 +3,12 @@
* 2019 Lameguy64 / Meido-Tek Productions
*
* Currently only provides a bunch of definitions and a few structs but no
- * handling functions yet. Use the code in pad.s in one of the sample
- * programs for the meantime instead.
+ * handling functions yet. See the io/pads example for a simple manual pollling
+ * implementation (with support for DualShock 2 controllers).
*
* Work in progress, subject to change significantly in future releases.
+ *
+ * Reference: https://gist.github.com/scanlime/5042071
*/
#ifndef _PSXPAD_H
@@ -50,58 +52,153 @@
#define GCON_TRIGGER 8192
#define GCON_B 16384
-// Struct for digital, joystick, dual analog and Dualshock controllers
-typedef struct {
- unsigned char stat; // Status
- unsigned char len:4; // Data length (in halfwords)
- unsigned char type:4; // Device type:
- // 0x4 - digital pad
- // 0x5 - analog joystick
- // 0x7 - dual analog & Dualshock
- unsigned short btn; // Button states
- unsigned char rs_x,rs_y; // Right stick coordinates
- unsigned char ls_x,ls_y; // Left stick coordinates
+typedef enum {
+ PAD_ID_MOUSE = 0x1, // Sony PS1 mouse
+ PAD_ID_NEGCON = 0x2, // Namco neGcon
+ PAD_ID_IRQ10_GUN = 0x3, // "Konami" lightgun without composite video passthrough
+ PAD_ID_DIGITAL = 0x4, // Digital pad or Dual Analog/DualShock in digital mode
+ PAD_ID_ANALOG_STICK = 0x5, // Flight stick or Dual Analog in green LED mode
+ PAD_ID_GUNCON = 0x6, // Namco Guncon (lightgun with composite video passthrough)
+ PAD_ID_ANALOG = 0x7, // Dual Analog/DualShock in analog (red LED) mode
+ PAD_ID_MULTITAP = 0x8, // Multitap adapter (when tap_mode == 1)
+ PAD_ID_JOGCON = 0xe, // Namco Jogcon
+ PAD_ID_CONFIG_MODE = 0xf, // Dual Analog/DualShock in config mode (if len == 0x3)
+ PAD_ID_NONE = 0xf // No pad connected (if len == 0xf)
+} PAD_TYPEID;
+
+// Controller command definitions
+typedef enum {
+ PAD_CMD_INIT_PRESSURE = '@', // Initialize DS2 button pressure sensors (in config mode)
+ PAD_CMD_READ = 'B', // Read pad state and set rumble
+ PAD_CMD_CONFIG_MODE = 'C', // Toggle DualShock configuration mode
+ PAD_CMD_SET_ANALOG = 'D', // Set analog mode/LED state (in config mode)
+ PAD_CMD_GET_ANALOG = 'E', // Get analog mode/LED state (in config mode)
+ PAD_CMD_REQUEST_CONFIG = 'M', // Configure request/unlock vibration (in config mode)
+ PAD_CMD_RESPONSE_CONFIG = 'O' // Configure response/unlock DS2 pressure (in config mode)
+} PAD_COMMAND;
+
+// Memory card command/response definitions
+typedef enum {
+ MCD_CMD_READ = 'R', // Read sector
+ MCD_CMD_IDENTIFY = 'S', // Retrieve ID and card size information
+ MCD_CMD_WRITE = 'W' // Write sector
+} MCD_COMMAND;
+
+typedef enum {
+ MCD_STAT_OK = 'G',
+ MCD_STAT_BAD_CHECKSUM = 'N',
+ MCD_STAT_BAD_SECTOR = 0xff
+} MCD_STATUS;
+
+#define MCD_CMD_READ_LEN 139
+#define MCD_CMD_IDENTIFY_LEN 9
+#define MCD_CMD_WRITE_LEN 137
+
+// Memory card status flags
+#define MCD_FLAG_WRITE_ERROR 4 // Last write command failed
+#define MCD_FLAG_NOT_WRITTEN 8 // No writes have been issued yet
+#define MCD_FLAG_UNKNOWN 16 // Might be set on third-party cards
+
+// Struct for data returned by controllers
+typedef struct _PADTYPE {
+ union { // Header:
+ struct __attribute__((packed)) { // When parsing data returned by BIOS:
+ unsigned char stat; // Status
+ unsigned char len:4; // Payload length / 2, 0 for multitap
+ unsigned char type:4; // Device type (PAD_TYPEID)
+ };
+ struct __attribute__((packed)) { // When parsing raw controller response:
+ unsigned char len:4; // Payload length / 2, 0 for multitap
+ unsigned char type:4; // Device type (PAD_TYPEID)
+ unsigned char prefix; // Must be 0x5a
+ } raw;
+ };
+ struct { // Payload:
+ unsigned short btn; // Button states
+ union {
+ struct { // Analog controller:
+ unsigned char rs_x,rs_y; // Right stick coordinates
+ unsigned char ls_x,ls_y; // Left stick coordinates
+ unsigned char press[12]; // Button pressure (DualShock 2 only)
+ };
+ struct { // Mouse:
+ char x_mov; // X movement of mouse
+ char y_mov; // Y movement of mouse
+ };
+ struct { // neGcon:
+ unsigned char twist; // Controller twist
+ unsigned char btn_i; // I button value
+ unsigned char btn_ii; // II button value
+ unsigned char trg_l; // L trigger value
+ };
+ struct { // Jogcon:
+ unsigned short jog_rot; // Jog rotation
+ };
+ struct { // Guncon:
+ unsigned short gun_x; // Gun X position in dotclocks
+ unsigned short gun_y; // Gun Y position in scanlines
+ };
+ };
+ };
} PADTYPE;
-// Struct for a mouse controller
-typedef struct {
- unsigned char stat;
- unsigned char len:4;
- unsigned char type:4; // Device type (0x1)
- unsigned short btn;
- char x_mov; // X movement of mouse
- char y_mov; // Y movement of mouse
-} MOUSETYPE;
-
-// Struct for a neGcon controller (for Namco neGcon)
-typedef struct {
- unsigned char stat;
- unsigned char len:4;
- unsigned char type:4; // (0x2)
- unsigned short btn;
- unsigned char twist; // Controller twist
- unsigned char btn_i; // I button value
- unsigned char btn_ii; // II button value
- unsigned char trg_l; // L trigger value
-} NCONTYPE;
-
-// Struct for a Jogcon controller (for Namco Jogcon)
-typedef struct {
- unsigned char stat;
- unsigned char len:4;
- unsigned char type:4; // (0xE)
- unsigned short btn;
- unsigned short jog_rot; // Jog rotation
-} JCONTYPE;
-
-// Struct for a Gun-Con controller (for Namco Gun-Con)
-typedef struct {
- unsigned char status;
- unsigned char len:4;
- unsigned char type:4; // (0x6)
- unsigned short btn;
- unsigned short gun_x; // Gun X position in dotclocks
- unsigned short gun_y; // Gun Y position in scanlines
-} GCONTYPE;
+typedef struct _MCDRESPONSE {
+ unsigned char flags; // Status flags
+ unsigned char type1; // Must be 0x5a
+ unsigned char type2; // Must be 0x5d
+ union {
+ struct { // MCD_CMD_READ response:
+ unsigned char dummy[2];
+ unsigned char ack1; // Must be 0x5c
+ unsigned char ack2; // Must be 0x5d
+ unsigned char lba_h;
+ unsigned char lba_l;
+ unsigned char data[128];
+ unsigned char checksum; // = lba_h ^ lba_l ^ data
+ unsigned char stat; // Status (MCD_STATUS)
+ } read;
+ struct { // MCD_CMD_IDENTIFY response:
+ unsigned char ack1; // Must be 0x5c
+ unsigned char ack2; // Must be 0x5d
+ unsigned char size_h; // Card capacity bits 8-15 (0x04 = 128KB)
+ unsigned char size_l; // Card capacity bits 0-7 (0x00 = 128KB)
+ unsigned char blksize_h; // Sector size bits 8-15 (must be 0x00)
+ unsigned char blksize_l; // Sector size bits 0-7 (must be 0x80)
+ } identify;
+ struct { // MCD_CMD_WRITE response:
+ unsigned char dummy[131];
+ unsigned char ack1; // Must be 0x5c
+ unsigned char ack2; // Must be 0x5d
+ unsigned char stat; // Status (MCD_STATUS)
+ } write;
+ };
+} MCDRESPONSE;
+
+//typedef PADTYPE MOUSETYPE;
+//typedef PADTYPE NCONTYPE;
+//typedef PADTYPE JCONTYPE;
+//typedef PADTYPE GCONTYPE;
+
+// Structs for raw controller request
+typedef struct _PADREQUEST {
+ unsigned char addr; // Must be 0x01 (or 02/03/04 for multitap pads)
+ unsigned char cmd; // Command (PAD_COMMAND)
+ unsigned char tap_mode; // 0x01 to enable multitap response
+ unsigned char motor_r; // Right motor control (on/off)
+ unsigned char motor_l; // Left motor control (PWM)
+ unsigned char dummy[4];
+} PADREQUEST;
+
+// Structs for raw memory card request
+typedef struct _MCDREQUEST {
+ unsigned char addr; // Must be 0x81 (or 02/03/04 for multitap cards)
+ unsigned char cmd; // Command (MCD_COMMAND)
+ unsigned char dummy[2];
+ unsigned char lba_h; // Sector address bits 8-15 (dummy for CMD_IDENTIFY)
+ unsigned char lba_l; // Sector address bits 0-7 (dummy for CMD_IDENTIFY)
+ unsigned char data[128]; // Sector payload (dummy for CMD_READ/CMD_IDENTIFY)
+ unsigned char checksum; // = lba_h ^ lba_l ^ data (CMD_WRITE only)
+ unsigned char dummy2[3];
+} MCDREQUEST;
#endif \ No newline at end of file
diff --git a/libpsn00b/include/stdint.h b/libpsn00b/include/stdint.h
new file mode 100644
index 0000000..83acb00
--- /dev/null
+++ b/libpsn00b/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef _STDINT_H
+#define _STDINT_H
+
+typedef unsigned int size_t;
+
+typedef char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+#endif // _STDINT_H \ No newline at end of file
diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h
index 474eba6..de3ab47 100644
--- a/libpsn00b/include/stdlib.h
+++ b/libpsn00b/include/stdlib.h
@@ -19,34 +19,16 @@ extern long atol(char *s);
extern char atob(char *s); // Is this right?
*/
-// Random number functions (not yet implemented)
-
-/*
-int rand();
-void srand(unsigned int seed);
-*/
-
// Quick sort (not yet implemented)
//void qsort(void *base , int nel , int width , int (*cmp)(const void *,const void *));
-// Memory allocation functions (not yet implemented, avoid using BIOS as they are reportedly buggy)
-
-/*
-#warning "malloc() family of functions NEEDS MORE TESTING"
-
-void *malloc(int size);
-void free(void *buf);
-void *calloc(int number, int size);
-void *realloc(void *buf , int n);
-*/
-
#ifdef __cplusplus
extern "C" {
#endif
extern int __argc;
-extern char __argv[];
+extern const char **__argv;
int rand();
void srand(unsigned long seed);
@@ -64,6 +46,14 @@ long atol(const char *s);
double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
+// Memory allocation functions
+unsigned int *GetBSSend();
+void InitHeap(unsigned int *addr, int size);
+int SetHeapSize(int size);
+void *malloc(int size);
+void *calloc(int number, int size);
+void free(void *ptr);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpsn00b/include/sys/types.h b/libpsn00b/include/sys/types.h
index aee197e..da43590 100644
--- a/libpsn00b/include/sys/types.h
+++ b/libpsn00b/include/sys/types.h
@@ -1,21 +1,13 @@
#ifndef _TYPES_H
#define _TYPES_H
+//#warning "<sys/types.h> and u_* types are deprecated, include <stdint.h> instead"
+
+//#include <stdint.h>
+
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
-typedef unsigned int size_t;
-
-typedef char int8_t;
-typedef short int16_t;
-typedef int int32_t;
-typedef long long int64_t;
-
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-
#endif // _TYPES_H \ No newline at end of file
diff --git a/libpsn00b/libc/c++-support.cxx b/libpsn00b/libc/c++-support.cxx
index fcf7cfc..d169fdb 100644
--- a/libpsn00b/libc/c++-support.cxx
+++ b/libpsn00b/libc/c++-support.cxx
@@ -1,7 +1,6 @@
#include <assert.h>
-#include <sys/types.h>
+#include <stdint.h>
#include <stdlib.h>
-#include <malloc.h>
extern "C"
diff --git a/libpsn00b/libc/start.c b/libpsn00b/libc/start.c
index c5872df..f190794 100644
--- a/libpsn00b/libc/start.c
+++ b/libpsn00b/libc/start.c
@@ -3,9 +3,9 @@
* (C) 2021 Lameguy64, spicyjpeg - MPL licensed
*/
-#include <sys/types.h>
+#include <stdint.h>
#include <string.h>
-#include <malloc.h>
+#include <stdlib.h>
#define KERNEL_ARG_STRING ((const char *) 0x80000180)
#define KERNEL_RETURN_VALUE ((volatile int *) 0x8000dffc)
@@ -47,13 +47,7 @@ static void _parse_kernel_args() {
}
}
-/* Main */
-
-// How much space at the end of RAM to leave for the stack (instead of using it
-// as heap). By default 128 KB are reserved for the stack, but this constant
-// can be overridden in main.c (or anywhere else) simply by redeclaring it
-// without the weak attribute.
-const int32_t __attribute__((weak)) STACK_MAX_SIZE = 0x20000;
+/* Heap initialization */
// These are defined by the linker script. Note that these are *NOT* pointers,
// they are virtual symbols whose location matches their value. The simplest
@@ -63,6 +57,20 @@ 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);
@@ -73,24 +81,16 @@ extern int32_t main(int32_t argc, const char* argv[]);
// to overwrite the arg strings in kernel RAM.
void _start(int32_t override_argc, const char **override_argv) {
__asm__ volatile("la $gp, _gp;");
-
- // Mem init assembly function (clears BSS and InitHeap to _end which is
- // not possible to do purely in C because the linker complains about
- // relocation truncated to fit: R_MIPS_GPREL16 against `_end'
- // Workaround is to do it in assembly because la pseudo-op doesn't use
- // stupid gp relative addressing
- //_mem_init();
// Clear BSS 4 bytes at a time. BSS is always aligned to 4 bytes by the
// linker script.
for (uint32_t *i = (uint32_t *) __bss_start; i < (uint32_t *) _end; i++)
*i = 0;
- // Calculate how much RAM is available after the loaded executable and
- // initialize heap accordingly.
- void *exe_end = _end + 4;
- unsigned int exe_size = (unsigned int) exe_end - (unsigned int) __text_start;
- InitHeap(exe_end, 0x200000 - (exe_size + STACK_MAX_SIZE));
+ // 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);
if (override_argv) {
__argc = override_argc;
diff --git a/libpsn00b/libc/string.c b/libpsn00b/libc/string.c
index e11ed67..445b227 100644
--- a/libpsn00b/libc/string.c
+++ b/libpsn00b/libc/string.c
@@ -6,7 +6,7 @@
#include <stdio.h>
#include <string.h>
-#include <malloc.h>
+#include <stdlib.h>
int tolower(int chr)
{
diff --git a/libpsn00b/libc/vsprintf.c b/libpsn00b/libc/vsprintf.c
index 361b24e..0a99dcc 100644
--- a/libpsn00b/libc/vsprintf.c
+++ b/libpsn00b/libc/vsprintf.c
@@ -58,6 +58,15 @@
pad_quantity = (pad_quantity - 1) - last; \
if(pad_quantity < 0) pad_quantity = 0;
+#define calculate_real_padding_bin() \
+ last = 0; \
+ for (x = 0; x < 32; x++) \
+ if((arg >> x) & 1) \
+ last = x; \
+ \
+ pad_quantity = (pad_quantity - 1) - last; \
+ if(pad_quantity < 0) pad_quantity = 0;
+
#define write_padding() \
if(!(flags & SPRINTF_NEGFIELD_FLAG)) \
for(x = 0; x < pad_quantity; x++) \
@@ -703,6 +712,9 @@ int vsnprintf(char *string, unsigned int size, const char *fmt, va_list ap)
//else
// arg = va_arg(ap, unsigned long long);
+ calculate_real_padding_bin();
+ write_padding();
+
for(x=31;x>=0;x--)
{
y = (arg >> x);
@@ -715,6 +727,8 @@ int vsnprintf(char *string, unsigned int size, const char *fmt, va_list ap)
put_in_string(string, ssz, y + '0', string_pos++);
}
+ write_neg_padding();
+
directive_coming = 0;
break;
diff --git a/libpsn00b/lzp/compress.c b/libpsn00b/lzp/compress.c
index 5969dd6..9cfc64d 100644
--- a/libpsn00b/lzp/compress.c
+++ b/libpsn00b/lzp/compress.c
@@ -3,7 +3,6 @@
#include <string.h>
#if LZP_USE_MALLOC == TRUE
#include <stdlib.h>
-#include <malloc.h>
#endif
#include "lzconfig.h"
diff --git a/libpsn00b/psxapi/sys/getsysteminfo.s b/libpsn00b/psxapi/sys/getsysteminfo.s
new file mode 100644
index 0000000..60c1d43
--- /dev/null
+++ b/libpsn00b/psxapi/sys/getsysteminfo.s
@@ -0,0 +1,10 @@
+.set noreorder
+
+.section .text
+
+.global GetSystemInfo
+.type GetSystemInfo, @function
+GetSystemInfo:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0xb4 \ No newline at end of file
diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c
index dc0c5ca..40a40af 100644
--- a/libpsn00b/psxcd/isofs.c
+++ b/libpsn00b/psxcd/isofs.c
@@ -1,6 +1,6 @@
#include <sys/types.h>
#include <stdio.h>
-#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
#include <psxgpu.h>
#include <psxsio.h>
diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c
index 586e7e1..e43374f 100644
--- a/libpsn00b/psxetc/dl.c
+++ b/libpsn00b/psxetc/dl.c
@@ -23,9 +23,9 @@
* of entries
*/
-#include <sys/types.h>
+#include <stdint.h>
#include <stdio.h>
-#include <malloc.h>
+#include <stdlib.h>
#include <ctype.h>
#include <elf.h>
#include <dlfcn.h>
diff --git a/libpsn00b/psxgpu/font.c b/libpsn00b/psxgpu/font.c
index 7d0dd89..4c715a9 100644
--- a/libpsn00b/psxgpu/font.c
+++ b/libpsn00b/psxgpu/font.c
@@ -1,7 +1,7 @@
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
-#include <malloc.h>
+#include <stdlib.h>
#include <ctype.h>
#include <psxgpu.h>
diff --git a/template/CMakeLists.txt b/template/CMakeLists.txt
index c2d0d9d..c0c05d0 100644
--- a/template/CMakeLists.txt
+++ b/template/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
# CMAKE_TOOLCHAIN_FILE must be set to point to cmake/sdk.cmake in the PSn00bSDK
# installation directory *before* calling project(). You don't have to hardcode
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index dd90109..af99046 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,7 +1,7 @@
# PSn00bSDK tools build script
# (C) 2021 spicyjpeg - MPL licensed
-cmake_minimum_required(VERSION 3.21)
+cmake_minimum_required(VERSION 3.20)
project(
PSn00bSDK-tools
@@ -12,22 +12,22 @@ project(
include(GNUInstallDirs)
-## External dependencies
-
-# Let CMake attempt to find tinyxml2 on its own first. This avoids invoking
-# pkg-config where it might not be installed, and allows usage of package
-# managers like vcpkg. The path to tinyxml2 can also be specified manually by
-# passing -Dtinyxml2_ROOT.
-find_package(tinyxml2 CONFIG)
+set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_CXX_STANDARD 11)
-if(NOT tinyxml2_FOUND)
- find_package(PkgConfig REQUIRED)
- pkg_search_module(_tinyxml2 REQUIRED IMPORTED_TARGET tinyxml2)
+## Dependencies
- add_library(tinyxml2::tinyxml2 ALIAS PkgConfig::_tinyxml2)
+if(NOT EXISTS ${PROJECT_SOURCE_DIR}/tinyxml2/tinyxml2.cpp)
+ message(FATAL_ERROR "The tinyxml2 directory is empty. Run 'git submodule update --init --recursive' to populate it.")
endif()
-## Internal dependencies
+# Build tinyxml2. I didn't bother with tinyxml2's actual CMake integration
+# because it's far easier do do this. It is a single-file library after all.
+add_library (tinyxml2 STATIC tinyxml2/tinyxml2.cpp)
+target_include_directories(tinyxml2 PUBLIC tinyxml2)
+
+#add_subdirectory(tinyxml2)
# Build liblzp using sources from the libpsn00b tree. Hacky but it works.
set(LIBPSN00B_PATH ${PROJECT_SOURCE_DIR}/../libpsn00b)
@@ -46,28 +46,18 @@ target_include_directories(
## Executables
-# This is required in order to properly link against tinyxml2 under MSVC.
-set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
-set(CMAKE_C_STANDARD 11)
-set(CMAKE_CXX_STANDARD 11)
-
add_executable(elf2x util/elf2x.c)
add_executable(elf2cpe util/elf2cpe.c)
add_executable(smxlink smxlink/main.cpp smxlink/timreader.cpp)
add_executable(lzpack lzpack/main.cpp lzpack/filelist.cpp)
-target_link_libraries(smxlink tinyxml2::tinyxml2)
-target_link_libraries(lzpack tinyxml2::tinyxml2 lzp)
+target_link_libraries(smxlink tinyxml2)
+target_link_libraries(lzpack tinyxml2 lzp)
## Installation
-# Install the executables alongside the tinyxml2 DLL (if any) and copy the
-# Blender SMX export plugin to the data directory (for manual installation).
-install(
- TARGETS elf2x elf2cpe smxlink lzpack
- RUNTIME_DEPENDENCIES
- PRE_EXCLUDE_REGEXES ".*"
- PRE_INCLUDE_REGEXES "tinyxml2"
-)
+# Install the executables and copy the Blender SMX export plugin to the data
+# directory (for manual installation).
+install(TARGETS elf2x elf2cpe smxlink lzpack)
install(
DIRECTORY plugin
DESTINATION ${CMAKE_INSTALL_DATADIR}/psn00bsdk
diff --git a/tools/mkpsxiso b/tools/mkpsxiso
new file mode 160000
+Subproject fe14e95d07a0da5727a8c2fb3ff2aaa892e465c
diff --git a/tools/tinyxml2 b/tools/tinyxml2
new file mode 160000
+Subproject a9773976845b19e89020c1215781e71116477ef
diff --git a/tools/util/elf2cpe.c b/tools/util/elf2cpe.c
index 46b0a37..210f25b 100644
--- a/tools/util/elf2cpe.c
+++ b/tools/util/elf2cpe.c
@@ -1,6 +1,6 @@
#include <stdio.h>
#include <string.h>
-#include <malloc.h>
+#include <stdlib.h>
#include "elf.h"
#ifdef WIN32