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,49 @@
|
||||
/*
|
||||
* cbl_push_accel — пропихнуть n байт из src в CBL акселератором,
|
||||
* записью на спец-страницу EMM 0xFD (маппится в W3 на 0xC000; см.
|
||||
* официальную доку "5.3 COVOX-Blaster" и docs/converted/accel_r.txt).
|
||||
* Звать ИЗ fill()-callback'а — единственный способ получить настоящий
|
||||
* 16-бит сэмпл (порт 0x4F/OTIR этого не умеет).
|
||||
*
|
||||
* Последовательность акселератора (см. libc/gfx/_gfx_hfill256.c —
|
||||
* тот же рабочий паттерн SMC для immediate-размера): LD D,D (режим
|
||||
* размера блока) → immediate LD A,n (патчится SMC — 0 значит 256,
|
||||
* тот же трюк, что и в OTIR) → LD L,L (режим "копирование блока") →
|
||||
* LD A,(HL) / LD (DE),A (блочное чтение источника → блочная запись
|
||||
* в 0xC000@стр.0xFD) → LD B,B (выкл). Акселератор НЕ продвигает
|
||||
* HL/DE сам — нам это и не нужно, вызов одноразовый.
|
||||
*
|
||||
* W3 сохраняется/восстанавливается вокруг свопа (как bank_read/
|
||||
* bank_write). Доп. DI/EI не нужны — функция вызывается ИЗ ISR
|
||||
* (прерывания уже замаскированы трамплином до его EI/RETI).
|
||||
*/
|
||||
|
||||
#include "_cbl.h"
|
||||
|
||||
void cbl_push_accel(const void *src, uint16_t n) __naked
|
||||
{
|
||||
(void)src; (void)n;
|
||||
__asm
|
||||
;; HL = src (1-й арг), DE = n (2-й арг) — __sdcccall(1)
|
||||
ld a, e
|
||||
ld (_cblpa_push_size), a ; SMC: 128 остаётся 128, 256 -> 0
|
||||
|
||||
in a, (#0xE2) ; сохранить текущий W3
|
||||
push af
|
||||
ld a, #0xFD ; замапить W3 на спец-страницу CBL
|
||||
out (#0xE2), a
|
||||
|
||||
ld de, #0xC000
|
||||
ld d, d ; 0x52 — режим размера блока
|
||||
ld a, #0 ; immediate — патчится SMC выше
|
||||
_cblpa_push_size = . - 1
|
||||
ld l, l ; 0x6D — режим "копирование блока"
|
||||
ld a, (hl) ; блочное чтение источника
|
||||
ld (de), a ; блочная запись в CBL-порт
|
||||
ld b, b ; 0x40 — выключить акселератор
|
||||
|
||||
pop af
|
||||
out (#0xE2), a ; вернуть W3
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
Reference in New Issue
Block a user