52636a5d6e
Графика вынесена из libc/ в новую библиотеку libbgi/:
- common/ — mode-agnostic математика и состояние (один исходник,
.rel попадает в оба driver-архива);
- bgi256/ + bgi16/ — mode-specific leaf'ы (raw-плот/чтение/спаны);
- include/ — graphics.h + gfx.h; _bgi.h — внутренний заголовок.
Собираются lib/bgi256.lib (и bgi16.lib в Фазе 2); выбор режима
линковкой через sprinter-cc --gfx 256|16. libc/ теперь без графики.
tests/bgi_img — тест спрайтов getimage/putimage/imagesize (5 операций
COPY/XOR/OR/AND/NOT + XOR-round-trip + self-check imagesize).
Проверен автотестом в MAME.
Примечание: make size-check пока красный (gfx_dbuf/gfx_demo выросли
после реорга) — закрыть по завершении миграции libbgi.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
2.8 KiB
C
73 lines
2.8 KiB
C
/*
|
||
* gfx_wait_vsync — ждать переход бита 5 порта 0xFE из 1 в 0: выход из
|
||
* нижнего blank/border (Y > 256 — см. MAME sprinter.cpp kbd_fe_r:
|
||
* `vpos() >= BORDER_TOP+SCREEN_YSIZE`) — начало нового кадра, идеальный
|
||
* момент для свопа страниц без разрывов. Это чтение РЕАЛЬНОГО
|
||
* состояния луча (не событие/прерывание), поэтому не подвержено
|
||
* путанице с другими источниками вектора 0xFF (клавиатура, CBL, CTC) —
|
||
* подробнее см. memory/gfx_wait_vsync_redesign.
|
||
*
|
||
* Бит доступен ТОЛЬКО пока включён cbl_mode() (bit7 порта 0x004E) —
|
||
* см. libc/cbl/_cbl_port.c: если приложение уже играет через
|
||
* cbl_open(), берём бит бесплатно (порт не трогаем); иначе
|
||
* лениво занимаем bit7 "немым" кодом частоты через _cbl_port_ref()
|
||
* при первом вызове, освобождаем в atexit.
|
||
*
|
||
* Fallback: если ни разу не увидели ожидаемое состояние за разумное
|
||
* число попыток (иное железо, бит ведёт себя не как в MAME) —
|
||
* откатываемся на одно кадровое прерывание (halt), чтобы не
|
||
* зависнуть намертво.
|
||
*/
|
||
|
||
#include "../_bgi.h"
|
||
#include <sprinter_exit.h>
|
||
|
||
static uint8_t vsync_ready;
|
||
|
||
static void vsync_cleanup(void)
|
||
{
|
||
_cbl_port_unref();
|
||
}
|
||
|
||
void gfx_wait_vsync(void)
|
||
{
|
||
if (!vsync_ready) {
|
||
vsync_ready = 1;
|
||
_cbl_port_ref();
|
||
atexit(vsync_cleanup);
|
||
}
|
||
|
||
__asm
|
||
;; --- фаза 1: дождаться bit5==1 (гарантированно в blank) ---
|
||
ld bc, #0 ; ~65536 попыток на фазу — таймаут
|
||
_gwv_wait1:
|
||
in a, (#0xFE)
|
||
bit 5, a
|
||
jr nz, _gwv_have1
|
||
dec bc
|
||
ld a, b
|
||
or c
|
||
jr nz, _gwv_wait1
|
||
jr _gwv_fallback ; bit5 ни разу не встал за таймаут
|
||
_gwv_have1:
|
||
|
||
;; --- фаза 2: дождаться bit5==0 (сам переход — начало кадра) ---
|
||
ld bc, #0
|
||
_gwv_wait0:
|
||
in a, (#0xFE)
|
||
bit 5, a
|
||
jr z, _gwv_done
|
||
dec bc
|
||
ld a, b
|
||
or c
|
||
jr nz, _gwv_wait0
|
||
;; таймаут и здесь — переходим к тому же фолбэку
|
||
|
||
_gwv_fallback:
|
||
ei
|
||
halt ; аварийный путь: одно кадровое прерывание
|
||
|
||
_gwv_done:
|
||
__endasm;
|
||
}
|