/*
 * 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;
}
