Files

161 lines
6.8 KiB
ArmAsm

;==============================================================================
; @file crt0.s
; @brief Стартовый код WC-плагина (SDCC Z80, --no-std-crt0)
;
; Этот файл заменяет стандартный crt0 SDCC. Он должен линковаться
; ПЕРВЫМ в цепочке .rel-файлов, чтобы _plugin_entry оказался
; по адресу --code-loc (обычно #8000).
;
; Входные параметры WC (при CALL plugin_base):
; A' = индекс расширения файла
; BC = указатель на имя файла (z-строка)
; HL = размер файла (младшее слово)
; DE = размер файла (старшее слово)
; IX = указатель на структуру активной панели WC
;
; Выход: A = код возврата (0=ESC, 2=следующий, 4=предыдущий)
;
; Адресное пространство:
; #8000-#BFFF = код + данные плагина
; #C000-#FFFF = VPL окно (данные VGM через WC API)
;
; ВАЖНО: gsinit обнуляет _DATA и копирует _INITIALIZER → _INITIALIZED.
; Без этого при повторном запуске (NEXT/PREV) стат. переменные
; содержат мусор от предыдущего запуска.
;==============================================================================
.module crt0
.globl _main
.globl _wc_exit_code
.globl _wc_file_idx
.globl _wc_file_count
; Линкер-символы для runtime-инициализации C
.globl s__DATA
.globl l__DATA
.globl s__INITIALIZED
.globl s__INITIALIZER
.globl l__INITIALIZER
;------------------------------------------------------------------------------
; Entry point (WC вызывает по "CALL plugin_base")
; Вход:
; A' = индекс расширения файла
; BC = указатель на имя файла (z-строка)
; HL = размер файла (младшее слово)
; DE = размер файла (старшее слово)
; IX = указатель на структуру активной панели (нужен WC API)
;------------------------------------------------------------------------------
.area _CODE
_plugin_entry::
;--------------------------------------------------------------
; Сохранить параметры WC на стеке: gsinit обнулит _DATA,
; поэтому нельзя записывать в глобалы до инициализации.
;--------------------------------------------------------------
push hl ; size_lo
push de ; size_hi
push bc ; file_name ptr
ex af, af'
push af ; file_ext (в A)
ex af, af'
;--- Сохранить HL'/DE' (номер объекта / кол-во файлов) ---
exx
push hl ; file_idx (HL')
push de ; file_count (DE')
exx
;--------------------------------------------------------------
; Инициализировать C runtime (обнулить _DATA,
; скопировать начальные значения в _INITIALIZED)
;--------------------------------------------------------------
call gsinit
;--------------------------------------------------------------
; Восстановить параметры WC из стека в (теперь чистые) глобалы
;--------------------------------------------------------------
pop de ; file_count (DE')
ld (_wc_file_count), de
pop hl ; file_idx (HL')
ld (_wc_file_idx), hl
pop af
ld (_wc_file_ext), a
pop bc
ld (_wc_file_name), bc
pop de ; size_hi
pop hl ; size_lo
ld (_wc_file_size+0), hl
ld (_wc_file_size+2), de
; Вызвать main()
call _main
; main() вернула void, код выхода — в _wc_exit_code
ld a, (_wc_exit_code)
; IX не менялся — просто возврат
ret
;------------------------------------------------------------------------------
; Глобальные переменные параметров WC (читаются из main.c)
;------------------------------------------------------------------------------
.area _DATA
_wc_file_ext:: .db 0
_wc_file_name:: .dw 0
_wc_file_size:: .dw 0, 0 ; 32-bit LE
_wc_exit_code:: .db 0
_wc_file_idx:: .dw 0 ; HL': номер объекта в панели (от 1)
_wc_file_count::.dw 0 ; DE': кол-во объектов в панели (вкл. "..")
;------------------------------------------------------------------------------
; Инициализация C runtime (SDCC: _GSINIT выполняется при старте)
;
; 1) Обнулить _DATA — все глобальные/статические переменные без
; явного инициализатора (аналог BSS).
; 2) Скопировать _INITIALIZER → _INITIALIZED — переменные с явным
; начальным значением (static uint8_t x = 5; и т.п.).
;------------------------------------------------------------------------------
.area _GSINIT
gsinit::
; ── 1. Обнулить _DATA ────────────────────────────────────────
ld bc, #l__DATA
ld a, b
or a, c
jr z, 00001$ ; l__DATA == 0 → нечего обнулять
ld hl, #s__DATA
ld (hl), #0 ; первый байт = 0
dec bc
ld a, b
or a, c
jr z, 00001$ ; l__DATA == 1 → уже готово
ld d, h
ld e, l
inc de ; DE = s__DATA + 1
ldir ; заполнить остаток нулями
00001$:
; ── 2. Скопировать _INITIALIZER → _INITIALIZED ──────────────
ld bc, #l__INITIALIZER
ld a, b
or a, c
jr z, 00002$ ; нет инициализированных данных
ld hl, #s__INITIALIZER ; источник (в ROM / code page 1)
ld de, #s__INITIALIZED ; приёмник (в RAM / _DATA area)
ldir
00002$:
.area _GSFINAL
gsfinal::
ret