Files
Sprinter-SDCC/libc/cbl/cbl_push_accel.c
T
snark13 5086c47f0f 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>
2026-07-07 21:21:54 +03:00

50 lines
2.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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;
}