A personal reverse-engineering and porting study by Pascal Peltriaux. The original game's NEC V30 code is translated, instruction by instruction, to the Neo Geo's Motorola 68000, and everything it sends to Irem's video hardware is redrawn with the Neo Geo's sprite engine. On top of that program runs a co-op mode: both players fly at once, on the original's own player code.
Direct captures of the port's video and sound at the console's native 320×224, scaled 4× with no filtering; the sound is the Neo Geo's YM2610 playing the port's FM driver. The play is scripted: a run is replayed from power-on with new steering every 90 frames until it goes through without a lost ship, then captured.
100 s Two-player co-op with the weighted view camera: a 2P start from the title, the fly-in with the 1P and 2P tags, the beam gauge split between the players, stage 1 up to its green walker, then stage 3 from its fly-in to the warship. Watch the window lean toward the enemies while both ships stay in view.
71 s Armour mode, one player, with the weighted view camera: ARMOUR picked on the start screen, then stage 1 where a hit takes the gauge from green to yellow without ending the game, and stage 2's cave where two more take it to red, the worms on the last ship.
45 s Power-on and attract mode: the Neo Geo BIOS boot, then the original's attract sequence (title, demo play, ranking) running through the translated code.
The arcade board is an Irem M72: a NEC V30 (an x86-compatible CPU) driving two tile layers, a sprite list and a palette RAM. The Neo Geo has a Motorola 68000, no tile layers at all, and 381 hardware sprites that can be chained into columns. The port keeps the original program and replaces its hardware.
A translator (Python, built on the Capstone disassembler) walks the original's code from its interrupt handler and main loop and emits 68000 assembly for every instruction it reaches: about 21,700 x86 instructions. The x86 flags live in the 68000's condition codes, with a liveness pass that saves and restores them only where a later instruction would need them. Segment registers, far calls, string instructions, BCD arithmetic and the V30's own extra instructions are all covered.
The translated code runs against a byte-exact copy of the original's memory: its program ROM image, 16 KB of work RAM, sprite RAM and palette RAM. Every 16-bit word is stored byte-swapped so that the big-endian 68000 reads the little-endian game's words as single moves.
The original writes a 128-entry sprite list, two 64×64 tilemaps and a palette. On the Neo Geo:
Translated code reports what it wrote, so changed tile groups are queued and redrawn in the next VBlank, and only then.
As on the board, the original's start-up code runs once, its main loop then pops tasks from its own queue forever, and the Neo Geo VBlank interrupt runs the original's interrupt handler wherever the main loop happens to be. Long tasks such as screen fills and map streaming span several frames exactly as they did in the arcade. The game gets every Neo Geo frame (59.19 Hz against the original's 55 Hz), so it plays a little faster but scrolls evenly.
Translated code is slower than native code, so the few shared routines every object calls each frame were rewritten in 68000 by hand from a description of what they do: the hit tests (with a broad phase that rejects most candidates before the original's chain of tests), the sprite piece writers, the palette fader, the tilemap clears and the map block streamer. The interrupt handler's object loops are native too, with a per-slot cache of each object's handler address. Everything else is the translation.
The arcade game is single-player with alternating turns. The co-op mode here runs the original's own player code a second time each frame, with player 2's copy of the player objects (ship, Force, shots, beam) swapped in. Player 2 flies a crimson R-9; its shots hit and score for it, enemies can hit it, and the items it touches are its own.
No player logic was rewritten. Each frame the handler runs player 1's code, then the port swaps in player 2's copy of the player objects and runs the same code again. Hooks at a handful of addresses make the original's "the player" mean the right ship: hit tests check both, items go to the one that touched them, and the HUD draws two scores.
A second rule set for the cabinet, picked on the start screen with up or down next to the stage select (the CREDIT line reads CLASSIC or ARMOUR; the choice stays until changed). The original's rule is unforgiving: one hit, one ship, back to the checkpoint. In Armour a hit with more than one ship left costs a ship and one level of the Force's laser, and the game goes on where it is: the ship blinks for two seconds, cannot be hit and passes through terrain, then play resumes. The last ship's hit is the original's death, with its game over, continue and checkpoint. In co-op each player has their own ships.
The hit routine is hooked at one address: with ships to spare it decrements the ship count and the laser level, sets the original's own "just in" state that it uses after a fly-in (blink, no hits, terrain pass-through) for 120 frames, and returns before the death path. Everything else, including what happens when the grace runs out inside a wall, is the original's behaviour.






The third mode on the start screen, after CLASSIC and ARMOUR: the seven bosses one after another, every ship fully armed, against the clock. The rules are the arcade version's, played by the same translated program.
The HUD's score row shows the run's time, mm:ss.cc, where the high score sits in a normal game. It counts the Neo Geo's own frames, real time: when the game slows down in a busy fight, that counts too. It runs through deaths, pauses from GAME OVER through the continue countdown, holds from a boss's fall to the next fight, and stops at the last boss, its total on screen through the ending.
When a run ends, a panel lists each boss's time, the total, the bosses beaten and the continues used, and the name entry follows. Runs rank by bosses beaten, then fewer continues, then time, in a table of their own: Boss Rush scores stay out of the game's ranking and high score. The attract mode shows both tables in turn; a two-player run is marked 2P in player 2's crimson.
Both tables survive power-off in the MVS's backup RAM. The BIOS keeps nothing of a game's work RAM there, so the port writes its own block in the cabinet's save slot: two copies, each with a sequence number and a checksum, so a power cut in the middle of a write leaves the other one.





The M72 draws 384×256 pixels at 55 Hz; the Neo Geo shows 320×224 at 59.19 Hz. Keeping the arcade's picture on the smaller screen was the one place where the port could not simply replace hardware, and every option cost something. The answer, in two steps: a window that keeps the ship whole, then one that also looks where the enemies are.
The window now slides over the playfield to follow the ship, within limits: 16 pixels either way sideways and the full 32 lines vertically, easing in and out at up to three quarters of a pixel per frame. At rest it is the original fixed window, so the game looks the same until the ship pushes an edge. At the back the ship is whole bar four pixels, at the top and bottom it is whole; the price is that the hidden strip moves to the far side while the player is retreating. Only a playing ship moves it: fly-ins, deaths, the attract demo, the text screens and a stage clear (from the boss's fall, so STAGE CLEARED is centred) stay at rest, and in co-op the window follows whichever ship is furthest back and highest.
In the program this is two words, the window's offset, folded into the tile layers' scroll values and subtracted from each sprite's position in the VBlank drawing. The original's code never sees it, and the HUD band on the fix layer does not move.
Following the ship alone still left the window pointing at empty space while enemies sat in the hidden strip. So within the range the ship allows, the window now settles where it shows the most of the original's enemy list: each enemy counts 3 per visible pixel, each bullet 1, the starfield and explosions nothing. The score of every candidate position is summed in one pass over the 94 object records, and the target only moves when another position shows two thirds of an enemy more, so the window repositions every few seconds rather than drifting. It glides there: its speed builds up by a thirty-second of a pixel each frame to three quarters of a pixel, and it brakes in time to stop on the target. Only when the ship has moved past its margin faster than that does the window follow it at up to four pixels a frame, which keeps the ship whole on a fast retreat.
The rule was chosen by measurement: a scripted run of the arcade original was recorded with its object list every frame and replayed through candidate rules offline. Against following the ship, the weighted window leaves about a third fewer enemies fully out of view on stage 1 and 2 and a sixth fewer over the whole game, with the same number of direction changes. Which of the original's object handlers are enemies, bullets, explosions or invisible controllers is data in a text file, profiled from a play-through of all eight stages, and a model in the test suite recomputes the camera's target from the same records after every frame and compares.


| Translated instructions | about 21,700 (everything reachable from the interrupt handler and the main loop) |
|---|---|
| Hand-written routines | 22 shared routines plus the interrupt's object loops; everything else is machine translation |
| Cartridge | 1 MB program ROM, no bank switching; the original's ROM image sits inside it |
| Frames run late | 42 of 5,160 in a profile run of attract mode and play (single player); 495 in co-op, mostly on the stage 2 snake |
| Interrupt handler | 81% of a frame in busy scenes; when four or more tasks are waiting, every other VBlank is left to the main loop so the game slows down instead of dropping tasks, as the original's 64-entry queue would |
| Frame rate | 59.19 Hz (every Neo Geo frame) against the original's 55 Hz |
| Window | 320×208 of the arcade's 384×240 playfield at 1:1, bounded by the ship (24 px / 12 lines from its edges) over 64 pixels of travel sideways and 32 lines vertically, aimed at the most enemy pixels, one pixel per frame; the targeting costs about 5 of the 264 scanlines a frame |
| Tested on | MAME 0.289 and a JAMMA arcade cabinet (libretro MAME 0.258) |
Native 320×224 frames, shown pixel for pixel.




















A harness records 300 frames of the original in MAME (its memory at one VBlank interrupt, then every port access per frame) and replays them through the translated code on the emulated Neo Geo. Each frame, 16-bit checksums of every 256-byte block of work RAM and both tilemaps are compared with the original's. Result: all 300 frames identical.
Each native routine keeps the original's exact memory, register and flag results, and is tested against its translated counterpart. The hit-test broad phase runs both ways in a check build and counts disagreements: none in 3,900 frames of play. A sprite check rebuilds the Neo Geo's sprite memory from a write tap and compares every object sprite against a model of the sprite list after every frame: 0 mismatches in about 715,000 checks.
Automated runs play attract mode and games in MAME, checking that nothing untranslated ran, that coins and starts worked, that fewer than 10% of frames ran late, and that music and effects played. A camera run pushes the ship to every edge and checks the window's stops, its one-pixel-per-frame motion, that the ship is drawn at the back, and that it rests after a death and through the attract demo. Every stage was also recorded on its own to check the tile layers against the original's maps.
The cartridge image runs under MAME's Neo Geo MVS emulation and on a JAMMA arcade cabinet. It uses only documented Neo Geo features; no flash cart or custom hardware is involved.
These are concept mock-ups, not products. No box, cartridge or label was ever made, and none will be. The images were generated with an AI image model from the port's own screenshots (the title logo, the two ships, the stage 1 boss) to imagine what a home-console release might have looked like, in the style of late-1980s airbrushed arcade flyers. The cartridge shell was drawn from a public-domain photograph of a Neo Geo AES cartridge (Evan-Amos, Wikimedia Commons). Any resemblance to real packaging of the period is the point of the exercise, not a claim.
This is a private, non-commercial technical study. It exists to show that an arcade program of this era can be translated to a different CPU and have its video hardware re-created on another console, and to explore a two-player mode and a second rule set on top of it. Nothing of it is sold, licensed or distributed.