Files
Sprinter-SDCC/testkit/host-tests.mk
T
Александр Петров 61d4255091 testkit: модульные тесты под ucsim_z80 + планы покрытия
Обвязка для быстрых тестов plain-C логики: секунды вместо прогона в MAME,
без образа диска.  ucsim_z80 идёт в комплекте нашего SDCC — новых
зависимостей нет.

ПОЧЕМУ ПОД Z80, А НЕ ХОСТОВЫМ GCC.  У SDCC z80 int 16 бит, у хоста 32, и
расходится это НЕ в объявлениях, а в выражениях: integer promotion
повышает операнды до int независимо от того, объявлены они как uint8_t
или uint16_t.  Перевод кода на фиксированные типы разницу не убирает —
убирает только исполнение с z80-семантикой.  Побочно проверяется
кодогенерация SDCC и модули с inline-asm, которых хостовая сборка не
видит в принципе.

Устройство: crt0_ucsim.s (SP, зануление, main, halt), tcheck.* (итог в
структуру в ОЗУ), run_ucsim.py (гоняет ucsim, дампит tc_result, печатает
отчёт), host-tests.mk (общие правила).  Вывода через printf нет: тестовый
бинарь линкуется без Sprinter-libc.  Через ucsim-simif не идём — номера
его команд плавают между версиями, halt + dump работают везде.

Наборы лежат РЯДОМ с проверяемым кодом, обвязка общая:
  testkit/t_selftest.c                     — самопроверка (sizeof(int)==2)
  applications/PoP/roomtest/tests-host/    — движок PoP

Первый содержательный набор — t_geom: сверяет рукописный asm-LCG из
pop_geom.c с наивной 32-битной формулой на 128 шагах.  Заявка «бит-в-бит
как в SDLPoP» до сих пор держалась на комментарии.  Тест проверен
мутацией: порча эталонной константы даёт красный.

Планы дальнейшего покрытия:
  docs/host-tests-plan.md                    — libc и libbgi (не начато)
  applications/PoP/docs/host_tests_plan.md   — движок PoP

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 22:36:16 +03:00

84 lines
3.9 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ----------------------------------------------------------------------
# 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: данные заведомо выше кода.
CFLAGS := -mz80 --no-std-crt0 --std-c99 --opt-code-size -I$(TESTKIT) \
$(if $(ENGINE_DIR),-I$(ENGINE_DIR))
LDFLAGS := -mz80 --no-std-crt0 --code-loc 0x0200 --data-loc 0x8000
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 и возвращает код.
run-%: $(BUILD)/%.ihx
@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)