161 lines
6.8 KiB
ArmAsm
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
|