toolchain: gsinit зануляет _DATA (C-семантика статиков) + sprinter-cc --max-allocs
Все четыре 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>
This commit is contained in:
@@ -34,6 +34,9 @@
|
|||||||
# --bank N=FILE.c compile FILE.c as bank N; repeatable; pulls crt0_banked
|
# --bank N=FILE.c compile FILE.c as bank N; repeatable; pulls crt0_banked
|
||||||
# automatically and adds -Wl-b_BANKN=0x{N}C000
|
# automatically and adds -Wl-b_BANKN=0x{N}C000
|
||||||
# --mkexe FLAG extra mkexe flag (repeatable; e.g. --mkexe -p --mkexe 0)
|
# --mkexe FLAG extra mkexe flag (repeatable; e.g. --mkexe -p --mkexe 0)
|
||||||
|
# --max-allocs N SDCC --max-allocs-per-node (default: SDCC's 3000).
|
||||||
|
# Higher values give smaller/faster code at the cost of
|
||||||
|
# compile time; 10000..100000 is a reasonable range.
|
||||||
# --debug enable runtime diagnostics — defines DEBUG_RT for both
|
# --debug enable runtime diagnostics — defines DEBUG_RT for both
|
||||||
# sdcc (-DDEBUG_RT) and the crt0 assembly (prepended
|
# sdcc (-DDEBUG_RT) and the crt0 assembly (prepended
|
||||||
# `DEBUG_RT = 1`). Exposes runtime introspection symbols
|
# `DEBUG_RT = 1`). Exposes runtime introspection symbols
|
||||||
@@ -82,6 +85,7 @@ SOURCES=()
|
|||||||
LD_EXTRA=()
|
LD_EXTRA=()
|
||||||
MKEXE_EXTRA=()
|
MKEXE_EXTRA=()
|
||||||
BANK_SPECS=() # entries like "1=engine.c"
|
BANK_SPECS=() # entries like "1=engine.c"
|
||||||
|
MAX_ALLOCS="" # if set, passed to sdcc as --max-allocs-per-node
|
||||||
|
|
||||||
# ------- Parse args ----------------------------------------------------------
|
# ------- Parse args ----------------------------------------------------------
|
||||||
usage() {
|
usage() {
|
||||||
@@ -105,6 +109,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
-Wl) LD_EXTRA+=("$2"); shift 2;;
|
-Wl) LD_EXTRA+=("$2"); shift 2;;
|
||||||
--bank) BANK_SPECS+=("$2"); shift 2;;
|
--bank) BANK_SPECS+=("$2"); shift 2;;
|
||||||
--mkexe) MKEXE_EXTRA+=("$2"); shift 2;;
|
--mkexe) MKEXE_EXTRA+=("$2"); shift 2;;
|
||||||
|
--max-allocs) MAX_ALLOCS="$2"; shift 2;;
|
||||||
--debug) DEBUG_RT=1; shift;;
|
--debug) DEBUG_RT=1; shift;;
|
||||||
-v) VERBOSE=1; shift;;
|
-v) VERBOSE=1; shift;;
|
||||||
-h|--help) usage 0;;
|
-h|--help) usage 0;;
|
||||||
@@ -272,6 +277,7 @@ run "$SDASZ80" -o "$HEAP_TOP_REL" "$HEAP_TOP_SRC"
|
|||||||
USER_RELS=()
|
USER_RELS=()
|
||||||
CC_FLAGS=(-mz80 --no-std-crt0 --std-c99 --opt-code-size -I "$INC_DIR" "${USER_INCS[@]}")
|
CC_FLAGS=(-mz80 --no-std-crt0 --std-c99 --opt-code-size -I "$INC_DIR" "${USER_INCS[@]}")
|
||||||
[[ $DEBUG_RT -eq 1 ]] && CC_FLAGS+=(-DDEBUG_RT)
|
[[ $DEBUG_RT -eq 1 ]] && CC_FLAGS+=(-DDEBUG_RT)
|
||||||
|
[[ -n "$MAX_ALLOCS" ]] && CC_FLAGS+=(--max-allocs-per-node "$MAX_ALLOCS")
|
||||||
for src in "${SOURCES[@]}"; do
|
for src in "${SOURCES[@]}"; do
|
||||||
rel="$WORK/$(basename "$src" .c).rel"
|
rel="$WORK/$(basename "$src" .c).rel"
|
||||||
run "$SDCC" "${CC_FLAGS[@]}" -c -o "$rel" "$src"
|
run "$SDCC" "${CC_FLAGS[@]}" -c -o "$rel" "$src"
|
||||||
|
|||||||
+31
-15
@@ -27,6 +27,8 @@
|
|||||||
.globl s__INITIALIZER
|
.globl s__INITIALIZER
|
||||||
.globl l__INITIALIZER
|
.globl l__INITIALIZER
|
||||||
.globl s__INITIALIZED
|
.globl s__INITIALIZED
|
||||||
|
.globl s__DATA
|
||||||
|
.globl l__DATA
|
||||||
.globl s__BSS
|
.globl s__BSS
|
||||||
.globl l__BSS
|
.globl l__BSS
|
||||||
|
|
||||||
@@ -300,10 +302,13 @@ gpn_skip:
|
|||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; Runtime data (HOME's _DATA / _BSS)
|
;; Runtime data (HOME's _DATA / _BSS)
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _DATA
|
.area _CODE
|
||||||
|
;; Written BEFORE gsinit runs (gsinit zeroes _DATA), so these live in
|
||||||
|
;; _CODE — RAM on the Sprinter, always mapped.
|
||||||
_estex_startup_ix::
|
_estex_startup_ix::
|
||||||
.ds 2
|
.ds 2
|
||||||
|
|
||||||
|
.area _DATA
|
||||||
_argc::
|
_argc::
|
||||||
.ds 2
|
.ds 2
|
||||||
_argv::
|
_argv::
|
||||||
@@ -326,32 +331,43 @@ progname_buf:
|
|||||||
.ds 128 ; ESTEX APPINFO app_path target
|
.ds 128 ; ESTEX APPINFO app_path target
|
||||||
|
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; gsinit — copy _INITIALIZER -> _INITIALIZED, then zero _BSS.
|
;; gsinit — zero _DATA + _BSS, then copy _INITIALIZER -> _INITIALIZED.
|
||||||
|
;; _DATA is zeroed because C guarantees zero-valued statics — this lets
|
||||||
|
;; code drop explicit `= 0` initializers that burn _INITIALIZER bytes.
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _GSINIT
|
.area _GSINIT
|
||||||
gsinit::
|
.area _CODE
|
||||||
ld bc, #l__INITIALIZER
|
;; zero_area — fill BC bytes at HL with 0 (BC may be zero).
|
||||||
|
zero_area:
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_bss
|
ret Z
|
||||||
ld de, #s__INITIALIZED
|
|
||||||
ld hl, #s__INITIALIZER
|
|
||||||
ldir
|
|
||||||
gsinit_bss:
|
|
||||||
ld bc, #l__BSS
|
|
||||||
ld a, b
|
|
||||||
or a, c
|
|
||||||
jr Z, gsinit_done
|
|
||||||
ld hl, #s__BSS
|
|
||||||
ld (hl), #0
|
ld (hl), #0
|
||||||
dec bc
|
dec bc
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_done
|
ret Z
|
||||||
ld d, h
|
ld d, h
|
||||||
ld e, l
|
ld e, l
|
||||||
inc de
|
inc de
|
||||||
ldir
|
ldir
|
||||||
|
ret
|
||||||
|
|
||||||
|
.area _GSINIT
|
||||||
|
gsinit::
|
||||||
|
ld hl, #s__DATA
|
||||||
|
ld bc, #l__DATA
|
||||||
|
call zero_area
|
||||||
|
ld hl, #s__BSS
|
||||||
|
ld bc, #l__BSS
|
||||||
|
call zero_area
|
||||||
|
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:
|
gsinit_done:
|
||||||
|
|
||||||
.area _GSFINAL
|
.area _GSFINAL
|
||||||
|
|||||||
+32
-15
@@ -35,6 +35,8 @@
|
|||||||
.globl s__INITIALIZER
|
.globl s__INITIALIZER
|
||||||
.globl l__INITIALIZER
|
.globl l__INITIALIZER
|
||||||
.globl s__INITIALIZED
|
.globl s__INITIALIZED
|
||||||
|
.globl s__DATA
|
||||||
|
.globl l__DATA
|
||||||
.globl s__BSS
|
.globl s__BSS
|
||||||
.globl l__BSS
|
.globl l__BSS
|
||||||
|
|
||||||
@@ -398,7 +400,9 @@ gpn_skip:
|
|||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; Runtime data
|
;; Runtime data
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _DATA
|
.area _CODE
|
||||||
|
;; Written BEFORE gsinit runs (gsinit zeroes _DATA), so these live in
|
||||||
|
;; _CODE — RAM on the Sprinter, always mapped.
|
||||||
_estex_startup_ix::
|
_estex_startup_ix::
|
||||||
.ds 2
|
.ds 2
|
||||||
_estex_file_handle::
|
_estex_file_handle::
|
||||||
@@ -407,6 +411,8 @@ _estex_block_id::
|
|||||||
.ds 1
|
.ds 1
|
||||||
_bank_block_id::
|
_bank_block_id::
|
||||||
.ds 1
|
.ds 1
|
||||||
|
|
||||||
|
.area _DATA
|
||||||
_argc::
|
_argc::
|
||||||
.ds 2
|
.ds 2
|
||||||
_argv::
|
_argv::
|
||||||
@@ -427,32 +433,43 @@ _w2_self_allocated::
|
|||||||
.endif
|
.endif
|
||||||
|
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; gsinit — same as crt0.s (copy INITIALIZER, zero BSS)
|
;; gsinit — same as crt0.s (zero _DATA + _BSS, copy INITIALIZER)
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _GSINIT
|
.area _GSINIT
|
||||||
gsinit::
|
.area _CODE
|
||||||
ld bc, #l__INITIALIZER
|
;; zero_area — fill BC bytes at HL with 0 (BC may be zero).
|
||||||
|
zero_area:
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_bss
|
ret Z
|
||||||
ld de, #s__INITIALIZED
|
|
||||||
ld hl, #s__INITIALIZER
|
|
||||||
ldir
|
|
||||||
gsinit_bss:
|
|
||||||
ld bc, #l__BSS
|
|
||||||
ld a, b
|
|
||||||
or a, c
|
|
||||||
jr Z, gsinit_done
|
|
||||||
ld hl, #s__BSS
|
|
||||||
ld (hl), #0
|
ld (hl), #0
|
||||||
dec bc
|
dec bc
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_done
|
ret Z
|
||||||
ld d, h
|
ld d, h
|
||||||
ld e, l
|
ld e, l
|
||||||
inc de
|
inc de
|
||||||
ldir
|
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:
|
gsinit_done:
|
||||||
|
|
||||||
.area _GSFINAL
|
.area _GSFINAL
|
||||||
|
|||||||
+30
-17
@@ -20,6 +20,8 @@
|
|||||||
.globl s__INITIALIZER
|
.globl s__INITIALIZER
|
||||||
.globl l__INITIALIZER
|
.globl l__INITIALIZER
|
||||||
.globl s__INITIALIZED
|
.globl s__INITIALIZED
|
||||||
|
.globl s__DATA
|
||||||
|
.globl l__DATA
|
||||||
.globl s__BSS
|
.globl s__BSS
|
||||||
.globl l__BSS
|
.globl l__BSS
|
||||||
|
|
||||||
@@ -70,40 +72,51 @@ _start::
|
|||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; Runtime data
|
;; Runtime data
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _DATA
|
.area _CODE
|
||||||
|
;; Written BEFORE gsinit runs (gsinit zeroes _DATA), so these live in
|
||||||
|
;; _CODE — RAM on the Sprinter, always mapped.
|
||||||
_estex_startup_ix::
|
_estex_startup_ix::
|
||||||
.ds 2
|
.ds 2
|
||||||
|
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; gsinit — copy _INITIALIZER -> _INITIALIZED, then zero _BSS.
|
;; gsinit — zero _DATA + _BSS, then copy _INITIALIZER -> _INITIALIZED.
|
||||||
;; SDCC appends per-unit init code between this label and the ret in _GSFINAL.
|
;; SDCC appends per-unit init code between this label and the ret in _GSFINAL.
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _GSINIT
|
.area _GSINIT
|
||||||
gsinit::
|
.area _CODE
|
||||||
;; --- Copy _INITIALIZER -> _INITIALIZED if non-empty ---
|
;; zero_area — fill BC bytes at HL with 0 (BC may be zero).
|
||||||
ld bc, #l__INITIALIZER
|
zero_area:
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_bss
|
ret Z
|
||||||
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
|
ld (hl), #0
|
||||||
dec bc
|
dec bc
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_done
|
ret Z
|
||||||
ld d, h
|
ld d, h
|
||||||
ld e, l
|
ld e, l
|
||||||
inc de
|
inc de
|
||||||
ldir
|
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:
|
gsinit_done:
|
||||||
|
|
||||||
.area _GSFINAL
|
.area _GSFINAL
|
||||||
|
|||||||
+35
-19
@@ -38,6 +38,8 @@
|
|||||||
.globl s__INITIALIZER
|
.globl s__INITIALIZER
|
||||||
.globl l__INITIALIZER
|
.globl l__INITIALIZER
|
||||||
.globl s__INITIALIZED
|
.globl s__INITIALIZED
|
||||||
|
.globl s__DATA
|
||||||
|
.globl l__DATA
|
||||||
.globl s__BSS
|
.globl s__BSS
|
||||||
.globl l__BSS
|
.globl l__BSS
|
||||||
|
|
||||||
@@ -119,11 +121,11 @@ w2_join:
|
|||||||
ld sp, #0xBFFE
|
ld sp, #0xBFFE
|
||||||
.ifdef DEBUG_RT
|
.ifdef DEBUG_RT
|
||||||
;; Save the self-alloc flag across gsinit (which clobbers BC/DE/HL and
|
;; Save the self-alloc flag across gsinit (which clobbers BC/DE/HL and
|
||||||
;; zeroes BSS). SP is in W2 now, push is safe.
|
;; zeroes _DATA/_BSS). SP is in W2 now, push is safe.
|
||||||
push af
|
push af
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
;; ----- Step 5: save IX prefix in its canonical W2 slot. -------------
|
;; ----- Step 5: save IX prefix in its canonical slot (_CODE, W1). ----
|
||||||
ld (_estex_startup_ix), ix
|
ld (_estex_startup_ix), ix
|
||||||
|
|
||||||
;; ----- Step 6: standard gsinit + argv flow (identical to crt0.s). --
|
;; ----- Step 6: standard gsinit + argv flow (identical to crt0.s). --
|
||||||
@@ -336,10 +338,13 @@ gpn_skip:
|
|||||||
;; Runtime data — same layout as crt0.s. Lives in DATA/BSS which the
|
;; Runtime data — same layout as crt0.s. Lives in DATA/BSS which the
|
||||||
;; linker places in W2 (--data-loc 0x8000).
|
;; linker places in W2 (--data-loc 0x8000).
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _DATA
|
.area _CODE
|
||||||
|
;; _estex_startup_ix is written BEFORE gsinit runs (gsinit zeroes _DATA),
|
||||||
|
;; so it lives in _CODE — RAM on the Sprinter, always mapped.
|
||||||
_estex_startup_ix::
|
_estex_startup_ix::
|
||||||
.ds 2
|
.ds 2
|
||||||
|
|
||||||
|
.area _DATA
|
||||||
_argc::
|
_argc::
|
||||||
.ds 2
|
.ds 2
|
||||||
_argv::
|
_argv::
|
||||||
@@ -362,33 +367,44 @@ _w2_self_allocated::
|
|||||||
.endif
|
.endif
|
||||||
|
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
;; gsinit — copy _INITIALIZER -> _INITIALIZED, then zero _BSS. Identical
|
;; gsinit — zero _DATA + _BSS, then copy _INITIALIZER -> _INITIALIZED.
|
||||||
;; to crt0.s; runs AFTER W2 is mapped so writes to _INITIALIZED/_BSS land.
|
;; Identical to crt0.s; runs AFTER W2 is mapped so the writes land.
|
||||||
|
;; _DATA is zeroed because C guarantees zero-valued statics — initializing
|
||||||
|
;; `static uint8_t x;` here lets code drop explicit `= 0` initializers
|
||||||
|
;; that would otherwise burn _INITIALIZER bytes in the EXE image.
|
||||||
;; =========================================================================
|
;; =========================================================================
|
||||||
.area _GSINIT
|
.area _CODE
|
||||||
gsinit::
|
;; zero_area — fill BC bytes at HL with 0 (BC may be zero).
|
||||||
ld bc, #l__INITIALIZER
|
zero_area:
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_bss
|
ret Z
|
||||||
ld de, #s__INITIALIZED
|
|
||||||
ld hl, #s__INITIALIZER
|
|
||||||
ldir
|
|
||||||
gsinit_bss:
|
|
||||||
ld bc, #l__BSS
|
|
||||||
ld a, b
|
|
||||||
or a, c
|
|
||||||
jr Z, gsinit_done
|
|
||||||
ld hl, #s__BSS
|
|
||||||
ld (hl), #0
|
ld (hl), #0
|
||||||
dec bc
|
dec bc
|
||||||
ld a, b
|
ld a, b
|
||||||
or a, c
|
or a, c
|
||||||
jr Z, gsinit_done
|
ret Z
|
||||||
ld d, h
|
ld d, h
|
||||||
ld e, l
|
ld e, l
|
||||||
inc de
|
inc de
|
||||||
ldir
|
ldir
|
||||||
|
ret
|
||||||
|
|
||||||
|
.area _GSINIT
|
||||||
|
gsinit::
|
||||||
|
ld hl, #s__DATA
|
||||||
|
ld bc, #l__DATA
|
||||||
|
call zero_area
|
||||||
|
ld hl, #s__BSS
|
||||||
|
ld bc, #l__BSS
|
||||||
|
call zero_area
|
||||||
|
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:
|
gsinit_done:
|
||||||
|
|
||||||
.area _GSFINAL
|
.area _GSFINAL
|
||||||
|
|||||||
Reference in New Issue
Block a user