/*
 * 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 (;;) { }
}
