Files
VGMPLAY.WMF/src_sdcc/asm/inflate_call.s
T

331 lines
12 KiB
ArmAsm
Raw 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.
;==============================================================================
; inflate_call.s — SDCC обёртка (sdcccall(1)) для вызова inflate из C
;
; uint8_t inflate_vgz(uint8_t src_page, uint8_t dst_page);
; void copy_pages_to_tap(uint8_t n_pages);
;
; sdcccall(1): A = первый аргумент
; Возврат inflate_vgz: A = 0 (успех) / 1 (ошибка)
;
; Inflate binary живёт в экстра-странице WMF. Обёртка маппит её в Win 3
; (ORG 0xC000) и делает JP 0xC000. Decode buffer — в Win 2 (0x8000),
; настраивается самим inflate. При выходе inflate восстанавливает Win 2.
;
; ╔══════════════════════════════════════════════════════════════════════╗
; ║ Почему код inflate обязан быть в Win 3, а не Win 2: ║
; ║ DEFLATE backref вычисляет HL = write_ptr − distance. ║
; ║ При decode buffer в Win 2 (0x8000) → HL ∈ [0x0000..0xBFFF], ║
; ║ никогда не попадает в Win 3 (0xC000+), где живёт код. ║
; ║ Если поменять местами (код Win 2, decode Win 3) → HL может ║
; ║ попасть в 0x8000–0xBFFF, что потребует ремапа Win 2 во время ║
; ║ исполнения из неё — невозможно. ║
; ╚══════════════════════════════════════════════════════════════════════╝
;
; copy_pages_to_tap:
; Копирует N страниц из мегабуфера (#20+) в TAP-страницы (#A1+).
; DI на время копирования, восстанавливает Win 0/Win 3 из sys vars.
;
; inflate_vgz:
; 1. Сохранить аргументы, IX, SP, Win 1
; 2. DI, маппить Win 3 = inflate page через порт
; 3. SP = 0xFFF0, push return addr → JP 0xC000
; 4. По возврату: SP, Win 1 восстанавливаем, EI, IX → ret
; Win 0 / Win 3 — восстанавливает вызывающий C-код через WC API
;==============================================================================
.module inflate_call
.globl _inflate_vgz
.globl _copy_pages_to_tap
; Progress bar params (filled by C before inflate_vgz)
.globl _ifl_pb_text_pg
.globl _ifl_pb_attr_ofs
.globl _ifl_pb_total
.globl _ifl_pb_bw
.globl _ifl_pb_green
;--- Константы ---------------------------------------------------------------
INFLATE_PAGE_IDX = 4 ; индекс inflate в плагине (1 code + 3 LUT)
; физ. страница = base_page + INFLATE_PAGE_IDX
; base_page читается из WC sys var (0x6002)
PORT_W0 = 0x10AF ; TSConfig Win 0 page port
PORT_W1 = 0x11AF ; TSConfig Win 1 page port
PORT_W3 = 0x13AF ; TSConfig Win 3 page port
;--- DATA (0xB800+) ----------------------------------------------------------
.area _DATA
_ifl_src_pg: .ds 1 ; src_page (физ. стр. TAP)
_ifl_dst_pg: .ds 1 ; dst_page (физ. стр. мегабуфера)
_ifl_sv_pg1: .ds 1 ; saved Win 1 physical page
_ifl_sv_pg2: .ds 1 ; saved Win 2 physical page → inflate D reg
_ifl_sv_sp: .ds 2 ; saved SP
_ifl_inflate_pg: .ds 1 ; computed inflate phys page (debug/scan)
; Progress bar parameters (set by C, copied to inflate page at 0xC1F0)
_ifl_pb_text_pg: .ds 1 ; text screen physical page
_ifl_pb_attr_ofs: .ds 2 ; attr base offset within text page (lo, hi)
_ifl_pb_total: .ds 1 ; estimated total output pages (0=disabled)
_ifl_pb_bw: .ds 1 ; bar width in columns
_ifl_pb_green: .ds 1 ; green attr value
;--- CODE (0x8000+) ----------------------------------------------------------
.area _CODE
_inflate_vgz::
push ix ; callee-saved (SDCC)
;--- 1. сохранить аргументы ---
ld (_ifl_src_pg), a ; A = src_page
ld a, l
ld (_ifl_dst_pg), a ; L = dst_page
;--- 2. DI ---
di
;--- 3. сохранить Win 1, Win 2 из WC sys vars (@ 0x6001/0x6002) ---
ld a, (0x6001)
ld (_ifl_sv_pg1), a
ld a, (0x6002)
ld (_ifl_sv_pg2), a
;--- 4. сохранить SP ---
ld (_ifl_sv_sp), sp
.ifdef DBG_ENABLE
;--- DBG: 0x01 = saved context, about to map inflate page ---
ld bc, #0xFFAF
ld a, #0x01
out (c), a
.endif
;--- 5. маппить Win 3 = inflate page (dynamic: base + IDX) ---
ld a, (0x6002) ; Win 2 phys page = plugin base
.ifdef DBG_ENABLE
ld bc, #0xFEAF
out (c), a ; DBG: FEAF = base page from 0x6002
.endif
add a, #INFLATE_PAGE_IDX ; + 5 = inflate page
ld (_ifl_inflate_pg), a ; save computed inflate page
.ifdef DBG_ENABLE
ld bc, #0xFDAF
out (c), a ; DBG: FDAF = computed inflate page
.endif
ld bc, #PORT_W3
out (c), a
.ifdef DBG_ENABLE
;--- DBG: 0x02 = Win3 mapped to inflate page ---
ld bc, #0xFFAF
ld a, #0x02
out (c), a
ld a, (0xC000)
ld bc, #0xFEAF
out (c), a ; byte[0] — expect 0xF5 (push af)
ld a, (0xC001)
ld bc, #0xFDAF
out (c), a ; byte[1] — expect 0xC5 (push bc)
;=== DBG: scan pages base+3..base+7 looking for inflate ===
ld a, (0x6002)
add a, #3
ld d, a
ld e, #0
_ifl_scan_loop:
ld a, d
ld bc, #PORT_W3
out (c), a
ld a, #0xD0
add a, e
ld bc, #0xFFAF
out (c), a
ld a, d
ld bc, #0xFDAF
out (c), a
ld a, (0xC000)
ld bc, #0xFEAF
out (c), a
inc d
inc e
ld a, e
cp #5
jr nz, _ifl_scan_loop
;--- DBG: 0x04 = scan done, re-map Win3 to inflate page ---
ld bc, #0xFFAF
ld a, #0x04
out (c), a
ld a, (_ifl_inflate_pg)
ld bc, #PORT_W3
out (c), a
.endif
;--- 6. стек в Win 3, push return addr ---
ld sp, #0xFFF0
ld hl, #_ifl_return
push hl
.ifdef DBG_ENABLE
;--- DBG: 0x05 = SP set, return addr pushed, loading regs ---
ld bc, #0xFFAF
ld a, #0x05
out (c), a
ld a, (_ifl_src_pg)
ld bc, #0xFEAF
out (c), a
ld a, (_ifl_dst_pg)
ld bc, #0xFDAF
out (c), a
.endif
;--- 6b. Copy progress bar params to inflate page (0xC1F0+) ---
; Win 3 = inflate page (mapped in step 5)
; Win 2 = _CODE/_DATA (still accessible for reading _ifl_pb_*)
ld a, (_ifl_pb_text_pg)
ld (0xC1F0), a
ld hl, (_ifl_pb_attr_ofs)
ld (0xC1F1), hl
ld a, (_ifl_pb_total)
ld (0xC1F3), a
ld a, (_ifl_pb_bw)
ld (0xC1F4), a
ld a, (_ifl_pb_green)
ld (0xC1F5), a
; Initialize runtime state
xor a
ld (0xC1F6), a ; pb_error = 0
ld (0xC1F7), a ; pb_col = 0
;--- 7. входные регистры inflate: A=src, E=dst, D=saved_pg2 ---
ld a, (_ifl_sv_pg2)
ld d, a ; D = saved Win 2 page
ld a, (_ifl_dst_pg)
ld e, a ; E = dst_page
ld a, (_ifl_src_pg) ; A = src_page
.ifdef DBG_ENABLE
;--- DBG: 0x06 = about to JP 0xC000 ---
push af
push bc
ld bc, #0xFFAF
ld a, #0x06
out (c), a
pop bc
pop af
.endif
;--- 8. запуск inflate ---
; JP 0xC200 = inflate_init (safe zone, survives backref LDIR)
; НЕ JP 0xC000! Entry zone 0xC000–0xC1FF перезаписывается
; LDIR overflow при распаковке backref'ов.
jp 0xC200
;--- сюда вернёмся по RET из inflate ---
; A = 0 (ok) / 1 (error)
; Win 2 уже восстановлен inflate → _DATA и код доступны
_ifl_return:
ld e, a ; результат → E
.ifdef DBG_ENABLE
;--- DBG: 0x03 = returned from inflate, A=result ---
ld bc, #0xFFAF
ld a, #0x03
out (c), a
ld a, e
ld bc, #0xFEAF
out (c), a
.endif
;--- восстановить SP (→ C-стек, сразу после push ix) ---
ld sp, (_ifl_sv_sp)
;--- восстановить Win 1 (WC API точка входа @ 0x6006) ---
ld a, (_ifl_sv_pg1)
ld bc, #PORT_W1
out (c), a
;--- вернуть результат ---
ld a, e
pop ix ; восстановить IX
ei ; EI + задержка 1 instr → ret атомарен
ret
;==============================================================================
; void copy_pages_to_tap(uint8_t n_pages)
;
; Копирует n_pages страниц из мегабуфера (#20..#20+n-1) в TAP (#A1..#A1+n-1).
; Использует прямые port-записи в Win 0 / Win 3.
; DI на время работы; при выходе: Win 0, Win 3 восстановлены, EI.
;
; sdcccall(1): A = n_pages
;==============================================================================
MEGABUF_START = 0x20 ; первая физ. страница мегабуфера
TAP_START = 0xA1 ; первая физ. страница TAP
_copy_pages_to_tap::
or a
ret z ; n=0 → ничего делать
push ix
ld c, a ; C = n_pages (сохраним)
di
;--- сохранить текущие страницы Win 0 / Win 3 ---
ld a, (0x6000)
ld (_cpt_sv_pg0), a
ld a, (0x6003)
ld (_cpt_sv_pg3), a
;--- подготовить счётчики ---
ld d, #MEGABUF_START ; D = src phys page
ld e, #TAP_START ; E = dst phys page
ld b, c ; B = loop counter
_cpt_loop:
push bc
push de
;--- Map Win 0 = megabuf page D ---
ld a, d
ld bc, #PORT_W0
out (c), a
;--- Map Win 3 = TAP page E ---
ld a, e
ld b, #0x13 ; C ещё 0xAF от предыдущего BC
out (c), a
;--- LDIR 16 КБ: Win 0 → Win 3 ---
ld hl, #0x0000
ld de, #0xC000
ld bc, #0x4000
ldir
pop de
inc d ; следующая megabuf page
inc e ; следующая TAP page
pop bc
djnz _cpt_loop
;--- восстановить Win 0 ---
ld a, (_cpt_sv_pg0)
ld bc, #PORT_W0
out (c), a
;--- восстановить Win 3 ---
ld a, (_cpt_sv_pg3)
ld b, #0x13
out (c), a
ei
pop ix
ret
;--- static vars for copy (в CODE — не в DATA, чтобы не зависеть от Win 2) ---
_cpt_sv_pg0: .ds 1
_cpt_sv_pg3: .ds 1