# Platform -- Sony PSP `DUSK_TARGET_SYSTEM`: `psp` Source layer: `src/duskpsp/` Renderer: OpenGL ES (legacy, via PSPGL/SDL2) --- ## Overview The PSP is a 32 MB MIPS-based handheld console running at up to 333 MHz. It uses SDL2 (ported to PSP) for windowing and OpenGL in legacy/fixed- function mode. The game binary and all assets are packaged together inside a `.pbp` file -- the PSP's native executable format. --- ## Hardware | Attribute | Value | |-----------|-------| | CPU | MIPS R4000 (Allegrex), up to 333 MHz | | RAM | 32 MB (4 MB reserved for OS) | | Display | 480x272, 16/32-bit colour | | Storage | Memory Stick (UMD for retail; MS for homebrew) | | Endian | Little-endian | --- ## Compile-time macros | Macro | Set | |-------|-----| | `DUSK_PSP` | yes | | `DUSK_SDL2` | yes | | `DUSK_OPENGL` | yes | | `DUSK_OPENGL_LEGACY` | yes | | `DUSK_INPUT_GAMEPAD` | yes | | `DUSK_PLATFORM_ENDIAN_LITTLE` | yes | | `DUSK_DISPLAY_WIDTH` | 480 | | `DUSK_DISPLAY_HEIGHT` | 272 | | `DUSK_THREAD_PTHREAD` | yes | No `DUSK_DISPLAY_SIZE_DYNAMIC` -- the resolution is fixed. No `DUSK_INPUT_KEYBOARD`, no `DUSK_INPUT_POINTER`. --- ## Display - Fixed 480x272 resolution. - OpenGL legacy (fixed-function pipeline, `DUSK_OPENGL_LEGACY`). - Texture dimensions **must** be powers of two (use `mathNextPowTwo`). - VFPU (4-wide float SIMD) is available -- use it for matrix/vector hot paths under `#ifdef DUSK_PSP`. --- ## Asset loading Assets are packed into the **PSAR** section of the `.pbp` file by the post-build `create_pbp_file()` CMake command. At runtime, `assetInitPBP()` locates and opens the PSAR from the running executable's path. The PBP format header: ```c typedef struct { char_t signature[4]; // "\0PBP" uint32_t version; uint32_t sfoOffset; uint32_t icon0Offset; uint32_t icon1Offset; uint32_t pic0Offset; uint32_t pic1Offset; uint32_t snd0Offset; uint32_t pspOffset; uint32_t psarOffset; // dusk.dsk starts here } assetpbpheader_t; ``` `assetpbp_t` holds the open file handle and parsed header. Asset paths inside the PSAR are ZIP paths within `dusk.dsk`. --- ## Input Layered on SDL2. `inputInitPSP()` maps PSP physical buttons to SDL2 `SDL_CONTROLLER_BUTTON_*` constants: | PSP button | Action | |------------|--------| | Cross | Accept | | Circle | Cancel | | Triangle | - | | Square | - | | L / R | Shoulder buttons | | D-pad | Directional | | L-Stick | Analog axes | No keyboard or pointer input available. Attempting to use `INPUT_BUTTON_TYPE_KEYBOARD` on PSP is undefined behaviour. The PSP system setting `PSP_UTILITY_ACCEPT_CROSS` / `ACCEPT_CIRCLE` swaps the Cross and Circle button roles in OS dialogs -- read this via `systemPSPGetCrossButtonSetting()` if you need to match the system convention. --- ## Save system - Path: `ms0:/PSP/SAVEDATA//save.dat` (default title ID `DUSK00001`, configurable via `SAVE_PSP_TITLE_ID`). - Uses `sceIo` for file I/O -- no extra dialog required for raw reads. - PSP OS-level save/load dialogs (via `sceUtility`) are separate and block the main loop when open (`systemGetActiveDialogType()` returns `SYSTEM_DIALOG_TYPE_TICK_BLOCKING`). - Do not call save functions directly from game code during a dialog. --- ## Network Connection requires an explicit user Wi-Fi selection step via the PSP system network dialog (`sceUtilityNetconfInitStart`). ``` networkRequestConnection(onConnected, onFailed, onDisconnect, user); // -> shows PSP Wi-Fi selection dialog (blocking dialog type) // -> calls onConnected or onFailed when the dialog closes ``` HTTP and SSL modules (`psphttp`, `pspssl`, `pspnet_resolver`) are linked in `psp.cmake` but the HTTP implementation code is commented out. The infrastructure exists for future use. --- ## Time - Tick source: `SDL_GetTicks64()`. - Real time: `sceRtcGetCurrentTick()` (returns microseconds). - Dynamic timestep is **not** enabled (`DUSK_TIME_DYNAMIC` not set). Every tick is a fixed 16 ms step. --- ## System dialogs PSP shows OS-level dialogs for: - Wi-Fi configuration (`networkRequestConnection`) - Save management (if using `sceUtility` save dialogs) Check `systemGetActiveDialogTypePSP()` to know whether the main loop should skip rendering or ticking. --- ## Build and toolchain Requires the [PSPDEV toolchain](https://github.com/pspdev/pspdev). Set `PSPDEV` in your environment before configuring. ```sh cmake -B build \ -DDUSK_TARGET_SYSTEM=psp \ -DCMAKE_TOOLCHAIN_FILE=${PSPDEV}/lib/cmake/psp.cmake \ -DCMAKE_BUILD_TYPE=Release cmake --build build ``` Post-build output: `Dusk.pbp` (executable + assets combined). Dependencies: SDL2-PSP, OpenGL-PSP, pspgu, pspctrl, pspdisplay, pspaudio, pspaudiolib, psputility, pspvfpu, pspvram, pspnet, pspnet_inet, pspnet_apctl, psphttp, pspssl, pspdebug, psphprm, mbedtls, mbedcrypto, lzma, zip, bz2, z. --- ## Endianness Little-endian. `DUSK_PLATFORM_ENDIAN_LITTLE` is set at compile time. No runtime endian check is needed. --- ## Gotchas - The PSP has only 28 MB of usable RAM after the OS. Keep asset budgets tight -- see `.claude/optimization.md`. - VFPU instructions are not valid on threads other than the main thread on some firmware versions. Use `assertIsMainThread` on any code that calls VFPU intrinsics. - OpenGL legacy mode means no vertex/fragment shaders; rendering uses the fixed-function pipeline via `pspgl`. - `DUSK_TIME_DYNAMIC` is absent -- physics always runs at exactly the fixed step rate.