Files
Sprinter-SDCC/libc/video/pal_get.c
T
snark13 16d3262340 Звук: насос CBL качает через W3 — вход в BIOS ломал W0
СИМПТОМ: затемнение (fade) хрипело — одинаково с играющей музыкой и в
тишине.  Ключевое наблюдение пользователя: повтор тишины обязан звучать
тишиной, значит дело не в недоливе буфера.

ПОИСК: отладочные клавиши, каждая делала ровно один кусок fade.  Ожидание
кадров — чисто; чтение палитры, запись палитры и 512 вызовов
bios_get_place() (видео вообще не трогает) — скрежет во всех трёх.
Последнее и решило: виновата не палитра, а ЛЮБОЙ вызов BIOS.

ПРИЧИНА: `rst 8` раскрывается в `out ($7C),a`, который включает системное
ПЗУ и перестраивает окно 0 (MAME sprinter.cpp, update_memory: m_pages[0] +
m_bank_view0.select).  ПЗУ ложится ПОВЕРХ страничного регистра, поэтому
запись в порт 0x82 из прерывания бесполезна — OTIR вычитывает ПЗУ и
отдаёт его в звук.  Отсюда же старое правило «глушить CBL на время
загрузки файлов»: причина была не в том, что ESTEX долго занимает CPU.

РЕШЕНИЕ (идея пользователя): качать через W3.  Он управляется только
портом 0xE2, подмену из прерывания никто не перекрывает, а BIOS во время
нашего ISR не исполняется — окно возвращается до выхода, и для него
подмена невидима.  После этого BIOS безопасен везде.

* pop_sfx.c — насос берёт взаймы W3 вместо W0, чтение по 0xC000 + смещение.
* pop_ui.c — буфер палитры по фиксированному 0x4000 (эти 256 байт DSS
  занимает только при загрузке программы): 256 байт со стека долой.
* libbgi/common/gfx_pal_write.c — запись палитры прямо в видеопамять,
  минуя BIOS.  Писалась как обход скрежета, после переноса насоса не
  нужна; оставлена как более быстрый примитив (2,5 тыс. тактов на 64
  цвета против 10,8 тыс. у BIOS) с честной шапкой.  Адресация разобрана
  по исходникам BIOS (FUNC_SCREEN.ASM): Port_Y = индекс цвета, адрес
  0xC3E0 + pal*4, порядок R/G/B/Y.
* libc/video/pal_get.c, pal_load.c — в шапках зафиксировано, что BIOS
  выбирает окно ПО АДРЕСУ БУФЕРА (`BIT 7,H`).
* pop_intro.c — при пропуске интро клавишей не глушился CBL, и следующая
  загрузка уровня шла с открытым буфером; добавлен pop_sfx_pause.
* pop_ctrl.c — убраны отладочные «осторожные шаги» на J/L (эмуляция
  Shift+стрелка для MAME), у них и стоял TODO.

Разбор целиком — docs/sound_plan.md §5.  Бюджет: _CODE 23966, куча 245 Б.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 19:36:47 +03:00

37 lines
1.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pal_get — прочитать блок палитровых записей из VRAM (BIOS $A4;
* тот же id функции, бит 7 регистра A переключает в чтение).
*
* ВНИМАНИЕ: BIOS выбирает окно ПО АДРЕСУ БУФЕРА (исходник
* docs/sources/Sprinter-BIOS/bios/exp/FUNC_SCREEN.ASM, PIC_SET_PAL:
* `BIT 7,H` -> SLOT3 либо SLOT1). Буфер выше 0x8000 заставляет его занять
* W1, где у приложений лежат резидентный код и вектор прерываний, — и всё
* время цикла ISR недоступен. Если рядом играет звук, пользуйтесь
* gfx_pal_read/gfx_pal_write из libbgi: они пишут видеопамять напрямую и
* BIOS не зовут.
*/
#include "_palette.h"
void pal_get(uint8_t pal_num, uint8_t start, uint8_t count, uint8_t *bgr0)
{
_pal_num = (uint8_t)(pal_num | 0x80); /* бит 7 = чтение */
_pal_start = start;
_pal_count = count;
_pal_data = (uint16_t)(uintptr_t)bgr0;
__asm
push ix
ld a, (__pal_start)
ld e, a ; E = start
ld a, (__pal_count)
ld d, a ; D = count (0 = 256)
ld hl, (__pal_data) ; HL = буфер
ld b, #0xFF ; B = маска
ld a, (__pal_num) ; A = 0x80 | pal_num чтение
ld c, #0xA4 ; BIOS PIC_GET_PAL (= $A4)
rst #0x08
pop ix
__endasm;
}