Files
dusk/.claude/platform-psp.md
T
2026-06-16 10:15:59 -05:00

5.4 KiB

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:

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/<TITLE_ID><slot>/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. Set PSPDEV in your environment before configuring.

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.