5086c47f0f
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>
117 lines
3.8 KiB
C
117 lines
3.8 KiB
C
/*
|
||
* _irq_tramp — вход IM2-прерывания (вектор 0xFF: кадр/клавиатура/CBL).
|
||
*
|
||
* До выяснения источника трогаем только AF:
|
||
* - клавиатура (бит 0 порта 0x19 = SIO-A RR0 «Rx Character
|
||
* Available») уходит напрямую в DSS;
|
||
* - CBL (бит 7 порта 0xFE) проверяется ТОЛЬКО при зарегистрированном
|
||
* хуке _irq_cbl_hook: при выключенном CBL бит подтянут к 1 (MAME
|
||
* kbd_fe_r: data |= 0xE0) и проверка ложно срабатывала бы на
|
||
* каждом кадре. CBL-путь: полный сейв → насос → restore →
|
||
* EI/RETI, к DSS НЕ чейнится (личное прерывание);
|
||
* - кадровое: полный сейв → user-handler → restore → чейн.
|
||
*
|
||
* Чейн — ВСЕГДА jp на обработчик DSS 0x0038 (DSS работает в IM 1;
|
||
* jp с interrupted-PC на стеке имитирует RST 38) — он делает свой
|
||
* save/restore и завершает EI/RETI: клавиатурный FIFO, SYSTIME и
|
||
* курсор мыши живут.
|
||
*
|
||
* Операнд финального jp (_irq_dss_target) — SMC, патчится из
|
||
* _irq_table_ref; модуль в _CODE (RAM на Sprinter, W2 в tiny/big).
|
||
*/
|
||
|
||
#include "_irq.h"
|
||
|
||
void _irq_tramp(void) __naked
|
||
{
|
||
__asm
|
||
push af
|
||
in a, (#0x19)
|
||
rrca ; бит 0 — клавиатурный байт принят?
|
||
jr C, _irq_chain
|
||
|
||
;; --- CBL? --- старший байт хука ненулевой у любого
|
||
;; W2-адреса — для проверки «хук есть» хватает одного байта.
|
||
ld a, (__irq_cbl_hook + 1)
|
||
or a, a
|
||
jr Z, _irq_frame
|
||
in a, (#0xFE)
|
||
rlca ; бит 7 — запрос блока CBL?
|
||
jr NC, _irq_frame
|
||
|
||
;; --- CBL: сейв, насос, restore, EI/RETI (без DSS) ---
|
||
push bc
|
||
push de
|
||
push hl
|
||
.db 0x08 ; ex af,af (теневой AF)
|
||
push af
|
||
exx
|
||
push bc
|
||
push de
|
||
push hl
|
||
push ix
|
||
push iy
|
||
ld hl, (__irq_cbl_hook)
|
||
call _irq_call_hl
|
||
pop iy
|
||
pop ix
|
||
pop hl
|
||
pop de
|
||
pop bc
|
||
exx
|
||
pop af
|
||
.db 0x08 ; ex af,af (теневой AF)
|
||
pop hl
|
||
pop de
|
||
pop bc
|
||
pop af
|
||
ei
|
||
reti
|
||
|
||
_irq_frame:
|
||
;; --- кадровое прерывание ---
|
||
push bc
|
||
push de
|
||
push hl
|
||
ld hl, (__irq_user)
|
||
ld a, h
|
||
or a, l
|
||
jr Z, _irq_pop3 ; handler не установлен
|
||
|
||
;; Сохранить теневой набор и индексные — user-код клобберит всё.
|
||
.db 0x08 ; ex af,af (теневой AF)
|
||
push af
|
||
exx
|
||
push bc
|
||
push de
|
||
push hl
|
||
push ix
|
||
push iy
|
||
|
||
ld hl, (__irq_user)
|
||
call _irq_call_hl
|
||
|
||
pop iy
|
||
pop ix
|
||
pop hl
|
||
pop de
|
||
pop bc
|
||
exx
|
||
pop af
|
||
.db 0x08 ; ex af,af (теневой AF)
|
||
_irq_pop3:
|
||
pop hl
|
||
pop de
|
||
pop bc
|
||
_irq_chain:
|
||
pop af
|
||
;; Всегда к DSS (IM 1, обработчик 0x0038) — EI/RETI за ним.
|
||
.db 0xC3 ; jp nn
|
||
__irq_dss_target::
|
||
.dw 0x0038 ; SMC: подтверждается в _irq_table_ref
|
||
|
||
_irq_call_hl:
|
||
jp (hl)
|
||
__endasm;
|
||
}
|