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:
@@ -0,0 +1,4 @@
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := accfill
|
||||
EXTRA_FLAGS ?= --gfx 256
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 (;;) { }
|
||||
}
|
||||
Reference in New Issue
Block a user