# Sprinter C Compiler — Release Notes ## v1.0 (2026-06-01) First public release. Production-ready toolchain for writing C programs that target Sprinter / ESTEX DSS. Built on top of vendored SDCC 4.5; this repository adds everything Sprinter-specific. ### Highlights * **One-line builds:** `sprinter-cc -o foo.exe foo.c` — pulls in crt0, libsprinter, packs the resulting .ihx into a SprintEXE. * **27 working examples** covering every API surface — used as regression tests while the toolchain was developed. * **Five memory modes** (`tiny / small / big / huge / manual`) handle programs from a few KB up to 32 KB of code + arbitrarily many 16 KB banks. * **Full Sprinter API coverage**: console, files & directories, environment, date/time, mouse, graphics (both 320×256×256 and 640×256×16 modes including the hardware accelerator), bitmap-font text, banking, paging. ### Component versions * SDCC: 4.5.0 (vendored binary) * SprintEXE format: as documented in `docs/converted/ProgrammerManual.txt` * MAME: 0.283 with `sprinter` driver (vendored at `mame/v306/mame.arm`) * DSS / ESTEX: 1.71.57 (matches `mame/v306/IMG/dss171u.img`) ### What's included Toolchain: * `bin/sprinter-cc` — Bash driver * `toolchain/mkexe/mkexe` — host C utility, packs `.ihx` → `.exe` * `toolchain/check_banks.py` — post-link bank size enforcement Runtime (`runtime/`): * `crt0.s` — default startup for tiny / big modes, parses argv * `crt0_minimal.s` — opt-out for very small programs (no argv) * `crt0_small.s` — for small / huge modes, allocates W2 via ESTEX `$3A` * `crt0_banked.s` — parameterised: handles W3 banks (huge) or W1 banks (big) via assemble-time `BANK_W1` flag * `bank.s` — `___sdcc_bcall_ehl` trampoline (banking-aware, preserves uint8_t return value in A) * `heap.s` + `heap_top.s` — 32 KB W2-resident heap, configurable upper bound via `sprinter-cc --stack-size` Libraries (`libc/`): * `libsprinter.lib` archives: io (open/read/lseek/close/unlink/stat/atexit/setjmp/ errno/sleep/time/env/conio/fsdir/dir/mouse), stdio (putchar/puts/getchar/print_hex/ file/cprintf/solid_helpers), mem (mem_alloc/bank_io), gfx (gfx_core/gfx_lines/ gfx_16/gfx_text) Headers (`libc/include/`): * Standard: `stdio.h`, `unistd.h`, `fcntl.h`, `errno.h`, `time.h`, `sys/stat.h` * Sprinter-specific: `conio.h`, `gfx.h`, `mouse.h`, `dir.h`, `sprinter.h`, `sprinter_exit.h`, `sprinter_mem.h` * Compatibility: `sprinter_compat.h` — Solid-C aliases and types Examples (27 in `examples/`): * I/O: hello, argv, cat, seek, ls, filetest, stattest, errno * Memory & banking: mem_test, malloc, banked, bankedbg, banklocl * Mouse: mouse, gfx_mous * Graphics: gfx_demo, gfx_d16, gfx_text * Misc: timedir, ptime, openenv, conio, attrprob, strtest, stdlib, assrtest, rt_test Documentation (`docs/`): * `TODO.md` — roadmap, v2 plans * `solid_c_compatibility.md` — Solid-C compatibility gap analysis * `im2_isr_design.md` — interrupt design (v2) * `converted/` — searchable plain-text copies of original Russian documentation ### Notable design decisions * **DSS allocates pages by program size** — `< 16 KB` programs get only one 16 KB page. Memory modes encode the four possible layouts. * **One libsprinter.lib for all modes** — SDCC's linker drops unused .rel members, so a `tiny` hello program only pulls in what it needs (~700 bytes overhead). * **Banking trampoline ABI**: 1-byte saved page + 2-byte bjump return between the bcall ret and the callee's stack arguments. `pop bc; out (c), b` on the way back preserves A (a previous version clobbered A and silently lost uint8_t return values). * **Text I/O is Turbo-C-style split**: `puts/printf/putchar` (fast, via PCHARS) ignore text attribute; `cputs/cprintf/putch` apply `g_text_attr`. Same convention as Borland C 2.x — programs port over with minimal changes. * **Graphics accelerator**: the `LD D,D / LD C,C / LD E,E / LD B,B` instruction trick is wrapped in self-modifying-code primitives in `gfx_lines.c` (the block length byte must literally follow `LD A,#imm`; we patch it at runtime). * **Mouse cursor format** (verified empirically): 1 byte per pixel, `0xFF = transparent`; the driver stores the bitmap in a dedicated video bank. * **Video mode bitmaps**: BIOS font is **interleaved** — `byte[r*256 + c]`, not `byte[c*8 + r]` as the obvious reading suggests. ### Limitations / known issues * **No interrupt handlers in v1** — scheduled for v2. `examples/rt_test` uses busy-wait sleep via ESTEX `$30` instead. * **MAME's mouse driver stubs `$0E GET_SENSITIVE`** — returns 0 instead of the current value. Workaround: always call `mouse_set_sensitivity(h, v)` with known values at startup; don't trust `mouse_get_sensitivity_*()` reads. * **MAME's mouse driver `$0B RETURN_CURSOR`** — writes the bitmap to the IX buffer but does not update the H/L/D/E result registers, so `mouse_get_cursor()` returns width/height/hot_x/hot_y as 0. * **Several Solid-C functions not yet ported** — see `docs/solid_c_compatibility.md` for the categorised list. * **No fprintf / scanf family** — workaround: `sprintf(buf, ...) + fputs(buf, fp)`. * **No double-buffering wrapper** — Sprinter hardware supports it (port `0xC9`), the user-facing wrapper is part of the v2 BGI-style API. ### Migration notes from pre-1.0 trees If you were tracking the project during development: * All example directories were renamed to satisfy 8.3 filenames on the floppy: `banked_big → bankedbg`, `seek_demo → seek`, `malloc_test → malloc`, `time_dir_test → timedir`, `bank_local_data → banklocl`, `gfx_demo16 → gfx_d16`, `gfx_text_demo → gfx_text`, `gfx_mouse_test → gfx_mous`, etc. * `puts` / `putchar` no longer apply `g_text_attr` (switched to fast PCHARS). Programs that depended on coloured stdio must use `cputs` / `cprintf` / `putch` instead, or call `textattr(...)` followed by clrscr. * `runtime/bank.s` is no longer bundled in `sprinter.lib` — it's assembled per-build by `sprinter-cc` with the right `BANK_W1` flag for the chosen memory mode. ### Acknowledgements * **Peters Plus** team (Иван Мак, Дмитрий Паринов) for designing Sprinter and publishing the architecture / BIOS / DSS documentation that made this toolchain possible. * **Dmitry M.** for the z88dk `+pps` Sprinter target — first proof-of-concept for cross-compiling C to SprintEXE; several conventions were borrowed. * **The SDCC team** for the Z80 backend that does the heavy lifting. * **The MAME team** for emulating the Sprinter Sp2000 well enough for full toolchain regression testing without hardware. --- ## v2.0 (planned) Scope: 1. IM2 interrupt handlers (`irq_install` / `irq_remove`) — design in `docs/im2_isr_design.md` 2. Turbo-C-style BGI graphics API (`initgraph` / `setcolor` / `circle` / `getimage` / `putimage` / `setviewport` / `setlinestyle` / ...) 3. Audio API (AY-3-8910 + COVOX, requires IM2) 4. ISA-8 slot drivers (sound, network — requires IM2) 5. Remaining Solid-C compatibility (Phase 2/3 in `docs/solid_c_compatibility.md`): `ungetc`, `getdate/gettime/setdate/settime`, `absread/abswrite`, `scanf` family, `fdopen` / `freopen` / `fclosall`