/* * gfx_pal_write — записать блок палитровых записей ПРЯМО в видеопамять, * минуя BIOS $A4. * * КОГДА НУЖНА. Штатный gfx_pal_load идёт через BIOS, а вход в BIOS * (`rst 8` = `out ($7C),a`) включает системное ПЗУ и перестраивает окно 0. * Пока это так, любой код, читающий данные ИЗ W0 в прерывании, получит * вместо них ПЗУ. В PoP на этом рвался звук, пока насос CBL брал взаймы * W0; после переноса насоса на W3 (см. pop_sfx.c) BIOS снова безопасен, и * в самой игре этот примитив не нужен. * * Остаётся полезен там, где BIOS звать нельзя по другим причинам, и просто * как более быстрый путь: цикл ниже кладёт 64 цвета примерно за 2,5 тыс. * тактов против 10,8 тыс. у BIOS (замеры в MAME, 2026-08-25). * * КАК АДРЕСУЕТСЯ ПАЛИТРА (исходник BIOS, FUNC_SCREEN.ASM, PIC_SET_PAL). * Port_Y выбирает ИНДЕКС ЦВЕТА и инкрементируется на каждый цвет; адрес * записи — 0xC3E0 + pal*4, внутри четвёрки порядок R, G, B, Y, а на входе * данные лежат как B, G, R, Y. Окно на время работы держит страницу 0x50. */ #include "../_bgi.h" #include /* Port_Y (0x89) как SFR: у libc готового объявления нет, а держать здесь * asm-вставку ради одного OUT дороже, чем одна строка. */ __sfr __at PORT_RGADR _io_port_y; /* Палитровые байты начинаются в килобайтной строке со смещения 0x3E0. */ #define PAL_SLOT0 0xC3E0u void gfx_pal_write(uint8_t pal_num, uint8_t start, uint8_t count, const uint8_t *bgr0) { uint8_t *slot = (uint8_t *)(PAL_SLOT0 + ((uint16_t)pal_num << 2)); uint8_t saved_bank = _gfx_bank; uint8_t y = start; /* Писать обязательно ОБЫЧНЫМ банком: в прозрачном (0x5C) байт 0xFF не * записывается, и белые компоненты палитры молча терялись бы. */ _gfx_bank = GFX_BANK_NORMAL; _bgi_begin(); do { /* count == 0 означает 256 цветов */ _io_port_y = y++; slot[2] = *bgr0++; /* B */ slot[1] = *bgr0++; /* G */ slot[0] = *bgr0++; /* R */ slot[3] = *bgr0++; /* Y */ } while (--count); _bgi_end(); _gfx_bank = saved_bank; }