libc/cbl: две точки входа вместо underrun_mode — malloc больше не в резиденте
Линкер тянет .rel целиком, поэтому malloc/free, стоявшие в мёртвой ветке CBL_UNDERRUN_SILENCE внутри cbl_open, приезжали в резидент КАЖДОМУ приложению — включая те, что льют тишину сами и кучей не пользуются. Разведено: cbl_open(freq, fmt, pump, fill) — ничего не аллоцирует; cbl_open_silence(freq, fmt, pump, fill) — аллоцирует буфер тишины; _cbl_open_raw(...) — общее тело. Параметр underrun_mode из публичного API убран: режим задаёт выбор функции. cbl_close больше не зовёт free — иначе malloc возвращался бы тем же путём. Буфер тишины живёт до выхода из программы и переиспользуется; его размер запоминается, иначе открытие 16-бит после 8-бит писало бы memset'ом мимо выделенного куска. _cbl_open_raw указатель на буфер не трогает вовсе — иначе cbl_open после cbl_open_silence терял бы уже выделенную память. В дереве режим SILENCE не использовал никто: все три вызова (cblwav, cblstream, PoP) передавали CBL_UNDERRUN_APP. Итог для PoP: _CODE 24329 -> 23716 (−613 Б), свободно в резиденте 129 -> 747 Б. make size-check чистый (67 программ), звук в MAME проверен — насос отработал 696 запросов, pop_snd_ok/want = 1/1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+29
-13
@@ -44,13 +44,14 @@
|
||||
* кладёт байт как есть в один слот, не собирая пару байт в 16-бит
|
||||
* значение — это умеет только акселераторный путь (страница 0xFD).
|
||||
*
|
||||
* Поведение при недоливе — CBL_UNDERRUN_* (4-й параметр cbl_open):
|
||||
* Поведение при недоливе задаётся ВЫБОРОМ ТОЧКИ ВХОДА (cbl_open /
|
||||
* cbl_open_silence), а не параметром:
|
||||
* CBL_UNDERRUN_APP (по умолчанию, 0) — недолив не наша забота;
|
||||
* в CBL доигрывает то, что уже лежит в его буфере (никакого
|
||||
* буфера тишины не аллоцируется).
|
||||
* CBL_UNDERRUN_SILENCE (1) — насос сам пропихивает тишину при
|
||||
* недоливе; буфер тишины (128/256 Б по формату) аллоцируется
|
||||
* malloc'ом ВНУТРИ cbl_open(), только в этом режиме.
|
||||
* malloc'ом внутри cbl_open_silence(), только в этом режиме.
|
||||
* cbl_underruns() считает недоливы в ОБОИХ режимах — это диагностика,
|
||||
* поведение не меняет.
|
||||
*
|
||||
@@ -89,8 +90,10 @@
|
||||
#define CBL_PUMP_ACCEL 1 /* cbl_push_accel() — единственный путь для 16-бит */
|
||||
|
||||
/* Поведение при недоливе (fill() вернул 0 или не задан). */
|
||||
#define CBL_UNDERRUN_APP 0 /* по умолчанию: не наша забота, буфер тишины не аллоцируется */
|
||||
#define CBL_UNDERRUN_SILENCE 1 /* насос сам шлёт тишину; буфер аллоцируется в cbl_open() */
|
||||
/* Внутренние коды режима недолива: приложение их не передаёт (режим задаёт
|
||||
* выбор cbl_open / cbl_open_silence), но насос по ним и различает поведение. */
|
||||
#define CBL_UNDERRUN_APP 0 /* не наша забота, буфер тишины не аллоцируется */
|
||||
#define CBL_UNDERRUN_SILENCE 1 /* насос сам шлёт тишину из буфера libc */
|
||||
|
||||
/* fill(n): пропихнуть n байт (через cbl_push_otir/accel) прямо из
|
||||
* данных приложения. Вызывается ИЗ ISR — обязан быть быстрым (без
|
||||
@@ -98,17 +101,30 @@
|
||||
* данных сейчас (недолив). */
|
||||
typedef int (*cbl_fill_fn)(uint16_t n);
|
||||
|
||||
/* Включить CBL с частотой CBL_FREQ_*, форматом CBL_FMT_*, способом
|
||||
* выдачи CBL_PUMP_* и поведением при недоливе CBL_UNDERRUN_*; fill —
|
||||
* callback, зовущийся из ISR за новым блоком (может быть NULL, тогда
|
||||
* недолив — на каждом запросе). 0 или -1 + errno (EBUSY — уже
|
||||
* открыт; EINVAL — плохой код частоты/формат/pump/underrun_mode, или
|
||||
* не-W2 режим; ENOMEM — не хватило памяти под буфер тишины). */
|
||||
/* Включить CBL с частотой CBL_FREQ_*, форматом CBL_FMT_* и способом выдачи
|
||||
* CBL_PUMP_*; fill — callback, зовущийся из ISR за новым блоком (может быть
|
||||
* NULL, тогда недолив — на каждом запросе). Недолив НЕ наша забота
|
||||
* (CBL_UNDERRUN_APP): железо доиграет по кругу неактивную половину, и если
|
||||
* это слышно — приложение обязано отдавать тишину само.
|
||||
*
|
||||
* 0 или -1 + errno (EBUSY — уже открыт; EINVAL — плохой код частоты, формат,
|
||||
* pump, или не-W2 режим).
|
||||
*
|
||||
* ТОЧКИ ВХОДА ДВЕ, и это не косметика: cbl_open() не аллоцирует ничего и
|
||||
* потому НЕ ТЯНЕТ malloc в резидент. За тишиной от libc — cbl_open_silence()
|
||||
* ниже, и malloc приезжает только тому, кто её позвал. */
|
||||
int cbl_open(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode,
|
||||
uint8_t underrun_mode, cbl_fill_fn fill);
|
||||
cbl_fill_fn fill);
|
||||
|
||||
/* Выключить CBL, отпустить IM2-таблицу, освободить буфер тишины (если
|
||||
* был). Идемпотентно. */
|
||||
/* То же, но при недоливе тишину шлёт САМА libc (CBL_UNDERRUN_SILENCE):
|
||||
* буфер под неё аллоцируется здесь. Добавляет ENOMEM к кодам ошибок.
|
||||
* Буфер живёт до конца программы и переиспользуется при повторном открытии
|
||||
* — cbl_close() его не освобождает намеренно (иначе free вернул бы malloc
|
||||
* в резидент всем подряд). */
|
||||
int cbl_open_silence(uint8_t freq_code, uint8_t fmt, uint8_t pump_mode,
|
||||
cbl_fill_fn fill);
|
||||
|
||||
/* Выключить CBL и отпустить IM2-таблицу. Идемпотентно. */
|
||||
void cbl_close(void);
|
||||
|
||||
/* Пропихнуть n байт из src прямо в CBL (звать ИЗ fill()). */
|
||||
|
||||
Reference in New Issue
Block a user