c71e249a4e
First substantive commit: the entire Sprinter C compiler tree on top of
the bare README+gitignore initial commit.
What's in here:
bin/sprinter-cc — driver script invoking SDCC + linker + mkexe
libc/ — Sprinter-specific libc layer over ESTEX/BIOS
(conio, gfx, io, mem, stdio + headers)
runtime/ — crt0 variants (default/small/banked/minimal)
+ heap + bank trampolines
toolchain/ — mkexe (SprintEXE packer, C + tests)
examples/ — 30 demo programs (gfx, file I/O, env, time, …)
lib/Makefile — builds the libc archive (sprinter.lib)
docs/ — converted Sprinter manuals + asm reference samples
third_party/ — solid-c reference compiler dump + sdcc setup script
release_docs/ — packaging / release notes
gitignore overhaul:
• Drop dangerous blanket patterns: *.asm (would hide docs/samples/*.asm)
and *.exe (case-insensitive match was hiding third_party/solid-c/*.EXE
on macOS APFS). Replaced with examples/*/*.{asm,exe,…} and lib/*.lib.
• Restore tracking of toolchain/mkexe/tests/{one,big}.bin — those are
INPUT fixtures, not build outputs.
• Collapse the duplicated SDCC/C/Sdcc sections into one section per
concern (build outputs / vendored / OS-junk).
• Add .sprinter-cc-*/, build/ (catches lib/build/ too), .claude/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
50 lines
2.2 KiB
Markdown
50 lines
2.2 KiB
Markdown
# Memory modes
|
|
|
|
Sprinter's CPU address space is four 16 KB windows. ESTEX DSS allocates RAM
|
|
pages by program size — programs ≤ 16 KB get only **one** page, so the
|
|
"default" Spectrum-style "code in W1, data in W2" layout silently fails for
|
|
small programs. This is why `sprinter-cc` has explicit memory modes.
|
|
|
|
## The five modes
|
|
|
|
| Mode | Code at | Data at | Banks in | Use when |
|
|
|---|---|---|---|---|
|
|
| `tiny` (default) | W2 (0x8100+) | chained after code | — | code + data ≤ 14 KB |
|
|
| `small` | W1 (0x4100+) | chained after code | — | code + data ≤ 30 KB |
|
|
| `big` | W2 (0x8100+) | chained after code | **W1** (0x4000) | tiny + extra banked modules |
|
|
| `huge` | W1 (0x4100+) | W2 (0x8000+) | **W3** (0xC000) | small + extra banked modules |
|
|
| `manual` | user-specified | user-specified | user-specified | special cases |
|
|
|
|
## Choosing
|
|
|
|
Start with **`tiny`**. If `sprinter-cc` says "_CODE too big" or the program
|
|
mysteriously fails to start, jump straight to `small`.
|
|
|
|
If you have a large code base (>32 KB total) and want to keep most of it
|
|
out of the always-resident window, use `huge` and split modules into banks
|
|
with `--bank N=mod.c`. `big` is the same idea but with banks in W1 instead
|
|
of W3 — useful when you need W3 for hardware (graphics, mapped memory).
|
|
|
|
## Stack and heap
|
|
|
|
The stack starts at `0xBFFE` (top of W2) and grows down. The heap starts
|
|
right after BSS and grows up. By default they share W2 with about 1.2 KB
|
|
reserved for the stack and the rest for the heap.
|
|
|
|
`--stack-size N` reserves more (or less) for the stack at the cost of heap.
|
|
|
|
## What's actually under the hood
|
|
|
|
Every mode picks a different `runtime/crt0_*.s`:
|
|
|
|
* `tiny`: `crt0.s` — SP = 0xBFFE, parse argv, call main.
|
|
* `small`: `crt0_small.s` — read port 0xC2 to see if DSS gave W2. If not,
|
|
allocate one page via ESTEX `$3D` and map it via `$3A SETWIN2` *before*
|
|
switching the stack — BIOS calls need the stack in W2, ESTEX calls don't.
|
|
* `big`: `crt0_banked.s` with `BANK_W1=1` prepended — banks live at
|
|
`0x{N}4000` and trampolines use port `0xA2`.
|
|
* `huge`: `crt0_banked.s` (default `BANK_W1=0`) — banks at `0x{N}C000` via
|
|
port `0xE2`. Also includes the small-mode W2 auto-allocate.
|
|
|
|
For `manual` see `sprinter-cc --memory-manual SPEC` syntax in `sprinter_cc.md`.
|