libc/cbl: выключение CBL больше не оставляет железо петь одну ноту
cbl_close() не пишет в порт управления ноль: пока gfx_wait_vsync держит ссылку ради бита луча (в PoP её берёт pop_pace_arm на всю программу), bit7 остаётся включённым. А буфер CBL (256 слотов) при включённом bit7 крутится по кругу и не чистится ничем — железо бесконечно поёт хвост последнего сэмпла, тоном и громкостью по последней мелодии. Пойман пользователем на железе: Ctrl+S во время музыки и пропуск заставки давали ноту до следующего cbl_open. В MAME не воспроизводится: "немым" кодом частоты был reserved-код 2, у которого divs[2]==0 и таймер не заводится вовсе. На железе reserved-коды не определены, ЦАП тактируется — тишина держалась на свойстве эмулятора, а не железа. Теперь тишину даёт СОДЕРЖИМОЕ БУФЕРА: - _cbl_port_sync() после каждой записи в порт управления зовёт _cbl_prime(0x80). Это закрывает и паузу звука, и включение bit7 ради луча на холодном старте (в буфере лежал мусор от прошлой программы), и полное выключение — при bit7=0 те же 256 записей уходят прямо в ЦАП обычного COVOX и центруют его, снимая щелчок; - _CBL_VSYNC_FREQ переведён с reserved-кода 2 на документированный 8 (7,8125 кГц): поведение определено и на железе, и в MAME, прерывания по-прежнему выключены (bit4=0), а бит 7 порта 0xFE трамплин смотрит только при живом хуке насоса; - cbl_close() зовёт sync внутри той же DI-скобки, где снимает хук, иначе насос долил бы буфер уже после заливки. Цена: +2 Б программам со звуком, +11 Б графическим (тянется _cbl_prime следом за gfx_wait_vsync), 256 OUT'ов (~0,3 мс) на редкое событие — эталоны cblstream/cbltest/cblwav/gfx_dbuf обновлены. Рост atlas в size-check к этой правке отношения не имеет (замерен тот же и без неё). Проверено: кодоген _cbl_port.asm; SprPoP пересобран и прогнан в MAME (титры → пропуск заставки → уровень 1, пейсинг по лучу жив). Сам баг проверяется только на железе. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DSYUpuaQpKr48kBav2iiV4
This commit is contained in:
+20
-3
@@ -7,9 +7,23 @@
|
||||
*
|
||||
* Если реальный CBL уже открыт (_irq_cbl_hook != 0) — портом владеет
|
||||
* он, ref/unref его не трогают вообще (это уже нужное состояние).
|
||||
* Иначе включаем/выключаем bit7 "немым" кодом частоты _CBL_VSYNC_FREQ
|
||||
* — таймер CBL при этом коде не заводится (divs[2]=0 в MAME), значит
|
||||
* ни звука, ни прерываний, только доступ к синхро-биту.
|
||||
* Иначе включаем/выключаем bit7 "немым" кодом частоты _CBL_VSYNC_FREQ.
|
||||
*
|
||||
* ТИШИНУ ДАЁТ ЗАЛИТЫЙ БУФЕР, А НЕ ОСТАНОВЛЕННЫЙ ТАЙМЕР. Раньше здесь
|
||||
* стоял reserved-код частоты 2 — ровно потому, что в MAME при нём не
|
||||
* заводится таймер (divs[2]=0). На железе поведение reserved-кодов не
|
||||
* определено, ЦАП тактируется, и включённый bit7 поверх старого буфера
|
||||
* даёт бесконечную ноту из хвоста последнего сэмпла (пойман Ctrl+S во
|
||||
* время музыки, 2026-09-02; разбор — в шапке _cbl.h). Поэтому после
|
||||
* КАЖДОЙ записи в порт управления заливаем все 256 слотов тишиной:
|
||||
* - bit7 включён — крутится тишина (беззвучно на любом железе);
|
||||
* - bit7 выключен — те же записи уходят в ЦАП обычного COVOX и
|
||||
* центруют его на 0x80, снимая щелчок/постоянное смещение.
|
||||
* Оба состояния редкие (старт пейсинга, пауза звука, выход), 256 OUT'ов
|
||||
* — около 0,3 мс.
|
||||
*
|
||||
* Цена для ГРАФИЧЕСКОЙ программы без звука: _cbl_prime (~10 Б кода)
|
||||
* приезжает следом за gfx_wait_vsync. Дешевле, чем гудящее железо.
|
||||
*/
|
||||
|
||||
#include "_cbl.h"
|
||||
@@ -19,6 +33,9 @@ void _cbl_port_sync(void)
|
||||
{
|
||||
if (_irq_cbl_hook) return; /* реальный CBL сам владеет портом */
|
||||
_cbl_ctrl(_cbl_port_refs ? (uint8_t)(0x80 | _CBL_VSYNC_FREQ) : 0);
|
||||
/* Формат "немого" режима всегда 8-битный (bit5 не выставлен), поэтому
|
||||
* тишина здесь — 0x80 независимо от того, каким был закрытый сеанс. */
|
||||
_cbl_prime(0x80);
|
||||
}
|
||||
|
||||
void _cbl_port_ref(void)
|
||||
|
||||
Reference in New Issue
Block a user