Files
snark13 c71e249a4e Add full compiler toolchain, libc, examples and reference docs
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>
2026-06-03 16:13:21 +03:00

111 lines
3.3 KiB
ArmAsm

;; ----------------------------------------------------------------------
;; crt0_minimal.s — Sprinter ESTEX C runtime startup, no argv parsing.
;;
;; This is the opt-out variant for programs where every byte counts.
;; The DEFAULT runtime is runtime/crt0.s which also parses argv from the
;; ESTEX command line and passes argc/argv to main().
;;
;; To use this instead of the default:
;; crt0.rel: $(PROJ_ROOT)/runtime/crt0_minimal.s
;; $(SDASZ80) -o $@ $<
;;
;; Otherwise identical to crt0.s — saves IX, calls gsinit, calls main
;; with no arguments, then EXIT via ESTEX $41.
;; ----------------------------------------------------------------------
.module crt0_minimal
.globl _main
;; Linker-emitted symbols for areas (resolved at link time).
.globl s__INITIALIZER
.globl l__INITIALIZER
.globl s__INITIALIZED
.globl s__BSS
.globl l__BSS
;; =========================================================================
;; AREA ORDERING — emitted up-front so the linker walks them in this order.
;; =========================================================================
.area _HOME
.area _CODE
.area _INITIALIZER
.area _GSINIT
.area _GSFINAL
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
;; =========================================================================
;; Entry point — first instruction in _CODE, hence at --code-loc (0x4100).
;; =========================================================================
.area _CODE
_start::
;; ESTEX already set SP from the EXE header, but make it explicit.
ld sp, #0xBFFE
;; Save startup prefix (IX) for argv/exit-code helpers.
ld (_estex_startup_ix), ix
;; Run SDCC global initialisers (concatenated into _GSINIT).
call gsinit
;; Hand off to user main.
call _main
;; SDCC 4.5 __sdcccall(1): int return is in DE, so low byte of main()'s
;; return is in E. (See memory/sdcc_z80_abi.md.)
;; main returned — terminate via ESTEX EXIT directly. We do NOT
;; expose a _exit symbol; programs that need exit() / atexit() must
;; link libc/io/atexit.c.
ld a, e
ld b, a
ld c, #0x41 ; ESTEX EXIT
rst #0x10
1$: halt
jr 1$
;; =========================================================================
;; Runtime data
;; =========================================================================
.area _DATA
_estex_startup_ix::
.ds 2
;; =========================================================================
;; gsinit — copy _INITIALIZER -> _INITIALIZED, then zero _BSS.
;; SDCC appends per-unit init code between this label and the ret in _GSFINAL.
;; =========================================================================
.area _GSINIT
gsinit::
;; --- Copy _INITIALIZER -> _INITIALIZED if non-empty ---
ld bc, #l__INITIALIZER
ld a, b
or a, c
jr Z, gsinit_bss
ld de, #s__INITIALIZED
ld hl, #s__INITIALIZER
ldir
gsinit_bss:
;; --- Zero _BSS if non-empty ---
ld bc, #l__BSS
ld a, b
or a, c
jr Z, gsinit_done
ld hl, #s__BSS
ld (hl), #0
dec bc
ld a, b
or a, c
jr Z, gsinit_done
ld d, h
ld e, l
inc de
ldir
gsinit_done:
.area _GSFINAL
ret