/* * _bgi_scroll_rows_raw — БЫСТРАЯ построчная копия video->video со сдвигом * ТОЛЬКО по X для gfx_scroll_h (mode 0x81). Специализация _bgi_copy_rows_raw * для скролла: обе стороны — видео, ОБА страйда НУЛЕВЫЕ (CPU-адрес строки * фиксирован, строку выбирает Port_Y), поэтому адресной арифметики в цикле * НЕТ ВООБЩЕ — ни страйдовых add (как у copy_rows), ни даже inc адресов * (как у heal). От _bgi_heal_rows_raw отличается тем, что src != dst * (HL — колонка-старт src-страницы, DE — dst-страницы со сдвигом dx): * горизонтальный сдвиг целиком в разнице адресов, задаётся вызывающим. * * Вертикального сдвига НЕТ (read и write одной строки на одном Port_Y) — * для сдвига по Y есть _bgi_scroll_cols_raw (колонки, вертикальный режим). * Зато rows на ~5-7% быстрее cols: на строку один OUT Port_Y (54Т/строку), * а cols нужен OUT на чтение И на запись колонки. * * ПОРЯДОК на строку: {OUT Port_Y · arm(LD L,L) · read(LD A,(HL)) · * write(LD (DE),A) · STOP(LD B,B)}. Между read- и write-триггером — * НИЧЕГО: на Sprinter accel перехватывает любое чтение программной памяти, * а fetch операнда любой инструкции там (immediate у OUT/ADD) спурьезно * перезапустил бы read-burst и набил буфер кодом. Port_Y ставится ДО * arm'а (accel разоружён STOP'ом прошлой строки — операнд OUT безопасен). * (memory/accel_operand_fetch_retrigger.) * * DI/EI — БАНДАМИ по 16 строк ВНУТРИ (как _gfx_recthfill256): накрывать DI * весь сдвиг нельзя (порвёт CBL-звук). Армирование размера блока — в * КАЖДОЙ скобке (в окне EI CBL-ISR армирует accel своим размером). Число * полных 16-банд и хвост считаем ОДИН раз на входе (precompute) — в петле * банд остаётся дешёвый dec (без per-band `sub 16` через IX-слот). * Регистры упёрты (HL src, DE dst, B djnz, C бегущий Port_Y) — быстрее уже * некуда: out(c) без стопов потребовал бы Port_Y-регистра, которого нет. * * ВХОД (__sdcccall(1)): src->HL, dst->DE; стек: w 4(ix) — байт в строке * (размер accel-блока, 1..256, 0=256), h 5(ix) — строк 1..256 (0 = 256, * КОНВЕНЦИЯ accel — как у w), y0 6(ix) — стартовый Port_Y (инкремент на * строку). Callee-pop 3 байта. * * Raw: клиппинга нет (вызывающий), W3 замаплен (_bgi_begin/end снаружи), * банк 0x50 (запись бьёт VRAM+тень — скролл И heal цели). Перекрытия * src/dst нет by design — стороны в РАЗНЫХ видеостраницах. Строку >256 * байт режет вызывающий. Клоббер: AF/BC; HL/DE/IX сохраняются * (адреса-константы не трогаются — LD L,L/LD D,D это accel-опкоды-no-op'ы). */ #include "../_bgi.h" void _bgi_scroll_rows_raw(uint16_t src, uint16_t dst, uint8_t w, uint8_t h, uint8_t y0) __naked { (void)src; (void)dst; (void)w; (void)h; (void)y0; __asm push ix ld ix, #0 add ix, sp ;; HL = src, DE = dst (адреса-константы; строку задаёт Port_Y) ld a, 4 (ix) ld (sc_row_len), a ; SMC: размер блока <- w (0 = 256) ld (sc_row_len2), a ; ...и в хвостовую скобку ld c, 6 (ix) ; C = бегущий Port_Y (y0) ;; --- precompute: полных 16-банд (ix+5) + хвост (SMC); h=0 => 256 --- ld a, 5 (ix) and #0x0F ld (sc_row_tail), a ; хвост = h & 15 (0 и при h=0, и при h=256) ld a, 5 (ix) or a, a jr NZ, sc_row_shr ld a, #16 ; h=0 => 256 => ровно 16 полных банд jr sc_row_setfull sc_row_shr: rrca rrca rrca rrca and #0x0F ; full = h >> 4 sc_row_setfull: ld 5 (ix), a ; ix+5 = число полных 16-строчных банд sc_row_band: ld a, 5 (ix) or a, a jr Z, sc_row_tailband ; полные банды кончились dec 5 (ix) ; full -= 1 ld b, #16 ; 16 строк в банде di ld d, d ; 0x52 — режим размера блока (no-op для D) ld a, #0 sc_row_len = . - 1 ld b, b ; выключить — размер сохранён (B=16 цел) sc_row_next: ld a, c out (#0x89), a ; Port_Y = y (accel ВЫКЛЮЧЕН — операнд безопасен) inc c ; y++ ld l, l ; 0x6D — арм гориз. копии (no-op для L) ld a, (hl) ; read-burst: src-строка -> буфер ld (de), a ; write-burst: буфер -> dst-строка (вплотную!) ld b, b ; 0x40 — стоп djnz sc_row_next ei ; окно прерываний между бандами jr sc_row_band ;; --- хвост h&15 строк: отдельная скобка со СВОИМ армированием --- sc_row_tailband: ld a, #0 sc_row_tail = . - 1 or a, a jr Z, sc_row_done ; хвоста нет ld b, a ; B = остаток строк (1..15) di ld d, d ld a, #0 sc_row_len2 = . - 1 ld b, b sc_row_trow: ld a, c out (#0x89), a inc c ld l, l ld a, (hl) ld (de), a ld b, b djnz sc_row_trow ei sc_row_done: pop ix ;; callee-pop 3 байта (w, h, y0) pop hl ; ret-адрес pop af inc sp jp (hl) __endasm; }