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
+35
View File
@@ -156,6 +156,41 @@ void gfx_blit_cols_part_w(int x, int y, const void *img, uint8_t flip,
void gfx_blit_cols_part_wx(int x, int y, const void *img, uint8_t flip,
int skip, int rows, uint8_t skipw, uint8_t maxw);
/* ---- Блит колонками с ЛОГИЧЕСКОЙ ОПЕРАЦИЕЙ ------------------------ *
* Акселератор умеет не только копировать блок, но и совмещать его с тем,
* что уже лежит в приёмнике: приёмник = приёмник <op> источник. Значения
* GFX_OP_* — это ОПКОДЫ Z80 `and/or/xor (hl)`: именно ими переключается
* автомат акселератора, и именно они патчатся SMC в ядре (одна функция на
* все три операции, ветвления в цикле нет). Иных значений не бывает.
*
* ПРОЗРАЧНОСТЬ. Аппаратная прозрачность (банк с битом 3 — не писать #FF)
* смотрит на РЕЗУЛЬТАТ, а не на источник:
* GFX_OP_AND — #FF нейтрален сам по себе, обычный атлас годится;
* GFX_OP_OR — #FF | bg = #FF, подавляется банком 0x58/0x5C — обычный
* атлас годится;
* GFX_OP_XOR — с прозрачным #FF даёт инверсию фона по всему футпринту;
* источник ОБЯЗАН хранить прозрачный пиксель как 0x00.
* Операция читает приёмник из ОЗУ-копии экрана: при банках 0x54/0x5C это
* ЧИСТЫЙ ФОН (нарисованного поверх не видно), при 0x50 — реальная картинка.
* Подробности — шапка common/gfx_blit_cols_part_wx_op.c. */
#define GFX_OP_AND 0xA6 /* опкод `and (hl)` */
#define GFX_OP_XOR 0xAE /* опкод `xor (hl)` */
#define GFX_OP_OR 0xB6 /* опкод `or (hl)` */
/* --- строками (row-major, как gfx_blit/gfx_blit_part) --- */
void gfx_blit_op(int x, int y, const void *img, uint8_t op);
void gfx_blit_part_op(int x, int y, const void *img,
int sx, int sy, int w, int h, uint8_t op);
/* --- колонками (column-major, как gfx_blit_cols; flip бесплатный) --- */
void gfx_blit_cols_op(int x, int y, const void *img, uint8_t flip, uint8_t op);
/* Полный вариант: те же клип-параметры, что у gfx_blit_cols_part_wx
* (skip/rows — обрезка сверху, skipw/maxw — окно по колонкам). */
void gfx_blit_cols_part_wx_op(int x, int y, const void *img, uint8_t flip,
int skip, int rows, uint8_t skipw, uint8_t maxw,
uint8_t op);
/* То же БЕЗ клипа по экрану — пара к gfx_blit_cols_part так же, как
* gfx_blit_part_noclip к gfx_blit_part. Вызывающий гарантирует: спрайт
* целиком на экране, ширина/высота кадра и y <= 255, skip < высоты.