Files
Sprinter-SDCC/libbgi/bgi256/_bgi_heal_rows_raw.c
T
snark13 72ce66275e libbgi: спрайтовый движок v2 + accel-блит/heal leaf'ы + noclip-путь
Спрайтовая графика поверх accel block-copy (docs/sprite-api-design.md):

- Ядро блиттинга: leaf'ы _bgi_blit_rows_raw (dst фикс, только src-страйд) /
  _bgi_copy_rows_raw (getimage) / _bgi_heal_rows_raw (src==dst). DI один на
  спрайт (санкция: малый спрайт под одним DI аудио не рвёт); src[0]-фикс
  снят (точная MAME подавляет CPU-байт триггера записи — на железе
  перепроверить; для heal был избыточен и снят безусловно).
- Общие bracket-free ядра _gfx_blit_full/_gfx_heal_full (полная ширина:
  клип по экрану + split >256 для putimage) + лин _gfx_blit_sprite/
  _gfx_heal_sprite (кадр ≤64, без split, 8-бит w/h) + noclip-варианты
  (клип-кода нет → полный codegen-win).  Имя *_full (не *_clip) — «clip»
  двусмысленно (sprite-ядра тоже клипуют; различитель — ширина/split).
- Движок retained-модели <sprite.h>: sprite_init/update/flip + inline
  move/frame/show/hide/touch; drawn[2] per-page внутри структуры; кадр —
  двухпроходно heal ВСЕ -> блит ВСЕ под одной W3-скобкой/банком на проход.
- Флаг gfx_sprite_clip(on/off): приложение, само следящее за границами,
  отключает клип (~+19% на анимации; диспетч пока через if — funcptr далее).
- putsprite/movesprite/gfx_blit/putimage(COPY)/getimage переведены на ядро.

Тесты: examples/balls (движок, дабл-буфер, boundary-тест клипа),
tests/sprites (RAM PASS, клип 4 края, атлас), tests/blitw (trig-leak),
tests/spriteclip (hardware-probe: железо НЕ режет за краем -> клип нужен),
tests/blitperf, tests/gfxbanks. size-baseline обновлён (53 программы).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 21:51:52 +03:00

73 lines
4.1 KiB
C
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.
/*
* _bgi_heal_rows_raw — специализация accel-копии для heal (src == dst ==
* адрес экрана): h строк по w байт «прочитать ОЗУ-копию → записать в
* VRAM+ОЗУ» на одном месте. Выделен из _bgi_copy_rows_raw по профилю
* examples/balls (2026-07-12): у heal ОБА страйда нулевые по
* определению (строку выбирает Port_Y, CPU-адрес не меняется), поэтому
* адресной арифметики в цикле нет вообще — строка 77Т + burst'ы против
* 204Т у универсального leaf'а до оптимизации.
*
* ВХОД (__sdcccall(1)): scr→HL (base + x), y0→DE (E — стартовый
* Port_Y); стек: w 4(ix), h 5(ix) — 1..256, 0 = 256 (конвенция
* акселератора). Callee-pops 2 байта.
*
* Raw: клиппинга нет, W3 замаплен вызывающим; банк выбирает
* вызывающий (gfx_heal форсит 0x50 — иначе heal бессмыслен).
* Полосы > 256 байт режет вызывающий.
*
* Квирк CPU-байта write-триггера (см. _bgi_copy_rows_raw): для heal
* предчитанный src[0] — ровно тот байт, что burst запишет в dst[0],
* так что фикс EX AF,AF' здесь одновременно и нейтрализация утечки,
* и просто корректное значение.
*
* Клоббер: AF/AF'/BC/DE/HL; IX сохраняется.
*/
#include "../_bgi.h"
void _bgi_heal_rows_raw(uint8_t *scr, int y0, uint8_t w, uint8_t h) __naked
{
__asm
push ix
ld ix, #0
add ix, sp
;; SMC: размер блока <- w (immediate требование FSM)
ld a, 4 (ix)
ld (hr_len_imm), a
ld c, e ; C = y (взять ДО затирания DE)
ld b, 5 (ix) ; B = счётчик строк (0 => 256)
ld d, h
ld e, l ; DE = HL = scr (src == dst)
;; ОДИН DI на весь спрайт (arm + все строки): убирает per-row
;; EI-окно, где CBL-ISR мог пере-армировать акселератор своим
;; размером блока (латентная реентерабельность), и тесней loop.
;; Санкция пользователя 2026-07-12: 16×16 = 256 байт под одним DI
;; (как 1×256 fill) на аудио не влияет. ВНИМАНИЕ: h ограничен
;; малыми спрайтами для больших блитов (putimage 256 строк)
;; вызывающий обязан резать на чанки 16 строк (иначе долгий DI).
di
ld d, d ; 0x52 режим размера блока
ld a, #0
hr_len_imm = . - 1
ld b, b ; 0x40 стоп (B=счётчик не тронут)
hr_row:
ld a, c
out (#0x89), a ; Port_Y = y
inc c
;; ld a, (hl) ; предчитать ОЗУ[0] (accel выключен)
;; ex af, af'
ld l, l ; 0x6D армировать копию строки
ld a, (hl) ; burst: ОЗУ-копия -> память акселератора
;; ex af, af' ; A = ОЗУ[0] CPU-байт триггера корректен
ld (de), a ; burst: память акселератора -> VRAM+ОЗУ
ld b, b ; 0x40 стоп
djnz hr_row ; адреса не меняются только Port_Y
ei ; закрыть DI-окно спрайта
pop ix
pop hl ; ret-адрес; callee-pop 2 байта (w,h)
inc sp
inc sp
jp (hl)
__endasm;
}