Files
Sprinter-SDCC/runtime/bank.s
T
snark13 8531b25e75 runtime: фикс banked-режимов — _bank_pages переезжает из _DATA в _CODE
Регрессия от 961cfb7 (gsinit зануляет _DATA, 2026-07-04): crt0_banked
заполняет таблицу физических страниц _bank_pages ДО gsinit, а тот её
стирал — трамплины banked-вызовов читали нули и прыгали в незамапленную
страницу.  Висли ВСЕ banked-программы (banked/bankedbg/banklocl/
banktest); найдено MAME-смоуком.  Тот коммит перенёс crt0-приватные
_estex_* в _CODE, но _bank_pages в runtime/bank.s пропустил.

- runtime/bank.s: _bank_pages → .area _CODE (RAM, всегда замаплен —
  это же условие нужно и трамплину); +16 Б _CODE у программ с bank.s
- app.mk: exe теперь зависит от runtime/*.s — правка crt0/bank.s
  перелинковывает тесты без make clean (фикс иначе не подхватывался)
- эталон размеров обновлён (+16 Б у banked/bankedbg/banklocl/
  banktest/openenv — size-check поймал ровно их)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:06:20 +03:00

75 lines
3.3 KiB
ArmAsm
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;; ----------------------------------------------------------------------
;; bank.s — Sprinter banked-call trampolines for SDCC __banked functions.
;;
;; ABI (verified empirically with SDCC 4.5, see memory/sdcc_banking.md):
;; On entry to ___sdcc_bcall_ehl:
;; E = bank id (1..15), HL = target address (low 16 bits).
;; Args already on stack, pushed by the caller right-to-left.
;; Stack picture once the trampoline finishes set-up and jp(hl) fires:
;; SP+0..1 = bjump return (callee's "ret address")
;; SP+2 = saved physical page (1 byte)
;; SP+3..4 = bcall caller return
;; SP+5.. = args ← __banked callees read from here
;;
;; The 3-byte spacer between callee ret and args is the contract SDCC bakes
;; into its codegen — touching it breaks all __banked calls.
;; ----------------------------------------------------------------------
.module bank
.globl _bank_pages
.globl ___sdcc_bcall_ehl
.globl ___sdcc_bjump_ehl
;; Choose between W3 (HUGE mode, default) and W1 (BIG mode, sprinter-cc
;; prepends `BANK_W1 = 1`). Keep in sync with crt0_banked.s.
.ifdef BANK_W1
BANK_PORT = 0xA2
.else
BANK_PORT = 0xE2
.endif
;; HOME area — always mapped, so the trampoline is reachable from any bank.
.area _CODE
___sdcc_bcall_ehl::
;; The 3-byte spacer between bcall-ret and args (1-byte saved page
;; + 2-byte bjump return address) is baked into SDCC's __banked
;; codegen — callees access their args at fixed offsets from SP.
;; We MUST keep that contract intact.
;;
;; The old `pop af; out (n), a` restore sequence clobbered A,
;; dropping uint8_t return values. We use the `OUT (C), r` form
;; (port via C, byte via B) so A is preserved. BC is scratch in
;; SDCC __sdcccall(1), so clobbering it here is harmless.
in a, (#BANK_PORT) ; A = current bank-window page
push af ; push A:F (2 bytes)
inc sp ; keep only the A byte (1-byte spacer)
call ___sdcc_bjump_ehl
;; Callee returned. A may hold a uint8_t return value.
dec sp ; widen back to 2 bytes
pop bc ; B = saved page (C = whatever F was)
ld c, #BANK_PORT ; C = bank-window select port
out (c), b ; OUT (port), B — A and F untouched
ret ; back to bcall caller
___sdcc_bjump_ehl::
push hl ; preserve target address
ld d, #0 ; D:E = 0:bank_id
ld hl, #_bank_pages
add hl, de ; HL = &_bank_pages[bank_id]
ld a, (hl) ; A = physical page for this bank
pop hl ; restore target address
out (#BANK_PORT), a ; map bank into banking window
jp (hl) ; tail-jump to callee
;; Per-bank physical page table. Index = bank id (1-based; [0] is unused).
;; Filled at startup by crt0_banked.s ДО gsinit, а gsinit зануляет
;; _DATA (с 2026-07-04) — поэтому таблица живёт в _CODE (RAM на
;; Sprinter, всегда замаплен: это же нужно и трамплину выше).
;; Регрессия «bank_pages[]=0 → трамплин прыгает в мусор» была именно
;; из-за .area _DATA здесь.
.area _CODE
_bank_pages::
.ds 16