- Game Logic
I reversed engineered the game logic and reimplemented the full game state machine in C:
- Player movement
- Enemy spawning patterns (Game A and Game B)
- Score and miss counter
- Game over logic
- Built-in clock and alarm
- Graphics Pipeline
The original CJ-71 uses a color filter overlay on a monochrome LCD. Each sprite is a fixed
segment. To reproduce this on a TFT:
- Sprites extracted from MAME artwork assets, converted to **RGB332** (1 byte/pixel) stored in flash
- Transparent pixels use `0x00` as sentinel
- Scenery background (471×238) centered on 480×320 display
- XOR blitting over scenery, deferred flush with union bounding box
- DMA double buffering for tear-free rendering
A Python asset pipeline (`gen_sprites.py`) handles extraction, color conversion, and C header generation.
- Audio
The SM511 melody ROM (256 bytes) was extracted from MAME. Rather than emulating the SM511
audio engine at runtime, I decoded the melody ROM offline into a table of `(freq_hz, duration_ms)`
note pairs — full audio fidelity with no runtime SM511 dependency.
On the Pico, **Core1** is dedicated to audio, generating square waves on GP8 via
`busy_wait_until()` for drift-free timing. All audio code runs from RAM to avoid flash latency.
The original CJ-71 audio circuit uses a PNP transistor (C458) in a negative-supply design to
drive the piezo. On the Pico, a direct GPIO connection proved sufficient — the piezo pressed
against the original plastic shell acts as a natural resonator and amplifier.
Kalice
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.