From 68000 Assembly to Godot: How I Ported a 1993 Amiga Game with LLM Assistance
I tackled the challenge of translating a 1993 Amiga game written in 68000 assembly into a modern Godot project, leveraging an LLM to auto‑translate low‑level code into high‑level logic. The result was a playable, maintainable remake that preserved the original feel while embracing Godot’s scene system and GDScript.

From 68000 Assembly to Godot: How I Ported a 1993 Amiga Game with LLM Assistance
Overview
In 1993, I wrote a small action‑platformer for the Amiga using the 68000 CPU and custom graphics routines. Fast forward to 2026: I wanted to bring that title to modern devices, but the original assembly was a nightmare to understand and port. The key insight was to use a large language model (LLM) to read the assembly, generate equivalent high‑level pseudocode, and then hand‑craft Godot scenes that mirror the original mechanics.
Core Challenges
- Opaque 68000 Assembly: No source comments, heavily optimized loops, and inline graphics blitting.
- Legacy Graphics & Sound: 512‑color chunky mode, custom sprite hardware, and Amiga’s Paula sound chip.
- Stateful Game Loop: Tight coupling of rendering, physics, and AI in a single 68000 routine.
- Modern Tooling Gap: Godot’s scene system expects modular nodes, not monolithic assembly.
High‑Level Architecture
1
2┌───────────────────────┐
3│ LLM Pipeline (Python) │
4│ - Assembly → AST │
5│ - AST → GDScript │
6└─────────────┬─────────┘
7 │
8┌─────────────▼─────────┐
9│ Godot Project (GDScript) │
10│ ├─ Player.tscn │
11│ ├─ Enemy.tscn │
12│ ├─ Level.tscn │
13│ └─ AudioManager.tscn │
14└───────────────────────┘The LLM acts as a translator, producing a skeletal GDScript file for each major subsystem. I then refactor these into Godot scenes, wiring them together with signals and a central ``GameManager node.
LLM Assisted Assembly Parsing
I built a small Python harness that feeds the assembly into OpenAI’s GPT‑4o. The prompt explicitly asks for a line‑by‑line pseudocode explanation and a GDScript skeleton.
1import openai
2
3assembly_code = open("original.asm").read()
4prompt = f"Translate the following 68000 assembly into GDScript skeleton code. Provide line‑by‑line comments and explain the logic.\n\n{assembly_code}"
5
6response = openai.ChatCompletion.create(
7 model="gpt-4o",
8 messages=[{"role": "user", "content": prompt}],
9 temperature=0.0,
10)
11print(response.choices[0].message.content)The model outputs a ``player.gd with methods like _physics_process(delta) and _draw(). I then copy that into a Godot script file and replace the placeholder logic with real physics.
Recreating Graphics & Sound
Graphics
The original used chunky mode 1, 512 colors. I exported the sprite sheets from the Amiga’s .iff files using a custom converter:
1python convert_sprites.py --input game.spr --output sprites/ --format pngIn Godot, I import these PNGs and create a ``Sprite2D node per sprite. The LLM helped me map the original sprite flip and palette logic to Godot’s flip_h, flip_v, and modulate properties.
Sound
Paula’s 8‑bit samples were stored as raw PCM. I used ffmpeg to convert them:
1ffmpeg -f s16le -ar 44100 -i samples.raw output.wavGodot’s ``AudioStreamPlayer now plays these WAVs. The LLM suggested a simple envelope to emulate Paula’s filter.
Godot Integration
I structured the game around a GameManager node that loads the level, spawns the player, and manages global timers.
1// GameManager.gd
2extends Node
3
4var player
5var level
6
7func _ready():
8 level = preload("res://Level.tscn").instantiate()
9 add_child(level)
10 player = preload("res://Player.tscn").instantiate()
11 add_child(player)
12 player.position = level.spawn_pointThe ``Player scene contains a KinematicBody2D with a CollisionShape2D, a Sprite2D, and an AnimationPlayer. The LLM generated an initial _physics_process that I refined with Godot’s move_and_slide().
Performance & Optimization
Because the original code ran on a 68000 at 7.16 MHz, my Godot version runs at 60 fps on a Raspberry Pi 4. I kept the frame budget tight by:
- Using Godot’s
TileMapfor static level geometry. - Caching sprite frames in a
SpriteFramesresource. - Offloading AI to a simple state machine written in TypeScript for Node‑based hot‑reloading.
1// ai-state.ts
2export enum State { IDLE, PATROL, CHASE }
3export class AI {
4 state: State = State.IDLE
5 update(delta: number) {
6 switch (this.state) {
7 case State.IDLE:
8 // logic
9 break
10 // ...
11 }
12 }
13}The TypeScript AI is compiled to JavaScript and injected into Godot via ``GodotJS plugin, allowing me to iterate quickly.
Pros & Cons
| Pro | Con |
|---|---|
| Rapid Translation – LLM cuts hours of manual reverse‑engineering. | Model Bias – The LLM may misinterpret obfuscated assembly, requiring manual verification. |
| Modern Toolchain – Godot’s scene system simplifies future feature additions. | Performance Overhead – High‑level abstractions can be slower than hand‑optimized assembly. |
| Cross‑Platform – Target iOS, Android, Web, and Desktop with one codebase. | Learning Curve – Team must learn Godot’s GDScript and scene graph. |
Takeaways
- LLMs are powerful assistants for legacy code – Treat the model as a first‑pass translator; never trust it blindly. 2. Leverage Godot’s modularity – Break the original monolithic loop into nodes; this improves maintainability. 3. Automate asset conversion – Small scripts can convert legacy formats into modern ones, saving hours. 4. Keep performance in mind – Profiling early helps spot bottlenecks introduced by the abstraction layer.
Further Reading
- [Godot 4.2 Docs – TileMaps](https://docs.godotengine.org/en/stable/tutorials/2d/tilemaps.html)
- [OpenAI API – Prompt Engineering for Code](https://platform.openai.com/docs/guides/code)
- [Paula Sound Chip Emulation](https://www.hardrec.org/paula.html)
Happy porting, and may your LLM be ever helpful!
Written by Piyush Kalsariya
Full-stack software engineer and AI automation builder specializing in Next.js, Node.js, Python, Sanity CMS, and production LLM orchestration.