961cfb786d
Все четыре crt0 (default/small/minimal/banked): gsinit теперь зануляет _DATA и _BSS через общий zero_area, затем копирует _INITIALIZER. Явные `= 0` у глобалов/статиков больше не нужны (они жгли байты _INITIALIZER в образе). crt0-приватные переменные, записываемые ДО gsinit (_estex_startup_ix и др.), перенесены из _DATA в _CODE (RAM). sprinter-cc: новая опция --max-allocs N → SDCC --max-allocs-per-node (агрессивнее аллокация регистров, меньше/быстрее код ценой времени компиляции). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
124 lines
3.7 KiB
ArmAsm
124 lines
3.7 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__DATA
|
|
.globl l__DATA
|
|
.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 _CODE
|
|
;; Written BEFORE gsinit runs (gsinit zeroes _DATA), so these live in
|
|
;; _CODE — RAM on the Sprinter, always mapped.
|
|
_estex_startup_ix::
|
|
.ds 2
|
|
|
|
;; =========================================================================
|
|
;; gsinit — zero _DATA + _BSS, then copy _INITIALIZER -> _INITIALIZED.
|
|
;; SDCC appends per-unit init code between this label and the ret in _GSFINAL.
|
|
;; =========================================================================
|
|
.area _GSINIT
|
|
.area _CODE
|
|
;; zero_area — fill BC bytes at HL with 0 (BC may be zero).
|
|
zero_area:
|
|
ld a, b
|
|
or a, c
|
|
ret Z
|
|
ld (hl), #0
|
|
dec bc
|
|
ld a, b
|
|
or a, c
|
|
ret Z
|
|
ld d, h
|
|
ld e, l
|
|
inc de
|
|
ldir
|
|
ret
|
|
|
|
.area _GSINIT
|
|
gsinit::
|
|
;; --- Zero _DATA + _BSS (C guarantees zero-valued statics) ---
|
|
ld hl, #s__DATA
|
|
ld bc, #l__DATA
|
|
call zero_area
|
|
ld hl, #s__BSS
|
|
ld bc, #l__BSS
|
|
call zero_area
|
|
;; --- Copy _INITIALIZER -> _INITIALIZED if non-empty ---
|
|
ld bc, #l__INITIALIZER
|
|
ld a, b
|
|
or a, c
|
|
jr Z, gsinit_done
|
|
ld de, #s__INITIALIZED
|
|
ld hl, #s__INITIALIZER
|
|
ldir
|
|
gsinit_done:
|
|
|
|
.area _GSFINAL
|
|
ret
|