Skip to content
PORTSNATIVE.
HomeCatalog
Web GamesEmulatorsToolsNews
PORTSNATIVE.

A catalog for discovering ports and related projects. We link to official sources and do not host original game files.

ExploreCatalogMy list
InformationAbout usSuggest a portSupportDonationsLegal notice
© 2026 PortsNative
Back to catalog
Harry Potter and the Prisoner of Azkaban (macOS)
PORTSNATIVE

Harry Potter and the Prisoner of Azkaban (macOS)

NATIVE PORTPLATFORMERMACOSALPHA

Harry Potter and the Prisoner of Azkaban (macOS)

Harry Potter and the Prisoner of Azkaban

OriginPlayStation 2

TechnologyNative C/C++ port (engine reimplementation)

Available formacOS

View official project

About the project

Harry Potter y el prisionero de Azkaban es un videojuego de acción-aventura, distribuido por Electronic Arts y Warner Bros. Interactive Entertainment, Inc., lanzado en 2004 para las plataformas de PC, Game Boy Advance, Xbox, PlayStation 2 y Nintendo GameCube.

2 versions of Harry Potter and the Prisoner of Azkaban

You're viewing: Harry Potter and the Prisoner of Azkaban (macOS)

Harry Potter and the Prisoner of Azkaban (macOS)github.com/chaikosh/azkaban-recomp
macOS
Current
Harry Potter and the Prisoner of Azkabangithub.com/holly-hacker/hp3-gba-decomp
Windows
Linux
macOS
›

Official project information

Author's original READMEOpen on GitHub ↗

PS2 static recompilation port of SLUS-20926

A static recompiler and host runtime that turn the PlayStation 2 executable of Harry Potter and the Prisoner of Azkaban (SLUS-20926) into a native program. The long-term goal is a native iOS/macOS build that needs no JIT.

This is an unofficial fan project. It is not affiliated with, endorsed by, or connected to Electronic Arts or Warner Bros. The repository contains no game assets and no game code. You must supply your own legally obtained disc.

Status (October 2026)

Work in progress.

  • Boots through the memory-card screen, the EA and WB logos and the intro movies (MPEG decoding matches ffmpeg frame for frame) to the main menu.
  • New Game reaches the Hogwarts Express and its 3D scenes with correct textures and geometry.
  • Music and sound come from the game's own IOP modules, run on a low-level IOP (vendored from ps2-web-recomp, see THIRD_PARTY.md).
  • EE code and the VU1 microprograms are statically recompiled to C; the VU1 code is checked bit-exact against the interpreter.
  • Two GS renderers: the software reference and a GPU renderer (WebGPU on Metal).
  • macOS (M1): the train corridor runs at the game's own 30 fps cap with the GPU ~42% busy, and the music no longer stutters; 46 of the 48 rooms that can be started directly (HP_ARGS="-startChapter=... -startRoom=...") run at 30 fps too, with the VU1 microprograms of 62 rooms recompiled.
  • iOS: runs on an iPhone 14 Pro Max (see iOS); the current GPU renderer has not been measured there yet (it was 15–20 fps before the renderer work of 19 October).
  • Gameplay past the train has only been checked by starting in rooms directly.

How it works

  1. recomp/ is a static recompiler for the PS2 Emotion Engine (MIPS R5900).
    • r5900.py decodes instructions, elf.py loads the ELF.
    • analyze.py finds functions and jump tables. Seeds are jal targets, data pointers, lui/addiu constants and prologues; jump tables are recovered by constant propagation.
    • lift.py emits C: one C function per guest function, labels and goto, delay slots, likely branches, VU0 macro ops and MMI.
    • main.py drives the pipeline.
    • recomp/hooks.txt maps guest function addresses to host overrides (hle_* functions in runtime/hle.c).
  2. runtime/ is the host runtime that the generated C is linked against: guest memory, the kernel and IOP high-level emulation, DMA, a software GS rasterizer, VIF1/VU1, the MPEG-2 IPU, and an SDL3 front end.

The generated C is derived from your own copy of the executable. It is written to build/ and is never distributed.

Build and run

Requirements: macOS, clang, Python 3, and SDL3 (brew install sdl3). The GPU renderer links wgpu-native; the Makefile downloads its static library with scripts/fetch_wgpu.sh on the first build.

