# SDL3 DOS Port (DJGPP)

In April 2026, [[sdl|SDL3]] gained native DOS support. [PR #15377](https://github.com/libsdl-org/SDL/pull/15377) by Anders Jenbo (AJenbo) — combined work with icculus, madebr, glebm, jayschwa, and ccawley2011 — landed on 2026-04-23: ~6,000 lines added across 58 files, building with DJGPP via a CMake cross-compilation toolchain. Tested extensively against [DevilutionX](https://github.com/diasurgical/devilutionX) inside DOSBox, with no real-hardware testing yet at merge time.

This means SDL3 games can now be cross-compiled to native DOS executables — a target the SDL ecosystem hadn't shipped in modern form. The earlier SDL 1.2 DOS effort never reached parity; SDL3's port is "fairly complete," missing only audio recording, a native `SDL_TIME` (it falls back to DJGPP's `gettimeofday`), and dynamic library loading (no `SDL_LoadObject`).

## What works

**Video**
- VGA framebuffer
- VESA 1.2+ framebuffer with hardware page-flipping and vsync
- RGB and 8-bit indexed color, with VGA DAC palette programming
- VBE state save/restore on exit (so quitting doesn't wreck the user's screen)

**Audio**
- Sound Blaster 16 — 16-bit stereo up to 44.1 kHz
- Sound Blaster Pro — 8-bit stereo up to 22 kHz
- Sound Blaster 2.0 / 1.x — 8-bit mono
- All via IRQ-driven DMA with double-buffered auto-init (the standard SB trick for glitch-free continuous playback)

**Input**
- PS/2 keyboard, including extended scancodes (the `0xE0` prefix that distinguishes things like right-Ctrl)
- INT 33h mouse driver, with sensitivity queried from the driver
- Gameport joystick via BIOS INT 15h, with auto-calibration

**Threading**
- Cooperative scheduler built on `setjmp` / `longjmp` with stack patching — conceptually borrowed from the SDL3 PS2 port
- Real mutexes, semaphores, TLS, and condition variables (generic fallback for the latter)
- Yield points in the event pump and delay functions keep audio and other cooperative threads responsive

**Timer**
- Native PIT-based timer using DJGPP's `uclock()`, ~1.19 MHz resolution

**Filesystem**
- `SDL_GetBasePath` / `SDL_GetPrefPath` via DJGPP's `searchpath()`
- POSIX filesystem ops as fallback

**Build infrastructure**
- CMake toolchain file `build-scripts/i586-pc-msdosdjgpp.cmake`
- Dedicated DJGPP CI job
- Preseed cache for faster cross-configure

## What's not included

- Audio recording (playback only)
- Native `SDL_TIME` implementation — uses DJGPP's POSIX `gettimeofday` instead
- Shared library loading (`SDL_LoadObject`) — DOS has no real dlopen equivalent that fits SDL's model

## How to build

```
cmake -S. -Bbuild-dos \
  -DCMAKE_TOOLCHAIN_FILE=build-scripts/i586-pc-msdosdjgpp.cmake \
  -DCMAKE_BUILD_TYPE=Release
cmake --build build-dos -j$(nproc)
```

You need a DJGPP toolchain on the host. The CI job in the SDL repo gives a working reference setup.

## Why this matters

SDL is the de-facto portability shim for cross-platform games. DOS being a supported SDL3 target means modern game code — written against SDL3 APIs — can be cross-compiled to a real DOS executable that runs on a 486-class machine (or, more commonly, on [[dosbox-detection-callback-opcode|DOSBox]]). DevilutionX, the open-source Diablo reimplementation, is the proof-of-concept used during development.

The threading bit is the most architecturally interesting piece. DOS has no preemptive threading; the only kernel is a 16-bit single-tasking BIOS plus whatever the runtime brings. SDL's port builds full thread primitives (mutexes/sema/TLS/condvars) on top of a cooperative scheduler that swaps stack frames via `setjmp` / `longjmp` and explicit yield points scattered through the event loop and delay paths. That's enough to make audio threads stay responsive without preemption — which is what real SB16-era games already had to do by hand, but now wrapped in SDL's portable thread API.

## Related

- [[sdl]] — the SDL project itself
- [[dosbox-detection-callback-opcode]] — Snow's post on detecting DOSBox; this PR was largely tested inside DOSBox
- [[early-dos-paterson-listings]] — adjacent April 2026 retro-DOS news: Microsoft's release of recovered 86-DOS / PC-DOS 1.00 source listings from Tim Paterson
- [[win32-stable-abi]] — adjacent "old binary platforms in 2026" theme: Wine/Win32 as the only stable Linux ABI for games
