libbgi: chunked-заливки на мульти-триггере акселератора + сплит rectfill
Семантика FSM акселератора вскрыта по драйверу MAME (sprinter.cpp) и подтверждена экспериментами в MAME (tests/accfill): армирование живёт до следующего accel-опкода (мульти-триггер работает); под армированием триггерит ЛЮБОЙ non-M1 доступ к памяти (fetch операнда djnz/out!); вертикальный Fill двигает Port_Y и не возвращает; размер блока переживает LD B,B. Детали: memory/accel_multitrigger_fill. - _bgi_clear_raw: 20 DI-скобок по 16 колонок вместо полного брекета на каждую из 320 колонок; армирование размера один раз на скобку. - _gfx_rectfill256 разделён: диспетчер (проверка ориентации ~160-245Т, break-even |w-h| >= ~4) + leaf'ы _gfx_recthfill256/_gfx_rectvfill256 для прямого вызова, когда форма известна заранее. - Leaf'ы: чанки <=16 линий одной скобкой (~54-56Т/линию против ~250Т у per-line варианта); счётчик чанков precompute'ится в байт-регистр (dec e/jr nz ~46Т/чанк вместо 16-бит арифметики в IX-слотах ~173Т/чанк); хвост — отдельная скобка со своим армированием (CBL-ISR в окне EI армирует акселератор своим размером — не выносить). - getpixel/putpixel/_bgi_read: уборка мёртвого закомментированного кода. - tests/accfill: регресс chunked-заливок (B0 clear, B1 vert 1+3 чанка, B2 horz чанк+хвост, полноширинный bar 320x8 — путь w>=256). Прежние реализации сохранены под #if 0 для отката/сравнения. Проверено в MAME (все PASS); семантика эмуляции — перепроверить на реальном Sprinter. size-baseline: accfill добавлен, gfx_demo +54 Б (обвязка диспетчера), остальные без роста. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,19 +1,71 @@
|
||||
/*
|
||||
* _gfx_rectfill256 — заливка прямоугольника (x,y,w,h) цветом color, mode 0x81.
|
||||
* _gfx_rectfill256 — диспетчер заливки прямоугольника (x,y,w,h,color),
|
||||
* mode 0x81: выбирает ориентацию с меньшим числом выстрелов и передаёт
|
||||
* управление leaf-заливке (tail-jump, стек не трогается — ABI идентичен):
|
||||
* w>h && w<=256 → _gfx_recthfill256 (h горизонтальных строк)
|
||||
* иначе → _gfx_rectvfill256 (w вертикальных колонок)
|
||||
*
|
||||
* Выбор ориентации burst'а: если w>h и w<=256 — гоним h горизонтальных
|
||||
* Fill'ов шириной w (y++ на каждой строке); иначе w вертикальных Fill'ов
|
||||
* высотой h (addr++ на каждой колонке). Инварианты (color=C, len=B) и
|
||||
* бегущий addr=HL/y=E живут в регистрах через весь цикл — _gfx_*_segment
|
||||
* их сохраняет; счётчик другой размерности крутится в его стек-слоте.
|
||||
* ---- ЦЕНА ПРОВЕРКИ и когда звать leaf'ы напрямую -------------------
|
||||
* Проверка + tail-jump: ~160Т (быстрый путь w<h) … ~245Т (w>256),
|
||||
* типично ~200Т ≈ 9.5 мкс @21МГц. Один выстрел-линия стоит ~55-65Т
|
||||
* CPU-оверхеда, т.е. проверка окупается, когда выбор ориентации
|
||||
* экономит |w−h| >= ~4 линии. На мелких/почти квадратных
|
||||
* прямоугольниках (|w−h| < 4) или когда форма известна заранее —
|
||||
* выгоднее прямой вызов _gfx_recthfill256 / _gfx_rectvfill256
|
||||
* (контракты — в их шапках: recthfill требует 1<=w<=256).
|
||||
*
|
||||
* __sdcccall(1): x→HL, y→DE(E=y); w→4/5(ix), h→6/7(ix), color→8(ix).
|
||||
* Pre: W3 замаплен, DI активен вокруг выстрелов внутри segment'ов.
|
||||
* Вызывающий управляет _bgi_begin/_bgi_end. w,h предполагаются >= 0.
|
||||
* Диспетчер сохраняет HL/DE и стек как есть; leaf делает свой
|
||||
* push ix и callee-pops. Pre/контракты — как у leaf'ов (W3 замаплен,
|
||||
* без клиппинга, w,h >= 0).
|
||||
*/
|
||||
|
||||
#include "../_bgi.h"
|
||||
|
||||
void _gfx_rectfill256(int x, int y, int w, int h, uint8_t color) __naked
|
||||
{
|
||||
__asm
|
||||
.globl __gfx_recthfill256
|
||||
.globl __gfx_rectvfill256
|
||||
push ix
|
||||
ld ix, #0
|
||||
add ix, sp ; только чтобы прочитать w/h; HL/DE не трогаем
|
||||
|
||||
;; --- w>h && w<=256 ? (unsigned, w/h >= 0) ---
|
||||
ld a, 4 (ix)
|
||||
sub a, 6 (ix)
|
||||
ld b, a ; (w-h) низкий
|
||||
ld a, 5 (ix)
|
||||
sbc a, 7 (ix) ; CF=1 если w<h
|
||||
jr C, disp_v
|
||||
or a, b
|
||||
jr Z, disp_v ; w==h -> не (w>h)
|
||||
ld a, 5 (ix) ; w high
|
||||
cp a, #2
|
||||
jr NC, disp_v ; w >= 512
|
||||
dec a
|
||||
jr NZ, disp_h ; high==0 -> w<256
|
||||
ld a, 4 (ix)
|
||||
or a, a
|
||||
jr NZ, disp_v ; high==1,low!=0 -> w>256
|
||||
; w==256 -> горизонталь (низкий байт 0 = «256»)
|
||||
disp_h:
|
||||
pop ix
|
||||
jp __gfx_recthfill256 ; tail-jump: аргументы на стеке как есть
|
||||
disp_v:
|
||||
pop ix
|
||||
jp __gfx_rectvfill256
|
||||
__endasm;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* ================================================================
|
||||
* Старый вариант (до 2026-07-10): полный брекет (арм+выстрел+выкл)
|
||||
* на КАЖДУЮ линию через call _gfx_*fill256_segment — ~100Т+call на
|
||||
* линию. Оставлен закомментированным для отката/сравнения.
|
||||
* (Промежуточный monolith-вариант с chunked-ветками жил здесь
|
||||
* 2026-07-10 и разъехался по _gfx_recthfill256.c/_gfx_rectvfill256.c.)
|
||||
* ================================================================ */
|
||||
void _gfx_rectfill256(int x, int y, int w, int h, uint8_t color) __naked
|
||||
{
|
||||
__asm
|
||||
@@ -89,3 +141,4 @@ void _gfx_rectfill256(int x, int y, int w, int h, uint8_t color) __naked
|
||||
jp (hl)
|
||||
__endasm;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user