b34997073e
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
52 lines
2.9 KiB
C
52 lines
2.9 KiB
C
/*
|
|
* _cbl_port — разделяемое владение bit7 порта управления 0x004E между
|
|
* реальной CBL-сессией (cbl_open/cbl_close) и другими держателями
|
|
* (сейчас — gfx_wait_vsync(), которому нужен только бит 5 порта 0xFE,
|
|
* доступный лишь пока включён cbl_mode(); см. libc/gfx/gfx_wait_vsync.c
|
|
* и MAME sprinter.cpp kbd_fe_r).
|
|
*
|
|
* Если реальный CBL уже открыт (_irq_cbl_hook != 0) — портом владеет
|
|
* он, ref/unref его не трогают вообще (это уже нужное состояние).
|
|
* Иначе включаем/выключаем 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"
|
|
#include "../irq/_irq.h"
|
|
|
|
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)
|
|
{
|
|
_cbl_port_refs++;
|
|
_cbl_port_sync();
|
|
}
|
|
|
|
void _cbl_port_unref(void)
|
|
{
|
|
if (_cbl_port_refs) _cbl_port_refs--;
|
|
_cbl_port_sync();
|
|
}
|