You need the contents of your own disc in two places (both git-ignored):

  • disc/: extracted files (SLUS_209.26, IOP/*.IRX, BIG/*.BIG, FILESYS.DAT, RUNTIME.CFG, SYSTEM.CNF).
  • iso/: the full ISO image (the CD/DVD reads are served from it; the path can be overridden with HP_ISO).
make -j8                                                  # recompiles if needed, builds build/hp
# or step by step:
python3 -I recomp/main.py disc/SLUS_209.26 build/recomp   # regenerate the C
./build/hp build/recomp/image.bin disc                    # run
make -j8 RELEASE=1 && HP_GS=gpu ./build/rel/hp build/recomp/image.bin disc   # optimized, GPU renderer

HP_GS=gpu draws with WebGPU compute shaders (Metal) instead of the software rasterizer in runtime/gs.c; the software renderer stays the default and the reference.

Fast test runs

A normal boot (memory card check, EA/WB logos, intro movie, title, menu, New Game, the train-compartment cutscene) reaches the first 3D gameplay (the train corridor) after about two minutes. HP_FASTBOOT=1 gets there in about 10 seconds by using the game's own debug paths (runtime/fastboot.c):

  • the debug options -startChapter=Intro -startRoom=HogwartsExpress are added to the options the game reads from RUNTIME.CFG, so it skips the logos, the movies and the front end and starts the chapter in that room;
  • cutscenes are made skippable and Cross is pressed while one plays, so the game's own skip ends it (the corridor that follows is the same as after watching the scene).
# corridor in ~10 s; the run ends at vsync 1200 (~20 s)
mkdir -p /tmp/shots
HP_FASTBOOT=1 HP_EXITAT=1200 HP_GS=gpu HP_SHOT=/tmp/shots HP_SHOTEVERY=60 \
  perl -e 'alarm shift; exec @ARGV' 60 build/rel/hp build/recomp/image.bin disc

The log shows [fastboot 8.7s v518] cutscene over: gameplay when the corridor starts (wall seconds since launch, vsync). Other modes and options:

  • HP_FASTBOOT=noskip: the same start, but cutscenes play (corridor at ~40 s).
  • HP_FASTBOOT=menu: the normal front end without the FMV (-nomovie): the main menu at ~22 s instead of ~75 s. Add HP_AUTOKEYV=1 HP_AUTOKEY=cross@23 for New Game (corridor at ~29 s, cutscene skipped).
  • HP_ARGS="-startChapter=Day1 -startRoom=GreatHall": start in another room (the Great Hall at ~7 s), or pass any other game option; HP_ARGS wins over the preset. Chapters and rooms are named like the script binaries in MISC.BIG (<chapter>_<room>.hpb: day1_greathall, night2_lowerdungeon, ...). An unknown chapter falls back to the normal front end.
  • HP_FASTBOOT=save: the direct start, then pause -> Save Game -> format a new card -> slot 1, then exit (~2 min). It writes build/memcard_fastboot.ps2 afresh: a save made in the train corridor ("The Dementor").
  • HP_FASTBOOT=load: the front end without the FMV, then Load Game -> slot 1 of build/memcard_fastboot.ps2: the corridor at ~43 s (the loaded game starts there; no cutscene). HP_MEMCARD picks another card for both.

The direct start is the fastest path and needs no memory card data; load exercises the front end, the memory card and the load path. The log also notes in-game UI starting (pre_ig) and in-game HUD, player control (ig).

The save/load presets drive the menus with a UI script that reacts to what the GUI reports instead of fixed times (menus accept input only after their animations, which vary from run to run). HP_UISCRIPT runs your own, e.g. HP_FASTBOOT=1 HP_UISCRIPT="wait:SetTraceControlMode(ig) press:start=PauseGame" opens the pause menu as soon as Harry can move. Steps: wait:TEXT, press:BUTTON=TEXT (press until TEXT is reported), press:BUTTON, sleep:SECONDS, exit; the events are the FSCommands HP_FSLOG=1 prints, and card_written. See runtime/fastboot.c.

GS traces

HP_GSREC=trace.gsr records what the GPU renderer is given (GIF data, frame requests, downloads; a 30 s corridor run is ~4 GB). make RELEASE=1 gsreplay builds build/rel/gsreplay, which plays a trace back:

build/rel/gsreplay trace.gsr [outdir first last]

It writes frames first..last as PPM and prints the time the GS passes took on the GPU. Renderer changes are checked by comparing the frames of two replays and timed on the same input (HP_REPLAYASYNC=1 reads frames back the way the game does; PS2_GPU_PROFILE=from,to,file times every dispatch). Timings are only comparable with no game running at the same time.

iOS

Makefile.ios builds a native arm64 app for the iOS Simulator or an iPhone/iPad from the same generated C (run make recomp or a desktop build first). It needs Xcode; ios/deps.sh (run automatically) fetches wgpu-native for iOS and copies SDL3 for iOS from a sibling port, or builds it from the SDL release source.

On iOS the paths default to the app sandbox (runtime/ios/ios.c):

DataLocation
Recompiled imagebundled in the app (image.bin)
Disc imageDocuments/Harry Potter and the Prisoner of Azkaban (USA).iso (or any *.iso there)
Memory cardDocuments/memcard0.ps2
Log (stderr)Documents/hp.log (HP_STDERR=1 keeps stderr)
Extracted filesDocuments/disc/, only read with HP_IOP=hle

HP_GS defaults to gpu. The app enables iTunes/Finder file sharing: on a Mac, select the device in Finder, open Files and drag the ISO onto HP Azkaban. If there is no ISO the app says so and waits (Retry). The ISO is never bundled.

The picture is shown at 4:3 in landscape with an on-screen PS2 controller (runtime/ios/touchpad.c: D-pad, left stick, face buttons, L1/L2/R1/R2, SELECT/START, multi-touch); it hides while a hardware controller is connected and comes back on a touch.

# Simulator (an arm64 iOS Simulator must be booted)
make -f Makefile.ios -j4                 # build/ios-iphonesimulator/HPAzkaban.app
make -f Makefile.ios sim-install sim-data sim-run   # SIM=<udid> instead of the booted one
make -f Makefile.ios sim-log             # Documents/hp.log
# game variables go through SIMCTL_CHILD_*, e.g.
SIMCTL_CHILD_HP_AUTOKEY=start@40 make -f Makefile.ios sim-run

# Device
make -f Makefile.ios SDK=iphoneos -j4    # build/ios-iphoneos/HPAzkaban.app
python3 -I ios/sign_device.py            # signs with an existing local development profile
xcrun devicectl list devices
python3 -I ios/install_device.py --device <id> [--iso "iso/Harry Potter and the Prisoner of Azkaban (USA).iso"]
# or sign and run from Xcode:
make -f Makefile.ios SDK=iphoneos lib xcode && open ios/HPAzkaban.xcodeproj

Status of the iOS port (paused, October 2026):

  • Works in the simulator (iPhone 17 Pro, iOS 26): the app builds and links, installs, finds the ISO in Documents, loads the image, opens the disc and the memory card, starts the IOP and the GS, and writes Documents/hp.log.
  • Broken: the GPU renderer aborts within seconds. The simulator's Metal adapter falls short of some WebGPU default limits, so wgpu-native creates the device with its downlevel limits (4 storage buffers per shader stage; the GS shaders bind 7). Pipeline creation fails, and the first wgpuQueueSubmit panics. Next step: in third_party/ps2gs/src/gs/gpu/gpu.cpp init(), request min(supported, WebGPU default) for the limits the GS needs (maxStorageBuffersPerShaderStage first). On a Mac that requests exactly the defaults, so nothing changes there. Untested: SIMCTL_CHILD_HP_GS=soft should select the software GS instead.
  • Not tested yet: the touch overlay and the 4:3 presentation on screen, audio, pause/resume in the background, the "no ISO" dialog, the device build (SDK=iphoneos), signing, and Xcode project generation. The macOS build is unchanged; every iOS path is behind TARGET_OS_IOS.

Debugging knobs

Everything is controlled by environment variables read by the runtime. See the named source file for exact semantics. Sending SIGUSR1 to the process writes a diagnostic dump.

VariableAreaPurpose
HP_TRACEcore.cGuest execution trace level
HP_STATShw.cPeriodic DMA statistics
HP_SHOT, HP_SHOTFBdisplay.cSave frame / framebuffer screenshots
HP_VRAMDUMP, HP_RAMDUMP, HP_PEEKcore.cDump VRAM or RAM; HP_PEEK=addr:len,... (hex)
HP_WATCH, HP_WATCHRINGcore.cWatch a guest address for writes
HP_CALLTRACE, HP_CALLHISTcore.cCall tracing / call history
HP_PCRINGkernel.cRing buffer of recent program counters
HP_PRIMLOG, HP_PRIMSKIP, HP_PRIMAFTERgs.cLog GS primitives
HP_XFERLOG, HP_XFERAFTERgs.cLog GS image transfers (with the RAM address of the packet), from a vsync on
HP_TEXDUMP, HP_TEXDUMPATgs.cWrite each distinct texture the primitives sample (from a vsync on) as a PPM, with its last upload
HP_TBP0LOGgs.cReport indexed TEX0 setups with TBP0 = 0 (streamed mip levels); with HP_VUSNAP/HP_RAMDUMP also save the VU1 run / RAM
HP_SYNCLOGdma.cLog VIF1/GIF synchronisation (kicks, I-bit stalls, STC, FLUSHA, completions) for 30 vsyncs
HP_CRTLOGdma.cLog changes of the PCRTC registers (PMODE, SMODE2, DISPFB, DISPLAY) from a vsync on
HP_DUMPAT, HP_EXITAThw.cRun the SIGUSR1 dump at given vsyncs; exit at a vsync (bounded runs)
HP_VIFLOG, HP_GIFLOG, HP_QLOGhle.cLog VIF, GIF and queue activity
HP_AUTOKEY, HP_AUTOKEYVdisplay.cScripted key presses (cross@12,start@20:1 = hold 1 s; also circle, square, triangle, select, d-pad up/down/left/right, left stick lup/ldown/lleft/lright, lone/rone for L1/R1); with HP_AUTOKEYV=1 the times are emulated seconds (vsyncs / 59.94), so runs repeat on a loaded machine
HP_FASTBOOTfastboot.cFast test boot: 1 straight into the train corridor with cutscenes skipped, noskip, menu, save, load (see "Fast test runs")
HP_UISCRIPTfastboot.cMenu input that reacts to the GUI's FSCommands (wait:, press:, sleep:, exit)
HP_MEMCARDhw.cMemory card file (default build/memcard0.ps2; written ~1 s after the game stops writing, and on window close)
HP_ARGS, HP_ARGSLOGfastboot.cExtra game options (-startChapter=X -startRoom=Y -startDebugPoint=Z -nomovie ...); log every option lookup
HP_FSLOGfastboot.cLog the GUI's FSCommands and the cutscenes (start / end, with wall seconds)
HP_HEADLESScore.cRun without a window
HP_GS_THREADSgs.cNumber of rasterizer worker threads
HP_GS=gpu, HP_GSSYNCgs_bridge.cppGPU renderer; HP_GSSYNC waits for each displayed frame instead of showing the newest finished one
HP_GSREC, HP_GSRECMAXgs_bridge.cppRecord everything the GPU GS is given to a file (stops at HP_GSRECMAX MB, default 4000) for tools/gsreplay
HP_GPUVARIANTS, HP_FRAMEPOLLgpu.cpp, gs_bridge.cppHP_GPUVARIANTS=0 draws with the generic raster kernel only (2: specialise on frame/Z formats only); HP_FRAMEPOLL=0 hands frames on at the next request only
HP_GPUFLUSHLOG, HP_GPULOOSETEX, HP_DECODEMAX, HP_NOCLUTSKIP, HP_NODECODECACHEgpu.cppBatch-end causes and texture decode census; the old padded texel test; largest decoded texture (log2 texels, 16); load every CLUT; no decode reuse
HP_EXPgs.wgslSwitch parts of the raster kernel off (bits, see the shader) to measure what they cost on a trace
HP_PCRTC=singledisplay.c, gs_bridge.cppShow one read circuit only instead of merging both (PMODE MMOD/ALP; the game's deflicker: the same buffer one line apart, blended 50/50)
HP_GS=bothgs_bridge.cpp, display.cThe software GS draws and is shown, the GPU renderer gets the same packets; with HP_SHOT every screenshot frame_<v>.ppm gets a gpu_<v>.ppm of the same frame (exact renderer comparisons)
HP_GSSTATSgs.cCensus of the distinct GS drawing states (prim type, formats, TEST, ALPHA, DTHE, texture modes, render-to-texture): each new one is logged when first drawn, all with primitive counts at HP_EXITAT / SIGUSR1; both renderers
HP_CDLAT, HP_CDSEEKiop_servers.cEmulated disc read latency / seek time
HP_ISOiop_servers.cPath to the ISO image

A few more (HP_CLOCK, HP_SNDDUMP, HP_VUDUMP, HP_VIFTRACE, HP_CTX2LOG) are used for narrower investigations; grep for getenv.

Layout

recomp/    static recompiler (Python): r5900, elf, analyze, lift, main, hooks.txt
runtime/   host runtime (C): core, kernel, hw, dma, iop, iop_servers, gs, vif,
           vu1, ipu, display, hle
tools/     helper scripts: elfinfo.py, vram.py, vudis.py
Makefile   build driver
disc/ iso/ build/   your game files and generated output (git-ignored)

License and legal

Released under the GNU General Public License, version 3 or (at your option) any later version. See LICENSE. Parts of the runtime are ported from PCSX2 (GPL-3.0); see THIRD_PARTY.md for the list of borrowed pieces and their origins.

No copyrighted game data is included. Do not commit disc/, iso/ or build/. All trademarks belong to their respective owners.

View official project
CALIFICACIÓN
—
Loading votes…
Advertisement

PROJECT FILE

Project type
NATIVE PORT
Genre
Platformer
Status
alpha
Original platform
PlayStation 2
Technology
Native C/C++ port (engine reimplementation)
Version
—
Updated
—

Target platforms 1

macOS
View on GitHub
Advertisement