/* * spriteclip — ЭКСПЕРИМЕНТ (гипотеза пользователя 2026-07-12): режет ли * ЖЕЛЕЗО спрайт, выведенный за ПРАВЫЙ/НИЖНИЙ край экрана, БЕЗ * программного клипа? Или запись за x>=320 / y>=256 портит соседнюю * память (следующую строку / страницу 1 / верх экрана)? * * Метод: блит 16×16 НЕПРОЗРАЧНОГО белого спрайта мимо клипа — прямым * вызовом leaf'а _bgi_copy_rows_raw (в обход _gfx_blit_clip). Фон — * синий; зелёные линии-маркеры на x=319 и y=255 (граница экрана); * левый край (0..7) и верх (0..7) залиты красным-маркером, чтобы * поймать «заворот» переполнения именно туда. * * Читать скриншот: * - ПРАВЫЙ (спрайт в x=312): если видно только 8 левых колонок белого * (x=312..319), а правых 8 нет И красная левая полоса цела → * железо режет по правому краю. Если правые 8 колонок «завернулись» * белым в x=0..7 (поверх красного) или появился мусор — НЕ режет, * клип обязателен. * - НИЖНИЙ (спрайт в y=250): если видно 6 строк белого (y=250..255), * а строк за 256 нет И красная верхняя полоса цела → железо режет по * нижнему. Если белое всплыло сверху (y=0..) — Port_Y завернулся. * - УГОЛ (x=312,y=250): комбинация. * * НЕ для CI-регресса — разовый hardware-probe (и в MAME, и на железе). */ #include #include #include #include /* Внутренние символы libbgi (глобальны в bgi256.lib) — тянем напрямую * ради no-clip блита. Обычному коду так делать НЕ надо (есть gfx_blit). */ extern void _bgi_begin(void); extern void _bgi_end(void); extern void _bgi_copy_rows_raw(const uint8_t *src, uint8_t *dst, uint8_t w, uint8_t h, int dstride, int sstride, uint8_t y0); extern uint16_t _gfx_addr_base; #define BW 16 static uint8_t sprite[4 + BW * BW]; static void build_sprite(void) { uint8_t *p = sprite; int i; *p++ = BW; *p++ = 0; *p++ = BW; *p++ = 0; for (i = 0; i < BW * BW; i++) *p++ = WHITE; /* непрозрачный: каждый байт пишется */ } /* Блит БЕЗ клипа: адрес = base + x, Port_Y стартует с y, строки шагают * Port_Y'ем (dstride 0). x/y могут выходить за экран — в этом и суть. */ static void blit_noclip(int x, int y) { uint8_t *dst = (uint8_t *)(_gfx_addr_base + x); gfx_set_bank(GFX_BANK_NORMAL); _bgi_begin(); _bgi_copy_rows_raw(sprite + 4, dst, BW, BW, 0, BW, (uint8_t)y); _bgi_end(); } int main(void) { build_sprite(); initgraph(); /* Фон синий. */ setfillstyle(SOLID_FILL, BLUE); bar(0, 0, 319, 255); /* Красные маркер-полосы: левые 8 колонок и верхние 8 строк — * сюда «завернётся» переполнение вправо/вниз, если железо не режет. */ setfillstyle(SOLID_FILL, RED); bar(0, 0, 7, 255); bar(0, 0, 319, 7); /* Зелёные маркеры границы экрана. */ setcolor(GREEN); line(319, 0, 319, 255); line(0, 255, 319, 255); /* Sanity: клипнутый putsprite тем же спрайтом в безопасном месте. */ putsprite(140, 120, sprite); /* Эксперимент — три no-clip блита за края: */ blit_noclip(312, 100); /* правый: x+16=328, 8 колонок за 320 */ blit_noclip(100, 250); /* нижний: y+16=266, 10 строк за 256 */ blit_noclip(312, 250); /* угол: и вправо, и вниз */ getch(); closegraph(); return 0; }