# 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

```sh
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:

```sh
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 |

```sh
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`:

```c
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

```sh
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 API** — `initgraph` / `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.
