Files
Sprinter-SDCC/libc/irq/_irq_tramp.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

117 lines
3.8 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.
/*
* _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;
}