Files
Sprinter-SDCC/tests/accfill/accfill.c
T
snark13 2c414da465 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>
2026-07-10 17:41:49 +03:00

96 lines
4.6 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.
/*
* accfill — регресс chunked-заливок libbgi на мульти-триггере акселератора
* (B0: cleardevice/_bgi_clear_raw; B1: bar → _gfx_rectvfill256, пути
* «1 чанк», «2 чанка + хвост»; B2: bar → _gfx_recthfill256, «чанк + хвост»;
* плюс полноширинный bar 320×8 — precompute-путь w>=256).
*
* Семантика FSM (из драйвера MAME src/mame/sinclair/sprinter.cpp;
* согласуется с примерами docs/part2/accelerator_doc.txt; сырые
* asm-эксперименты E1-E3, подтвердившие её, удалены — см. git history
* 2026-07-10 и memory/accel_multitrigger_fill):
* - армирование (LD C,C / LD E,E / ...) живёт до следующего accel-опкода —
* мульти-триггер поддерживается;
* - под армированием триггерит ЛЮБОЙ non-M1 доступ к памяти: в т.ч. fetch
* immediate/displacement (djnz/jr/ld a,#n) и стек → между триггерами
* допустимы ТОЛЬКО регистровые M1-опкоды, либо выключать (LD B,B);
* - вертикальный Fill двигает Port_Y (+len) и НЕ возвращает; адрес
* константен. Горизонтальный — двигает адрес, Port_Y на месте;
* - OUT — I/O, акселератор не триггерит (но fetch операнда порта — да,
* поэтому OUT делать при выключенном акселераторе);
* - размер блока хранится во внутреннем регистре и переживает LD B,B —
* армировать размер достаточно один раз на скобку.
*
* Верификация: getpixel по всем линиям прямоугольника + нетронутый фон
* в 1px вокруг. Результат (PASS/FAIL) печатается на экране.
*/
#include <graphics.h>
/* Прямоугольник (x0,y0,w,h) залит col целиком, а 1px вокруг — фон (0)?
* Сканируем все колонки в трёх строках и все строки в трёх колонках —
* ловит пропуск отдельного триггера (дырку в колонке/строке). */
static uint8_t rect_ok(int x0, int y0, int w, int h, color_t col)
{
int i;
for (i = 0; i < w; i++) {
if (getpixel(x0 + i, y0) != col) return 0;
if (getpixel(x0 + i, y0 + h / 2) != col) return 0;
if (getpixel(x0 + i, y0 + h - 1) != col) return 0;
}
for (i = 0; i < h; i++) {
if (getpixel(x0, y0 + i) != col) return 0;
if (getpixel(x0 + w / 2, y0 + i) != col) return 0;
if (getpixel(x0 + w - 1, y0 + i) != col) return 0;
}
/* вокруг — нетронутый фон */
if (getpixel(x0 - 1, y0) != 0) return 0;
if (getpixel(x0 + w, y0) != 0) return 0;
if (getpixel(x0, y0 - 1) != 0) return 0;
if (getpixel(x0, y0 + h) != 0) return 0;
return 1;
}
int main(void)
{
uint8_t b0;
initgraph();
cleardevice();
/* B0: cleardevice (chunked _bgi_clear_raw) — углы и центр чистые */
b0 = getpixel(0, 0) == 0 && getpixel(319, 0) == 0 &&
getpixel(0, 255) == 0 && getpixel(319, 255) == 0 &&
getpixel(160, 128) == 0;
setcolor(WHITE);
outtextxy(8, 8, "ACCEL multi-trigger fill test v3");
/* B1: bar → вертикальная ветка rectfill: 1 чанк (16 кол.) и 3 чанка (40) */
setfillstyle(SOLID_FILL, LIGHTBLUE);
bar(16, 60, 31, 123); /* 16×64 */
setfillstyle(SOLID_FILL, YELLOW);
bar(230, 60, 269, 119); /* 40×60 */
/* B2: bar → горизонтальная ветка rectfill: 2 чанка (20 строк) */
setfillstyle(SOLID_FILL, LIGHTMAGENTA);
bar(200, 18, 299, 37); /* 100×20 */
bar(0, 8, 319, 15); /* 320×8 */
outtextxy(8, 132, b0
? "B0 cleardevice chunked: PASS"
: "B0 cleardevice chunked: FAIL");
outtextxy(8, 144, (rect_ok(16, 60, 16, 64, LIGHTBLUE) &&
rect_ok(230, 60, 40, 60, YELLOW))
? "B1 bar vert 1+3 chunks: PASS"
: "B1 bar vert 1+3 chunks: FAIL");
outtextxy(8, 156, rect_ok(200, 18, 100, 20, LIGHTMAGENTA)
? "B2 bar horz 2 chunks: PASS"
: "B2 bar horz 2 chunks: FAIL");
outtextxy(8, 208, "done");
for (;;) { }
}