/* * _gfx_rectfill256 — диспетчер заливки прямоугольника (x,y,w,h,color), * mode 0x81: выбирает ориентацию с меньшим числом выстрелов и передаёт * управление leaf-заливке (tail-jump, стек не трогается — ABI идентичен): * w>h && w<=256 → _gfx_recthfill256 (h горизонтальных строк) * иначе → _gfx_rectvfill256 (w вертикальных колонок) * * ---- ЦЕНА ПРОВЕРКИ и когда звать leaf'ы напрямую ------------------- * Проверка + tail-jump: ~160Т (быстрый путь w256), * типично ~200Т ≈ 9.5 мкс @21МГц. Один выстрел-линия стоит ~55-65Т * CPU-оверхеда, т.е. проверка окупается, когда выбор ориентации * экономит |w−h| >= ~4 линии. На мелких/почти квадратных * прямоугольниках (|w−h| < 4) или когда форма известна заранее — * выгоднее прямой вызов _gfx_recthfill256 / _gfx_rectvfill256 * (контракты — в их шапках: recthfill требует 1<=w<=256). * Полный бюджет тактов/размеров всех вариантов: docs/accel-fill-budget.md. * * __sdcccall(1): x→HL, y→DE(E=y); w→4/5(ix), h→6/7(ix), color→8(ix). * Диспетчер сохраняет 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 не (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 .globl __gfx_addr_base .globl __gfx_hfill256_segment .globl __gfx_vfill256_segment push ix ld ix, #0 add ix, sp ld bc, (__gfx_addr_base) add hl, bc ; HL = base + x (бегущий addr) ld a, 8 (ix) ld c, a ; C = color ;; --- ветка: 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 не (w>h) ld a, 5 (ix) ; w high cp a, #2 jr NC, rf_vbranch ; w >= 512 dec a jr NZ, rf_hbranch ; high==0 -> w<256 ld a, 4 (ix) or a, a jr NZ, rf_vbranch ; high==1,low!=0 -> w>256 rf_hbranch: ld a, 4 (ix) ld b, a ; B = len = w (256 -> 0) rf_hloop: ld a, 6 (ix) or a, 7 (ix) jr Z, rf_done ; h == 0 call __gfx_hfill256_segment inc e ; y++ ld a, 6 (ix) sub a, #1 ld 6 (ix), a ld a, 7 (ix) sbc a, #0 ld 7 (ix), a jr rf_hloop rf_vbranch: ld a, 6 (ix) ld b, a ; B = len = h (256 -> 0) rf_vloop: ld a, 4 (ix) or a, 5 (ix) jr Z, rf_done ; w == 0 call __gfx_vfill256_segment inc hl ; addr++ ld a, 4 (ix) sub a, #1 ld 4 (ix), a ld a, 5 (ix) sbc a, #0 ld 5 (ix), a jr rf_vloop rf_done: pop ix pop hl pop af pop af inc sp jp (hl) __endasm; } #endif