libc: IM2 Phase 2b — звук CBL/COVOX через callback fill(), без кольца libc
CBL уже имеет аппаратный буфер 256 Б (2×128, двойная буферизация на стороне железа) — держать поверх него ещё одно кольцо в libc было бы лишней копией. cbl_open(freq, fmt, pump_mode, underrun_mode, fill) регистрирует callback, вызываемый из ISR за очередным блоком; он сам пропихивает данные приложения (откуда угодно) через cbl_push_otir()/ cbl_push_accel() — без промежуточного буфера. - два насоса: OTIR (порт 0x4F) и ACCEL (акселератор, спец-страница EMM 0xFD@0xC000); OTIR+16-бит запрещён (EINVAL) — по исходнику MAME порт данных физически не может собрать 16-бит сэмпл из пары байт; - форматы CBL_FMT_MONO8/16/STEREO8/16, частоты 7.8..109к; - CBL_UNDERRUN_APP (по умолчанию, недолив не наша забота) / CBL_UNDERRUN_SILENCE (буфер тишины malloc'ится только в этом режиме); - tests/cbltest: матрица 64 комбинации (2 насоса × 8 форматов × 4 частоты); tests/cblwav: banked-стрим речи с дискеты (физстраницы кэшированы заранее — mem_get_page нельзя звать из fill()/ISR); tests/cblstream: единственный случай с собственным кольцом уровня приложения (диск нельзя читать из fill()). Verified в MAME 2026-07-07 — все три теста работают. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* _cbl.h — внутренности CBL-модуля (НЕ публичный заголовок).
|
||||
*
|
||||
* Механика (форум Sprinter Team + официальная документация "5.3
|
||||
* COVOX-Blaster" + docs/converted/accel_r.txt):
|
||||
* - порт управления 0x004E — 16-битный (только ld bc,#0x004E /
|
||||
* out (c),a): bit7 = CBL on, bit6 = stereo, bit5 = 16-бит,
|
||||
* bit4 = int enable, bits3..0 = частота; выключение — запись 0;
|
||||
* - буфер 256 Б аппаратно разбит на две половины по 128 Б; бит 7
|
||||
* порта 0xFE отражает, какая половина ИГРАЕТ сейчас — флип этого
|
||||
* бита поднимает прерывание (вектор 0xFF), пора долить неактивную
|
||||
* половину;
|
||||
* - размер блока — 128 Б для 8-бит формата, 256 Б для 16-бит (не
|
||||
* зависит от моно/стерео) — см. _cbl_block;
|
||||
* - выдача блока — ДВА способа (cbl_push_otir.c/cbl_push_accel.c):
|
||||
* OTIR в порт 0x4F, либо акселератором в спец-страницу EMM 0xFD
|
||||
* (маппится в W3 на 0xC000); библиотека сама НИЧЕГО не пропихивает
|
||||
* — это делает fill()-callback приложения;
|
||||
* - насос вызывается из кадрового трамплина через хук _irq_cbl_hook
|
||||
* (см. _irq.h) — прямой ссылки irq→cbl нет, DCE сохраняется.
|
||||
*
|
||||
* Никакого собственного кольца НЕТ — второй буфер поверх аппаратного
|
||||
* был бы избыточен. _cbl_fill — callback приложения; _cbl_silence —
|
||||
* буфер тишины, malloc'ится в cbl_open() ТОЛЬКО при
|
||||
* CBL_UNDERRUN_SILENCE (иначе NULL).
|
||||
*/
|
||||
#ifndef _CBL_INTERNAL_H
|
||||
#define _CBL_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cbl.h>
|
||||
|
||||
#define _CBL_CTRL_PORT 0x004E
|
||||
#define _CBL_DATA_PORT 0x4F
|
||||
#define _CBL_ACCEL_PAGE 0xFD /* спец-страница EMM: запись на W3@0xC000 идёт в CBL */
|
||||
|
||||
extern uint16_t _cbl_block; /* размер блока: 128 или 256 (по формату) */
|
||||
extern uint16_t _cbl_reqs; /* блоков-запросов обслужено */
|
||||
extern uint16_t _cbl_undr; /* из них недолив (fill вернул 0/не задан) */
|
||||
extern cbl_fill_fn _cbl_fill; /* callback приложения, может быть NULL */
|
||||
extern uint8_t _cbl_underrun_mode; /* CBL_UNDERRUN_* */
|
||||
extern uint8_t *_cbl_silence; /* буфер тишины или NULL */
|
||||
|
||||
/* Запись в 16-битный порт управления 0x004E. */
|
||||
void _cbl_ctrl(uint8_t v);
|
||||
|
||||
/* ISR-насосы: вызвать fill(), при недоливе — тишина по режиму (один
|
||||
* регистрируется в _irq_cbl_hook при cbl_open — по выбору CBL_PUMP_*). */
|
||||
void _cbl_pump_otir(void);
|
||||
void _cbl_pump_accel(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user