libbgi: bgi256 fill-примитивы на register-ABI + typedef color_t

- удалён глобальный скретч акселератора (_gfx_acc256.c); fill-сегменты
  (_gfx_hfill256/_gfx_vfill256) принимают аргументы в регистрах HL/C/B/E,
  вызываются только из asm raw-примитивов
- новый _gfx_rectfill256: заливка прямоугольника через Horizontal_Size
- raw-примитивы (plot/read/hspan/vspan/clear) переписаны под новый ABI
- graphics.h: typedef color_t (uint8_t) для всех public color-функций
- sprinter-cc: флаг --safe (линковка *_safe.lib при наличии)
- CLAUDE.md/mame_interactive: авто-прогон тестов в MAME
- gfx_demo: демонстрация rectfill

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 14:32:21 +03:00
parent 52636a5d6e
commit 029607971f
31 changed files with 618 additions and 283 deletions
+67 -47
View File
@@ -1,79 +1,99 @@
# Build lib/bgi256.lib — Sprinter BGI graphics driver (320×256×256).
# Build lib/bgi256.lib + lib/bgi256_safe.lib — Sprinter BGI graphics driver (320×256×256).
#
# libbgi/ — самостоятельная графическая библиотека, отделённая от libc.
# Две driver-библиотеки собираются из одной исходной базы:
# bgi256.lib = common/*.rel + bgi256/*.rel (эта — Фаза 1)
# bgi16.lib = common/*.rel + bgi16/*.rel (Фаза 2; пока не собирается)
# common/ — mode-agnostic: .rel компилируется ОДИН раз и кладётся в ОБА
# архива (один исходник для функций, общих 256- и 16-цветной версиям).
# bgi256/ — mode-specific leaf'ы (реальные реализации, без обёрток).
# bgi256.lib = common/*.rel + bgi256/*.rel (fast, без bounds-check)
# bgi256_safe.lib = common/*.rel + bgi256/*.rel (safe, с bounds-check)
# common/ — mode-agnostic: .rel компилируется в ОБЕ версии параллельно.
# bgi256/ — mode-specific leaf'ы.
#
# Каждый .c — отдельный .rel в архиве (1 публичная функция = 1 модуль);
# линкер тянет только нужные .rel → DCE на уровне файлов. См. план
# «Рефакторинг GFX → BGI» и memory/bgi_two_lib_design.
# линкер тянет только нужные .rel → DCE на уровне файлов.
#
# make build lib/bgi256.lib
# make clean remove build/ + lib/bgi256.lib
# make build lib/bgi256.lib + lib/bgi256_safe.lib (обе)
# make fast build только lib/bgi256.lib
# make safe build только lib/bgi256_safe.lib
# make BUILD_SAFE=1 build только lib/bgi256_safe.lib (legacy)
# make clean remove build/ + обе библиотеки
#
# (Фаза 2 добавит bgi16.lib = common + bgi16; common .rel переиспользуются.)
PROJ_ROOT := $(abspath $(CURDIR)/..)
SDCC_BIN := $(PROJ_ROOT)/third_party/sdcc/bin
SDCC := $(SDCC_BIN)/sdcc
SDAR := $(SDCC_BIN)/sdar
# -I libbgi/include (gfx.h, graphics.h) + -I libc/include (palette.h,
# sprinter_exit.h — публичные заголовки libc; libbgi всегда линкуется с
# libc). SDCC stdint и пр. — из собственного include-пути SDCC.
INC := -I$(CURDIR)/include -I$(PROJ_ROOT)/libc/include
CC_FLAGS := -mz80 --no-std-crt0 --std-c99 --opt-code-size $(INC)
BUILD := $(CURDIR)/build
COMMON_C := $(wildcard $(CURDIR)/common/*.c)
BGI256_C := $(wildcard $(CURDIR)/bgi256/*.c)
COMMON_C := $(wildcard $(CURDIR)/common/*.c)
BGI256_C := $(wildcard $(CURDIR)/bgi256/*.c)
# BGI16_C := $(wildcard $(CURDIR)/bgi16/*.c) # Фаза 2
COMMON_RELS := $(patsubst $(CURDIR)/common/%.c,$(BUILD)/common/%.rel,$(COMMON_C))
BGI256_RELS := $(patsubst $(CURDIR)/bgi256/%.c,$(BUILD)/bgi256/%.rel,$(BGI256_C))
KNOWN_RELS := $(COMMON_RELS) $(BGI256_RELS)
COMMON_FAST_RELS := $(patsubst $(CURDIR)/common/%.c,$(BUILD)/fast/common/%.rel,$(COMMON_C))
BGI256_FAST_RELS := $(patsubst $(CURDIR)/bgi256/%.c,$(BUILD)/fast/bgi256/%.rel,$(BGI256_C))
COMMON_SAFE_RELS := $(patsubst $(CURDIR)/common/%.c,$(BUILD)/safe/common/%.rel,$(COMMON_C))
BGI256_SAFE_RELS := $(patsubst $(CURDIR)/bgi256/%.c,$(BUILD)/safe/bgi256/%.rel,$(BGI256_C))
LIB_DIR := $(PROJ_ROOT)/lib
LIB256 := $(LIB_DIR)/bgi256.lib
LIB_FAST := $(LIB_DIR)/bgi256.lib
LIB_SAFE := $(LIB_DIR)/bgi256_safe.lib
# Штамп списка модулей — иначе удаление/переименование исходника не
# триггерит перелинковку и stale .rel остаётся в архиве. На exFAT
# грубая mtime — сравниваем по списку, не по времени.
MODLIST := $(BUILD)/.modules
ifneq ($(shell cat $(MODLIST) 2>/dev/null),$(KNOWN_RELS))
_ := $(shell mkdir -p $(BUILD); echo "$(KNOWN_RELS)" > $(MODLIST); rm -f $(LIB256))
endif
all: fast safe
all: $(LIB256)
fast: $(LIB_FAST)
# Pattern rule для common/ и bgi256/ (один уровень под build/).
$(BUILD)/common/%.rel: $(CURDIR)/common/%.c
safe: $(LIB_SAFE)
# --- Fast version: -DGFX_NOCHECK (guard'и выключены) ---
$(BUILD)/fast/common/%.rel: $(CURDIR)/common/%.c
@mkdir -p $(dir $@)
$(SDCC) $(CC_FLAGS) -c -o $@ $<
$(SDCC) -mz80 --no-std-crt0 --std-c99 --opt-code-size -DGFX_NOCHECK $(INC) -c -o $@ $<
$(BUILD)/bgi256/%.rel: $(CURDIR)/bgi256/%.c
$(BUILD)/fast/bgi256/%.rel: $(CURDIR)/bgi256/%.c
@mkdir -p $(dir $@)
$(SDCC) $(CC_FLAGS) -c -o $@ $<
$(SDCC) -mz80 --no-std-crt0 --std-c99 --opt-code-size -DGFX_NOCHECK $(INC) -c -o $@ $<
# Archive — sdar rcs = replace/create/symtab. Перед упаковкой удаляем
# stale .rel (wildcard не знает об удалённых исходниках).
$(LIB256): $(COMMON_RELS) $(BGI256_RELS) $(MODLIST)
@find $(BUILD) -name '*.rel' -print | sort > $(BUILD)/.have
@printf '%s\n' $(KNOWN_RELS) | sort > $(BUILD)/.want
@comm -23 $(BUILD)/.have $(BUILD)/.want | while read f; do \
echo " stale: $$f (исходник удалён) — rm"; \
# --- Safe version: guard'и включены (по умолчанию) ---
$(BUILD)/safe/common/%.rel: $(CURDIR)/common/%.c
@mkdir -p $(dir $@)
$(SDCC) -mz80 --no-std-crt0 --std-c99 --opt-code-size $(INC) -c -o $@ $<
$(BUILD)/safe/bgi256/%.rel: $(CURDIR)/bgi256/%.c
@mkdir -p $(dir $@)
$(SDCC) -mz80 --no-std-crt0 --std-c99 --opt-code-size $(INC) -c -o $@ $<
# --- Archive: fast ---
$(BUILD)/fast/.have: $(COMMON_FAST_RELS) $(BGI256_FAST_RELS)
@find $(BUILD)/fast -name '*.rel' -print | sort > $@ 2>/dev/null || true
@printf '%s\n' $(COMMON_FAST_RELS) $(BGI256_FAST_RELS) | sort > $(BUILD)/fast/.want
@comm -23 $(BUILD)/fast/.have $(BUILD)/fast/.want | while read f; do \
echo " stale: $$f — rm"; \
rm -f "$$f" "$${f%.rel}.asm" "$${f%.rel}.lst" "$${f%.rel}.sym"; \
done
$(LIB_FAST): $(COMMON_FAST_RELS) $(BGI256_FAST_RELS) $(BUILD)/fast/.have
rm -f $@
$(SDAR) -rcs $@ $(COMMON_RELS) $(BGI256_RELS)
@echo " Built $@ with $(words $(COMMON_RELS)) common + $(words $(BGI256_RELS)) bgi256 modules."
$(SDAR) -rcs $@ $(COMMON_FAST_RELS) $(BGI256_FAST_RELS)
@echo " Built $@ with $$(( $$(echo "$(words $(COMMON_FAST_RELS))") + $$(echo "$(words $(BGI256_FAST_RELS))") )) modules."
# --- Archive: safe ---
$(BUILD)/safe/.have: $(COMMON_SAFE_RELS) $(BGI256_SAFE_RELS)
@find $(BUILD)/safe -name '*.rel' -print | sort > $@ 2>/dev/null || true
@printf '%s\n' $(COMMON_SAFE_RELS) $(BGI256_SAFE_RELS) | sort > $(BUILD)/safe/.want
@comm -23 $(BUILD)/safe/.have $(BUILD)/safe/.want | while read f; do \
echo " stale: $$f — rm"; \
rm -f "$$f" "$${f%.rel}.asm" "$${f%.rel}.lst" "$${f%.rel}.sym"; \
done
$(LIB_SAFE): $(COMMON_SAFE_RELS) $(BGI256_SAFE_RELS) $(BUILD)/safe/.have
rm -f $@
$(SDAR) -rcs $@ $(COMMON_SAFE_RELS) $(BGI256_SAFE_RELS)
@echo " Built $@ with $$(( $$(echo "$(words $(COMMON_SAFE_RELS))") + $$(echo "$(words $(BGI256_SAFE_RELS))") )) modules."
clean:
rm -rf $(BUILD) $(LIB256)
rm -rf $(BUILD) $(LIB_FAST) $(LIB_SAFE)
.PHONY: all clean
.PHONY: all fast safe clean