# ---------------------------------------------------------------------- # host-tests.mk — общие правила модульных тестов, исполняемых под ucsim_z80. # # Сама обвязка (crt0_ucsim.s, tcheck.*, run_ucsim.py) лежит в testkit/ и ни # к какому подпроекту не привязана: тестировать так можно и libc, и логику # приложений — всё, что на plain C и не трогает железо. # # Подключается из каталога с наборами t_*.c: # # TESTKIT := $(abspath ../../../../testkit) # ENGINE_DIR := $(abspath ..) # где лежат модули под тестом # OBJS_geom := build/eng_pop_geom.rel # что доложить в этот набор # include $(TESTKIT)/host-tests.mk # # Набор t_<имя>.c подхватывается wildcard'ом, регистрировать не надо. # ---------------------------------------------------------------------- ifndef TESTKIT $(error перед include надо задать TESTKIT — путь к каталогу testkit/) endif PROJ_ROOT ?= $(abspath $(TESTKIT)/..) SDCC := $(PROJ_ROOT)/third_party/sdcc/bin/sdcc SDASZ80 := $(PROJ_ROOT)/third_party/sdcc/bin/sdasz80 UCSIM := $(PROJ_ROOT)/third_party/sdcc/bin/ucsim_z80 RUNNER := $(TESTKIT)/run_ucsim.py BUILD := build # --code-loc: стартовый код занимает 13 байт по 0x0000, код с 0x0200. # --data-loc 0x8000: данные заведомо выше кода. # # CODE_LOC переопределяется набором, если ему нужна нижняя память под # данные: так делает t_phys в roomtest — он кладёт по 0x100 страницу # таблиц анимации, которую на устройстве туда приводит маппинг W0. # EXTRA_INC — заголовки, которых нет ни в testkit, ни в ENGINE_DIR # (например libc/libbgi, когда модуль под тестом их включает). # DATA_LOC — та же история сверху: набор, чей код перерос 0x8000, обязан # отодвинуть данные, иначе линкер молча кладёт хвост кода (_HOME, деления # из libsdcc) ПОВЕРХ _DATA — тест ведёт себя как «зациклился», хотя логика # ни при чём. Проверку наложения делает check-overlap ниже. CODE_LOC ?= 0x0200 DATA_LOC ?= 0x8000 EXTRA_INC ?= CFLAGS := -mz80 --no-std-crt0 --std-c99 --opt-code-size -I$(TESTKIT) \ $(if $(ENGINE_DIR),-I$(ENGINE_DIR)) $(EXTRA_INC) $(EXTRA_CFLAGS) LDFLAGS := -mz80 --no-std-crt0 --code-loc $(CODE_LOC) --data-loc $(DATA_LOC) SUITES := $(patsubst t_%.c,%,$(notdir $(wildcard t_*.c))) COMMON := $(BUILD)/crt0_ucsim.rel $(BUILD)/tcheck.rel .PHONY: all clean $(addprefix t_,$(SUITES)) # Иначе make считает .rel/.ihx промежуточными и удаляет их после прогона — # следующий `make` пересобирал бы всё заново. .SECONDARY: # OBJS_<набор> подставляется в правило по имени цели — нужен второй проход # раскрытия, иначе модуль не попадёт в зависимости и не соберётся. .SECONDEXPANSION: # Ярлык каталога в отчёте — с родителем: «tests-host» само по себе # неоднозначно, когда таких каталогов несколько. LABEL := $(notdir $(patsubst %/,%,$(dir $(CURDIR))))/$(notdir $(CURDIR)) all: $(addprefix run-,$(SUITES)) @echo "$(LABEL): все наборы прошли ($(words $(SUITES)))" # Прогон одного набора. Раннер сам разбирает tc_result и возвращает код. # Наложение кода на данные линкер sdld НЕ считает ошибкой: код просто # ложится поверх _DATA, и тест виснет/врёт без единого предупреждения. # Ловим сами — конец _CODE (CODE_LOC + l__CODE) против DATA_LOC. define CHECK_OVERLAP @python3 -c "import sys; \ d={p[1]:int(p[2],16) for p in (l.split() for l in open('$(1)')) if len(p)==3 and p[0]=='DEF'}; \ end=$(CODE_LOC)+d.get('l__CODE',0); \ sys.exit(0) if end<=$(DATA_LOC) else sys.exit('%s: КОД НАЕХАЛ НА ДАННЫЕ — _CODE кончается на 0x%04X, а DATA_LOC = 0x%04X.\n Поднять DATA_LOC в Makefile набора (стек в crt0_ucsim — 0xFEF0).' % ('$(1)', end, $(DATA_LOC)))" endef run-%: $(BUILD)/%.ihx $(call CHECK_OVERLAP,$(BUILD)/$*.noi) @python3 $(RUNNER) $(UCSIM) $(BUILD)/$*.ihx $(BUILD)/$*.noi # Удобный псевдоним: `make t_geom` вместо `make run-geom`. t_%: run-% ; $(BUILD)/%.ihx: $(BUILD)/%.rel $(COMMON) $$(OBJS_$$*) @$(SDCC) $(LDFLAGS) -o $@ $(COMMON) $(BUILD)/$*.rel $(OBJS_$*) $(BUILD)/%.rel: t_%.c $(TESTKIT)/tcheck.h | $(BUILD) @$(SDCC) $(CFLAGS) -c -o $@ $< # Модули под тестом собираются ТЕМ ЖЕ компилятором и с той же семантикой, # что и продукт, — включая модули с inline-asm, которые хостовой сборкой # не проверить в принципе. $(BUILD)/eng_%.rel: $(ENGINE_DIR)/%.c | $(BUILD) @$(SDCC) $(CFLAGS) -c -o $@ $< $(BUILD)/tcheck.rel: $(TESTKIT)/tcheck.c $(TESTKIT)/tcheck.h | $(BUILD) @$(SDCC) $(CFLAGS) -c -o $@ $< $(BUILD)/crt0_ucsim.rel: $(TESTKIT)/crt0_ucsim.s | $(BUILD) @$(SDASZ80) -plosgff $@ $< $(BUILD): @mkdir -p $(BUILD) clean: @rm -rf $(BUILD)