Porting a 1993 Amiga Game to Godot Using an LLM to Read 68000 Assembly
TL;DR
Claude Fable 5 successfully ported the 1993 Amiga title Babylonian Twins to Godot 4, automatically translating both the original 68000 assembly (72,758 lines) and the later 2010 C++ engine (34,000 lines). The AI reconstructed undocumented file formats, reproduced the exact original binaries, and exposed decades‑old bugs that had never been discovered.
Why the experiment mattered
The author wanted to test whether a modern LLM could understand undocumented 68 k assembly that never appeared in training data. By giving Claude the full Amiga source, assets, and build tools, the author could compare the AI‑generated port against the original binaries byte‑for‑byte, providing a concrete benchmark for LLMs on low‑level reverse‑engineering tasks.
Step 1 – Porting the 2010 C++ engine in under an hour
- Result: A playable Godot project was scaffolded in 21 minutes, reproducing the entire 34 k‑line C++ codebase.
- Key insight: The AI kept the original fixed‑tick logic (60 Hz) and did not replace the custom movement code with Godot’s
CharacterBody2D. Preserving the hand‑written collision routine avoided subtle physics mismatches. - Technical note: The original game used a multiplicative drag factor (
velocity.x *= 0.85each tick). Because the original ran at 50 Hz, the same constant would feel wrong at 60 Hz. The AI kept the two tick rates separate, preserving the original feel.
Step 2 – Rebuilding the 68000 assembly automatically
- Result: Claude reconstructed the 1993 source, assembled it with
vasm, and produced binaries that were byte‑identical to the shipped Amiga disks. - How it worked: The model wrote a preprocessing pass to bridge dialect differences between ASM‑One and
vasm(e.g.,cmp #4,d0encoding) and generated a script that fixed broken filename mappings caused by a 2008 transfer. orghandling: The AI learned that the original used manual memory layout (org $6a000) without a linker. It correctly reproduced the layout, except for oneds.b 800block where ASM‑One’s “skip” semantics differed; the AI initially emitted 800 zero bytes, shifting subsequent data by 944 bytes. The error was caught when the rebuilt demo rendered the wrong graphics.- Variable‑area delta: About 108 bytes differed because the shipped binaries were snapshots of RAM after a run, while a fresh assembly left those variables at zero. The AI explained that the code writes those variables before reading them, so the discrepancy is harmless.
Decoding the undocumented formats
Level maps
- The level loader consists of 1,652 lines of undocumented 68000 code. The AI inferred the tile‑grid format (no header, compressed chunk) by tracing the draw routine and extracting width/height constants.
- It regenerated all five levels, rendered them to PNG, and performed pixel‑perfect comparison against the author’s 2020 screenshots. Two mismatches (sky gradient and water colour cycle) were traced to missing copper‑list data, which the AI then added.
Map‑cell properties
- Each 16‑bit cell packs a 6‑bit property, a bank‑select bit, and an 8‑bit tile index. The AI discovered the property bits by analysing both the drawing loop (masking low byte) and the collision routine (masking high bits). It reconstructed the full property table, including solid ground, climbable tiles, damage codes, doors, and kill zones.
Object tables
- Objects are stored per‑screen in a custom table. The AI identified markers (
$1111= empty screen,$2222= dead object) and decoded behaviour offsets such ashiddenwallR‑lrb. It then converted all object coordinates to world space and verified them against the rendered maps.
Copper‑list sky gradient
- The sky colour is generated by a copper list that writes a series of colour words (e.g.,
dc.w $09FF,$09EF,…). The AI extracted the 24‑word gradient for level 2, rendered it as vertical bands, and re‑added it to the port after the initial build omitted it.
Sprite‑sheet ambiguity
- Amiga sprites are stored as planar bit‑planes. The AI detected an ambiguity in the sheet size (
frames * width * height * 2 * 5) and asked the author for clarification. The correct interpretation was two stacked rows, one per facing direction, which the AI then decoded.
Step 3 – Embedding the original as a guest inside the modern build
- Within a single evening, the AI added a “guest” mode that launches the 1993 game at 50 Hz inside the Godot executable, switching back to 60 Hz when the player returns to the modern version.
- All assets (PNG, WAV, JSON) were extracted once by Python scripts; behaviour was re‑implemented in GDScript.
- The final Steam release ships the modern game plus the original Amiga version as a second launch option.
Bugs uncovered by the AI‑driven port
| Bug | Original symptom | AI‑generated fix |
|---|---|---|
| Guard shove range | Guard on a high platform shoved the player through solid rock in level 2. | Restored missing upper‑bound check (cmp.w #4,d4; bpl Sg.Far). |
| Hidden door tiles | Doors appeared as empty sky because they are drawn by runtime code, not stored in the map. | Added runtime door‑drawing routine to the port. |
| Trampoline physics | Jump felt too high on modern build. | Discovered that a held‑jump flag from the 2010 iOS build caused a release‑on‑press mismatch; corrected input handling in Godot. |
| Sprite‑sheet orientation | AI initially mirrored the twin’s facing direction. | Clarified that the original sheet contains two rows (left/right) and kept the correct orientation. |
| Missing sky gradient | First rebuild rendered a flat sky. | Re‑added copper‑list colour table, eliminating pixel‑diff warnings. |
Release workflow automated by the LLM
- The AI generated command‑line flags (
--level,--pose,--drive,--probe,--screenshot) to enable headless testing and scripted gameplay. - It produced screenshots at all required store resolutions, launched the game in each language, and captured in‑game captions using the real fonts.
- Store metadata (titles, descriptions, icons) were filled automatically; only a manual login was required for Steam’s web dashboard.
- Reviews were scraped from Google Play, parsed, and any bug‑reporting reviews (e.g., a one‑star “cant get through door on level one”) were surfaced for immediate fixing.
Community reaction (selected HN comments)
mattjoyce: “I downloaded a ZX81 memory dump and asked Claude to rebuild it in Go. It nailed it.” – Highlights the broader potential of LLMs for retro‑computing archaeology.
hedgehog: “It would be interesting to have Claude export an engineering guide for similar ports.” – Suggests that the workflow itself could become a reusable blueprint.
robviren: “The amount of non‑standard, hackish code from the past feels impossibly complicated to touch today.” – Underscores how the AI bridged a 30‑year knowledge gap.
coder‑pm: “Did you ever run the port against the original in UAE with the same inputs?” – Points to a valuable future validation step; the author confirmed pixel‑by‑pixel diff checks were performed.
What this means for future retro ports
- Feasibility: An LLM can read undocumented 68 k assembly, reconstruct missing formats, and produce a faithful modern port with minimal human guidance.
- Speed: The entire pipeline—from source import to a working Godot build—took roughly 5 hours of continuous AI execution, far faster than a manual rewrite would have required.
- Preservation: Byte‑identical rebuilds guarantee that the original game can be archived, studied, and executed on modern hardware without loss of authenticity.
- Bug discovery: Automated reverse‑engineering surfaced bugs that had survived undetected for three decades, demonstrating a practical benefit beyond mere code translation.
Where to play the games
- Original 1993 Amiga version: Free disk image on itch.io (run with FS‑UAE, WinUAE, or real hardware).
- Definitive Edition (Godot 4): Available on iOS, Android, and (Fall 2026) on Steam, with the 1993 version bundled as a secondary launch option.
The port was driven by Claude Fable 5 running in Claude Code; the author supplied notes, repos, and the original binaries, and the AI produced the first draft of this article, which was then edited line‑by‑line.
Sources
Related
- Project
- Dispatch
- Dispatch
- Dispatch
- Dispatch