libbgi: блочные AND/OR/XOR акселератора (блит строками и колонками)

Акселератор умеет не только копировать блок, но и совмещать его с
приёмником: опкод `and/or/xor (hl)` между триггерами чтения и записи
переводит внутренний автомат из «буфер := память» в «буфер <op>= память».
Операция ортогональна направлению (гориз. LD L,L / верт. LD A,A), значит
одинаково работает и для row-major картинок, и для column-major спрайтов
персонажей с бесплатным флипом.

Полный набор, по образцу существующего копирующего:
- ядра bgi256/_bgi_blit_rows_op_raw.c и _bgi_blit_cols_op_raw.c;
- строками: gfx_blit_op / gfx_blit_part_op (через _gfx_blit_full_op);
- колонками: gfx_blit_cols_op / gfx_blit_cols_part_wx_op (skip/rows/
  skipw/maxw и flip — как у копирующего близнеца);
- putimage(XOR/OR/AND_PUT) переведён на accel, попиксельным остался
  только NOT_PUT — закрыт пункт 2d-1 docs/TODO.md.

Одна функция на три операции: опкод патчится SMC, как размер блока и
страйд, — ветвления в цикле нет.  Колоночный путь дороже строкового на
один OUT Port_Y: вертикальный op-burst шагает Port_Y, и перед записью
его надо вернуть на верх колонки (STOP обязателен — иначе fetch операнда
OUT перезапустит burst, memory/accel_operand_fetch_retrigger).

Две оговорки (в шапках модулей):
- операция ЧИТАЕТ ОЗУ-копию экрана, а не видео-ОЗУ, поэтому при банках
  0x54/0x5C совмещается с чистым фоном, а не с нарисованным поверх;
- аппаратная прозрачность #FF совместима с AND (нейтраль) и OR (#FF|bg =
  #FF, запись подавляется), но НЕ с XOR: там источник обязан хранить
  прозрачный пиксель как 0x00.

Проверка: tests/accop (новый) — 8/8 PASS в MAME, побайтно, источник с
разными значениями по строкам И колонкам + рамка вокруг; tests/bgi_img
получил две байтовые самопроверки (COPY==источник, XOR дважды == фон),
обе PASS.  make size-check: роста нет (эталон принят заново — kbdpoll
+63 Б приехал из прошлой сессии, воспроизводится и без этих правок).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 15:03:47 +03:00
parent d154cb452c
commit a823e7ee9c
15 changed files with 829 additions and 23 deletions
+40
View File
@@ -15,6 +15,15 @@
* Прогон в MAME визуальный: см. что источник и его COPY-копия
* идентичны (в т.ч. красный маркер в левом-верхнем углу — ловит
* зеркалирование), а XOR-дважды не оставляет следа на фоне.
*
* 2026-08-11: XOR/OR/AND_PUT переведены с попиксельного цикла на блочные
* операции акселератора (gfx_blit_part_op), поэтому к визуальной проверке
* добавлены ДВЕ БАЙТОВЫЕ (PASS/FAIL на экране) — глазами тут промах на
* пиксель или уехавший Port_Y не поймать:
* P1 COPY == источник побайтно (клип/адресация не сдвинули образ);
* P2 XOR дважды == чистый фон побайтно (op-burst читает ровно тот байт
* приёмника, поверх которого потом пишет).
* Механика самих блочных операций проверяется отдельно — tests/accop.
*/
#include <graphics.h>
@@ -53,10 +62,30 @@ static void draw_source(void)
rectangle(l - 1, t - 1, r + 1, b + 1); /* рамка вокруг источника */
}
/* Прямоугольник (x0,y0,w,h) совпадает с прямоугольником (x1,y1,w,h)? */
static uint8_t rect_eq(int x0, int y0, int x1, int y1, int w, int h)
{
int cx, cy;
for (cy = 0; cy < h; cy++)
for (cx = 0; cx < w; cx++)
if (getpixel(x0 + cx, y0 + cy) != getpixel(x1 + cx, y1 + cy))
return 0;
return 1;
}
static void say(int x, int y, const char *s, uint8_t ok)
{
setcolor(ok ? LIGHTGREEN : LIGHTRED);
outtextxy(x, y, s);
outtextxy(x + textwidth((char *)s) + 4, y, ok ? "PASS" : "FAIL");
}
int main(void)
{
static const int ops[5] = { COPY_PUT, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT };
static const char *names[5] = { "COPY", "XOR", "OR", "AND", "NOT" };
uint8_t p_copy, p_xor2;
int i, x;
int sl = SPR_L, st = SPR_T;
int sr = SPR_L + SPR_W - 1, sb = SPR_T + SPR_H - 1;
@@ -95,6 +124,10 @@ int main(void)
putimage(x, 120, sprite, ops[i]);
}
/* P1: COPY-копия (x = 16, первая в ряду) обязана совпасть с источником
* побайтно — ловит сдвиг на пиксель и зеркалирование. */
p_copy = rect_eq(16, 120, sl, st, SPR_W, SPR_H);
/* --- XOR дважды = восстановление фона --- */
setcolor(WHITE);
outtextxy(16, 176, "XOR x2 -> restores bg (patch stays clean):");
@@ -110,5 +143,12 @@ int main(void)
setcolor(WHITE);
outtextxy(130, 202, "<- these two must match ->");
/* P2: наложенный и снятый XOR не оставил следа — сравниваем с
* нетронутым зелёным эталоном справа. */
p_xor2 = rect_eq(16, 190, 80, 190, SPR_W, SPR_H);
say(16, 228, "P1 COPY==src:", p_copy);
say(16, 240, "P2 XORx2==bg:", p_xor2);
for (;;) { }
}