Skip to content

Latest commit

 

History

106 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PySP

A PlayStation Portable emulator written in pure Python.

PySP boots PSP homebrew (ELF, relocatable PRX, EBOOT.PBP) and runs it on an interpreted Allegrex CPU with a software-rendered graphics engine. The whole machine is ordinary Python on top of numpy. That makes it slow by emulator standards, and very easy to read and single-step, which was the point: it started as a way to understand how the hardware fits together and turned into something that actually draws frames.

Screenshots

Paper PSP title screen Paper PSP in play

Paper PSP by Jerome Berg, MIT licensed homebrew, running from its released EBOOT.PBP at the native 480 by 272. The blue trail is following the d-pad; the other squares are bots. Both frames came out of --screenshot.

The same game in the window frontend:

The PySP window running Paper PSP

What works

  • The MIPS core: the integer set with the Allegrex extras (min/max, ext/ins, bit shuffles), single-precision COP1, and the VFPU with its matrix register file and operand prefixes
  • Loading: ELF, PRX with relocation, PBP containers with PARAM.SFO
  • The kernel: threads with PSP scheduling rules, semaphores, event flags, mutexes, pools, callbacks, alarms-by-delay, and a cycle-accurate event queue
  • Graphics: display list execution with a numpy rasteriser. Triangles, sprites, texturing (palettes included), depth, blending, scissor
  • I/O: a mounted ms0: backed by a host directory, ISO 9660 images on disc0:, controller input, audio mixing into a ring buffer
  • Save states, a PNG screenshotter, an interactive debugger and a pygame window

There's no JIT, no media decoding (the Atrac3 and MPEG stubs just answer politely) and no network. Retail titles are encrypted and PySP doesn't decrypt them, so in practice this is a homebrew machine.

Installing

Python 3.10 or newer.

pip install -e .          # emulator + numpy
pip install -e .[gui]     # add pygame for the window
pip install -e .[dev]     # add pytest and ruff

Running

pysp game.pbp                         # windowed
pysp game.pbp --headless --frames 300 --screenshot out.png
pysp game.pbp --debug                 # start in the debugger
pysp game.pbp --slim                  # 64 MB model
pysp-disasm game.pbp --imports       # what does it call?

ms0: maps to ./memstick unless --memory-stick says otherwise. Logging is per subsystem: --log info,ge=debug turns the graphics engine up without drowning in everything else.

Keys in the window: arrows for the pad, z/x/a/s for cross, circle, square and triangle, q/w for the triggers, enter and space for start and select, ijkl for the analogue stick.

The debugger

pysp game.pbp --debug drops you at a prompt before the first instruction:

pysp> break sceDisplaySetFrameBuf
pysp> go
pysp> regs
pysp> disasm pc 8
pysp> threads

Breakpoints take addresses or HLE function names, state summarises the kernel, save/load snapshot the whole machine.

macOS app

The macos app workflow builds a self-contained PySP.app with PyInstaller on every tag (or by hand from the Actions tab) and attaches the zip to the release. Opened from Finder it asks for an executable with a file picker; from a terminal it takes the same arguments as pysp.

Development

pytest -q          # the whole suite
ruff check .       # lint

Tests assemble their own PSP executables with the built-in MIPS assembler, so the suite goes through the real path (stub tables, syscalls, display lists) without shipping binaries. docs/architecture.md has the tour.

License

MIT.

About

A PlayStation Portable emulator written in pure Python.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages