Александр Петров e86f254b87 L1-START + L1-EXIT: старт по данным уровня и выход через дверь уровня
L1-START.  Старт и оба рестарта (смерть, выпадение из уровня) сведены в
pop_start_level() — порт start_level + do_startpos + set_start_pos (seg003).
Комната/тайл/направление берутся из pop_level_start_*, направление
инвертируется (~start_dir), поза входа — из tbl_entry_pose: у уровня 1 это
падение внутрь (seq_7_fall) плюс нажатие кнопки room5(0,2), то самое, что
захлопывает решётку за спиной.  Жёсткие START_ROOM/COL/ROW убраны.
Проверено в MAME: старт даёт room 1, col 0, падение на row 1 — как по данным.

L1-EXIT.  Ветка двери уровня из up_pressed + go_up_leveldoor (seg005:0482/
0574): тайлы и геометрия — pop_leveldoor_enter() в pop_map, последовательность
seq_70 — в pop_ctrl.  Опкод 0xF1 END_LEVEL в play_seq инкрементит
pop_next_level (порт next_level), главный цикл по нему перезапускает уровень
— ровно та точка, куда levels_plan §2.2 подключит загрузку уровня 2.
Открытость двери проверяется по modifier >= 42 (ветка fix_exit_door), а не по
ванильному leveldoor_open: иначе можно войти в ещё ползущую створку.

Отдельно стоило разбора: go_up_leveldoor сначала писал Char.x/Char.direction,
и оба присваивания молча терялись — окно Char вокруг диспетчера возвращает
назад только curr_seq и sword (pop_savekid_state).  Направление оставалось
«вправо», а все DX в seq_70 отрицательные, поэтому Кид уходил ИЗ проёма
влево (поймано стоп-кадром).  Геометрию персонажа в этом порте меняет
pop_map, пишет в Kid — как pop_down_action и pop_jump_up_seq.

Известный остаток — BUG-DOOR-CLIP в bug_list.md: нет обрезки силуэта правым
косяком проёма (недопортирован obj_clip_right в clip_char); нужен вариант
колоночного блита с ограничением ширины.  ROOMNAV пока оставлен включённым —
он нужен, чтобы попадать в комнату 9 для этой работы.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:47:47 +03:00
2026-06-10 10:41:03 +03:00

Sprinter C Compiler — v1.0

C toolchain for Sprinter — the Z80-based home computer by Peters Plus, running ESTEX DSS. Host: macOS / Linux. Target: .EXE files in SprintEXE format.

Built on top of SDCC 4.5 (vendored in third_party/sdcc/). This repository adds everything Sprinter-specific: crt0, linker integration, libc wrappers over ESTEX, banked-call trampolines, graphics & accelerator API, mouse driver wrappers, and the mkexe utility for producing SprintEXE images.

What you get

  • bin/sprinter-cc — one-line driver: sprinter-cc -o foo.exe foo.c
  • Memory modes: tiny, small, big, huge, manual — see below.
  • stdio + conio: printf, puts, putchar, getchar, fopen/fread/..., cprintf, cputs, putch, textcolor/textbackground/textattr, gotoxy, kbhit/getch.
  • Graphics: 320×256×256 and 640×256×16 modes, accelerator-backed primitives (hline / vline / rect / fill_rect / line via Bresenham, plus clear), bitmap-font text in both modes via BIOS character generator.
  • File I/O: POSIX (open/read/write/close/lseek/unlink/creat), FILE* streams (fopen/fgets/fwrite/...), directory listing (ffirst/fnext), chdir/getcwd/mkdir/rmdir, stat/fstat.
  • Memory: 32 KB heap (W2-resident), banking-aware page allocator (mem_alloc_pages/bank_read/bank_write), explicit memory modes for sub-16 KB programs.
  • Mouse: full Sprinter driver wrapper (14 functions including custom cursor bitmaps).
  • Environment: getenv/putenv/sysenv over ESTEX $46.
  • Time: getdatetime/setdatetime + POSIX time/localtime/mktime/asctime/ctime.
  • Misc: errno/strerror/perror, atexit, setjmp/longjmp, sleep, full argv parsing in crt0.

Quick start

git clone <this repo> sprinter-c
cd sprinter-c
make sdcc                      # one-time: fetch SDCC 4.5 binary (~25 MB)
make all                       # build mkexe + libsprinter.lib + 27 examples
make floppy                    # pack everything into mame/v306/IMG/mc.img
cd mame/v306 && ./run_mame.sh  # boot Sprinter in MAME

Compile a single program:

cat > hello.c <<EOF
#include <stdio.h>
int main(void) { puts("Hello, Sprinter!"); return 0; }
EOF

bin/sprinter-cc -o hello.exe hello.c

That's it — hello.exe is now a valid SprintEXE you can RUN HELLO from the ESTEX shell.

Memory modes

Sprinter's address space is four 16 KB windows (W0 / W1 / W2 / W3). DSS allocates pages by program size — small programs get only one page. Pick a memory mode based on what your program needs:

Mode Code lives in Banking Use when Note
tiny (default) W2 (0x8100+) no code+data < 14 KB
small W1-W2 (0x4100+) no code+data < 30 KB
big W2 + W1 banking yes (W1) tiny + extra code modules
huge W1-W2 + W3 banking yes (W3) small + extra code modules
manual user-specified optional special layouts Not implemented
sprinter-cc --memory small  -o big.exe   bigprog.c
sprinter-cc --memory huge   -o app.exe   main.c --bank 1=engine.c --bank 2=ai.c

Banked functions are declared with __banked:

void engine_tick(int dt) __banked;   // lives in BANK1, automatically swapped

Examples (27 total)

Example What it demonstrates
hello Hello world with stdio + conio Turbo-C-style colors
argv argv parsing in crt0
cat File I/O — read & print TEST.TXT
seek 32-bit lseek over a 100 KB file
ls Directory listing via ffirst/fnext
filetest FILE* streams (fopen/fread/...)
stattest stat/fstat on files and directories
errno errno / strerror / perror
mem_test Page allocator + bank_read/bank_write
malloc Heap stress test (200+ allocations)
banked Banked code in W3 (huge mode)
bankedbg Banked code in W1 (big mode)
banklocl Bank-local static data and BSS
mouse Mouse driver in text mode
gfx_mous Mouse with custom bitmap cursor in graphics mode
gfx_demo 320×256×256 lines / rects / accelerator
gfx_d16 640×256×16 same primitives
gfx_text Bitmap-font text on graphics screen
timedir Date/time + directory listing
ptime POSIX time API
openenv open() flags + environment vars
conio conio API smoke test
attrprob Probe Sprinter text attribute byte layout
strtest string.h test (from SDCC's z80.lib)
stdlib stdlib.h test (qsort / rand / strtol / etc.)
assrtest assert()
rt_test Runtime helpers (sleep, setjmp, atexit)

Headers

Standard:

  • <stdio.h> — puts / printf / FILE* + Sprinter-specific dec/hex helpers
  • <stdlib.h> — atoi / atof / malloc / qsort / ... (from SDCC z80.lib)
  • <string.h> / <ctype.h> / <math.h> — from SDCC z80.lib
  • <unistd.h> — read / write / close / lseek / unlink
  • <fcntl.h> — open / creat + O_RDONLY / O_CREAT / ...
  • <errno.h> — errno + error names + strerror
  • <sys/stat.h> — stat / fstat
  • <setjmp.h> / <assert.h> — from SDCC

Sprinter-specific:

  • <conio.h> — putch / cputs / cprintf, textcolor / textbackground / textattr, kbhit / getch, clrscr, gotoxy, wherex/y
  • <gfx.h> — gfx_init/done, palette, putpixel, hline/vline/rect/fill_rect/line, text — for both 320 and 640 modes (gfx_*16 variants)
  • <mouse.h> — full 14-function driver wrapper + mouse_cursor_t with bitmap support
  • <dir.h> — chdir / getcwd / mkdir / rmdir / ffirst / fnext / ffblk
  • <time.h> — getdatetime / setdatetime + POSIX time / localtime / etc.
  • <sprinter.h> — raw ports, ESTEX/BIOS function numbers, env API
  • <sprinter_exit.h> — exit / _exit / atexit
  • <sprinter_mem.h> — mem_alloc_pages / mem_free_block / bank_read / bank_write
  • <sprinter_compat.h> — Solid-C compatibility layer (aliases + BOOL/WORD/uint types)

Toolchain commands

make all              # build mkexe + lib + every example
make floppy           # repack mame/v306/IMG/mc.img with all .exe files
make check            # 17 mkexe unit-tests
make clean            # remove all build artefacts
make sdcc             # one-time: fetch SDCC 4.5 binary

sprinter-cc options

sprinter-cc -o foo.exe foo.c [more.c ...] [options]

  --memory MODE           tiny | small | big | huge | manual    (default: tiny)
  --memory-manual SPEC    explicit placement (CODE=W1|W2,DATA=W1|W2|SAME,BANKED=W1|W3)
  --stack-size N          bytes reserved for the stack (default ~1278)
  --crt0=TYPE             default | minimal | banked | small
  --bank N=FILE.c         compile FILE.c into bank N (repeatable, max 15)
  --debug                 enable runtime diagnostics (defines DEBUG_RT)
  -I PATH                 extra include path
  -L 0xADDR / -E / -S     override load / entry / stack addresses
  -Wl FLAG                pass FLAG to sdldz80
  --mkexe FLAG            pass FLAG to mkexe (e.g. --mkexe -p --mkexe 0 for bank padding)
  -v                      verbose

Status

What works in v1.0:

  • Compile / link / pack to SprintEXE — verified on all 27 examples
  • Four memory modes (tiny / small / big / huge)
  • Graphics (both modes) with accelerator
  • Mouse (text + graphics cursor)
  • File I/O, directories, environment, time
  • All headers listed above

Deferred to v2.0 (see docs/TODO.md):

  • Turbo-C-style BGI graphics APIinitgraph / setcolor / circle / getimage / putimage / etc. on top of our gfx_* primitives
  • Remaining Solid-C compatibility gaps (Phase 2/3) — see docs/solid_c_compatibility.md
  • Manual memory mode
  • Rewrite FILE* stream API (current implementation is very primitive and doesn't use buffers)

Deferred to v3.0:

  • IM2 interrupt handlers — research complete (docs/im2_isr_design.md), implementation scheduled for v3
  • Audio API (AY-3-8910 + COVOX) — requires IM2
  • ISA-8 slot drivers — requires IM2 (???)

Documentation

  • docs/TODO.md — roadmap and open work items
  • docs/solid_c_compatibility.md — gap analysis vs Solid-C 2004
  • docs/im2_isr_design.md — interrupt handler design (v2)
  • docs/converted/ — source documentation (ESTEX, BIOS, architecture) converted to plain text for grep
  • docs/reference/, docs/samples/, docs/memory management/ — original Russian docs and code samples from Peters Plus

Repository layout

bin/sprinter-cc           one-line compiler driver (bash)
toolchain/mkexe/          host-side tool: .ihx -> .exe SprintEXE
toolchain/check_banks.py  post-link bank size enforcer
runtime/                  crt0 variants (default, minimal, small, banked)
                          bank trampolines, heap, heap_top
libc/include/             headers
libc/io|stdio|mem|gfx/    C and asm sources for libsprinter.lib
lib/                      Makefile that archives libsprinter.lib via sdar
examples/                 27 example programs
mame/v306/                MAME binary + Sprinter ROM/HDD images + floppy script
third_party/sdcc/         vendored SDCC 4.5 (fetched via `make sdcc`)
third_party/solid-c/      reference: original Sprinter native C (for compat target)
docs/                     documentation

License

This repository contains:

  • Original code in bin/, toolchain/, runtime/, libc/, lib/, examples/ — MIT-licensed.
  • third_party/sdcc/ — SDCC 4.5 under GPLv2 with linking exception (see third_party/sdcc/COPYING.txt)
  • third_party/solid-c/ — original Sprinter Solid C, used only as a reference

Credits

  • Sprinter / Peters Plus — Иван Мак, Дмитрий Паринов and the original team
  • SDCC — for the underlying Z80 compiler
  • MAME — for the Sprinter Sp2000 emulation

For questions / patches: see CONTRIBUTING.md (TBD) or open an issue.

S
Description
No description provided
Readme MIT 12 MiB
Languages
C 84%
Python 8.2%
Makefile 2.8%
Assembly 2.7%
Shell 2.3%