-
Notifications
You must be signed in to change notification settings - Fork 0
Emulator atari800
The Atari 800XL bundle is the only one in GenX-DOS where we ended up compiling the emulator from source, because nothing else fit.
The shortlist was three projects. All three fell out, in order:
-
jsA8E (
AnimaInCorpore/A8E) — looked promising; a real WASM build of A8E, working in a browser. NoLICENSEfile in the repo, though. Under default copyright we can't legally redistribute, so it was out. -
EmulatorJS — covers a lot of ground but the upstream supported-systems list does not include Atari 800; the closest core is
a5200. No good. -
libretro-atari800 in the official RetroArch emscripten nightly — plausible because the same nightly ships ~90 other cores. We downloaded the full 760 MB
RetroArch.7zfrombuildbot.libretro.com/nightly/emscripten/RetroArch.7zto verify. atari800 is not one of the cores in the web build. (Useful side-effect: that audit confirmed VICE, gearcoleco, and o2em are in there, which seeded the C64 / Coleco / Odyssey² bundles we did later.)
So we built atari800 from source.
emscripten via emsdk, fetched into /tmp because the build needs to be reproducible and that's the path the recipe encodes:
cd /tmp && git clone --depth 1 https://github.com/emscripten-core/emsdk.git
cd /tmp/emsdk && ./emsdk install latest && ./emsdk activate latest
source /tmp/emsdk/emsdk_env.shemsdk lives at ~/emsdk/ on this machine for persistence between sessions.
atari800's autoconf uses AM_PATH_SDL2, which shells out to sdl2-config. emscripten ships SDL2 as a port (it's pulled in automatically by -sUSE_SDL=2) but doesn't ship the sdl2-config binary. The build dies on detection before it even gets to the C files.
The fix was a six-line shim that pretends to be sdl2-config and tells autoconf whatever it wants to hear:
cat > /tmp/fake-sdl2-config <<'EOF'
#!/bin/sh
case "$1" in
--cflags|--cflags-only-I|--libs|--libs-only-l|--static-libs|--prefix) echo "" ;;
--version) echo "2.30.0" ;;
esac
EOF
chmod +x /tmp/fake-sdl2-configThen SDL2_CONFIG=/tmp/fake-sdl2-config emconfigure ./configure … runs cleanly.
SDL2_CONFIG=/tmp/fake-sdl2-config emconfigure ./configure \
--target=default \
--with-video=sdl2 \
--with-sound=sdl2 \
--without-opengl \
--disable-netsio \
--disable-riodevice --disable-rserial --disable-rnetwork \
--disable-audiorecording --disable-videorecording \
--enable-altirra_bios \
CFLAGS="-O2 -sUSE_SDL=2" LIBS="-sUSE_SDL=2"Why each flag is there:
-
--without-opengl— atari800's SDL+GL path callseglCreateContext, which fails in emscripten and leaves the canvas black. The software SDL renderer works fine. -
--disable-netsio/--disable-riodevice/--disable-rserial/--disable-rnetwork— these all needclock_gettimeor a real host TTY/serial port, both of which trip emcc's strict implicit-declaration check. Nothing about them works in a browser anyway. -
--disable-audiorecording/--disable-videorecording— strips RLE/ZMBV/WAV/ADPCM/μ-law codecs we don't need. -
--enable-altirra_bios— this is the big one. It bakes Avery Lee's AltirraOS-XL 3.41 directly into the WASM. No copyrighted Atari OS ROM needs to ship alongside the bundle; the emulator falls back to AltirraOS automatically when no real ROM is found. This is also whyemulators/atari800/has noroms/directory full of.binfiles — the OS lives insideatari800.wasm. -
-sUSE_SDL=2— pulls emscripten's SDL2 port for canvas, keyboard, and WebAudio.
The plain emmake make builds a Node-style src/atari800 script, not a browser-loadable bundle. To get the browser artefacts:
cd src
OBJS=$(ls atari800-*.o sdl/atari800-*.o roms/atari800-*.o codecs/atari800-*.o atari_ntsc/atari800-*.o 2>/dev/null | grep -v video_gl)
emcc -O2 -sUSE_SDL=2 -sASYNCIFY -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=64MB \
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap,FS -sEXIT_RUNTIME=0 \
-o atari800.html $OBJS -lm-sASYNCIFY is non-optional. atari800's for(;;) main loop in sdl/main.c would hang the browser without it. ASYNCIFY suspends and resumes at SDL_Delay so the page can paint between frames.
Output: atari800.js (186 KB) + atari800.wasm (1.7 MB). The default emcc shell HTML gets thrown away — play.html replaces it.
play.html sets up window.Module before injecting atari800.js:
-
canvas— the<canvas>element -
arguments—['/game.atr']for disks,['-cart', '/game.rom']for cartridges, optionally['-cart-type', N, '-cart', '/game.rom']for headerless cart dumps (Star Raiders needscartType:1= Standard 8KB) -
preRun— callsModule.FS.createPreloadedFile('/', vfsName, romUrl, true, false)to fetch the ROM into the WASM virtual FS beforemain()runs
The Star Raiders .atr shipped as a8b_Star_Raiders_1979_Atari_US_k_file is a cart-binary-in-disk-wrapper — it boots straight into a 6502 CIM at $A184. The right source is the 8 KB .rom from a8b_cart_Star_Raiders_1979_Atari_US, launched with -cart-type 1.
Headless chromium screenshots of SDL2/WASM canvases look black even when frames are being drawn — SwiftShader/compositor timing makes them unreliable. Verify in a real browser, or read pixels via getImageData from a probe page.
emulators/atari800/
├── play.html
├── atari800.js
├── atari800.wasm ← AltirraOS baked in here
├── games.json
├── controls.html
├── build-wasm.sh ← reproducible build recipe
└── roms/ ← cart / disk / cassette images
The reproducible build script lives in the Retro-Jack/atari800 fork — upstream source untouched, just build-wasm.sh + BUILDING-WASM.md on top.
- Emulators — index of all engines
- Emulator-XRoar-CoCo — the other from-source emscripten build
- File-Structure — where bundles sit in the repo