# roomtest — проверка порта статического фона PoP (Шаг 3): реальная # композиция слоёв (pop_bg.c) для комнаты 1. --memory huge --gfx 256. PROJ_ROOT := $(abspath $(CURDIR)/../../..) EXAMPLE := roomtest # small: W1+W2 как единое 32КБ-пространство, DATA сразу за CODE (иначе # CODE ~23КБ переполняет W1 и лезет в фиксированный DATA@0x8000 в huge). MEMORY ?= huge # small-раскладка + банки кода в W3 (стражи) # Резидента --w3 БОЛЬШЕ НЕТ: отрисовка уехала в БАНК 2 (pop_bg + pop_gdraw # в одной странице — вызовы между ними прямые, если функция не помечена # __banked). Так снято главное ограничение резидента: из банка его было # не достать ни прямо, ни транзитивно, а банк→банк работает (трамплин # сохраняет страницу окна на СТЕКЕ, проверено вложенной цепочкой # банк1→банк2→банк1 в MAME 2026-07-30). Теперь в банки можно уводить и # логику, которая рисует. См. docs/layout_plan_v2.md §2, memory # sdcc_banked_call_rules. # Банк 5 = pop_ctrl.c (MEM-BANK5). CODE и DATA делят одно 32-КБ # пространство W1+W2, поэтому килобайт кода, уехавший в банк, — это # килобайт, доступный данным. Кандидат выбран не по размеру, а по частоте # вызова: диспетчер управления дёргается один раз за кадр на персонажа и # горячих банк→банк переходов не создаёт (в отличие от pop_level, чей # pop_level_tile зовётся из банка 2 на КАЖДЫЙ тайл). Шина control_* # переехала в pop_state.c — см. там. # --max-allocs-per-node: во сколько вариантов размещения регистров SDCC # упирается на узел. У sprinter-cc дефолт 100000 (агрессивно, как fast-сборки # библиотек) — на roomtest это МИНУТЫ на банк, потому что модули крупные. # Дефолт SDCC — 3000, и для разработки его достаточно: разница в размере # единицы процента, а сборка кратно быстрее. Замер (2026-08-05) — в шапке # TASKS_CLOSED.md, запись BUILD-FAST. # # make — быстрая сборка (ALLOCS=3000) # make ALLOCS=100000 — как раньше: минимальный код, для замеров размера # и для «релизного» образа # # ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том # же ALLOCS — иначе сравниваются не правки, а уровни оптимизации. ALLOCS ?= 3000 EXTRA_FLAGS ?= --gfx 256 --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 4=pop_gdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c $(PROF_FLAGS) # Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по # умолчанию, пока идёт работа с производительностью; make PROF=0 выключает. # Каждая фаза кадра красит бордюр в свой цвет, высота полосы на скриншоте # MAME = время фазы в растровых строках. PROF ?= 1 PROF_FLAGS := -DPROF_BORDER=$(PROF) EXTRA_SRCS := pop_state.c pop_draw.c pop_kid.c pop_level.c pop_redraw.c pop_geom.c pop_guard.c BG_DIR := $(CURDIR)/../poc/res/bg KID_DIR := $(CURDIR)/../poc/res/kid LVL_DIR := $(CURDIR)/../SDLPoP/data/LEVELS # ВСЕ уровни игры (res2001..res2015, по 2305 Б = 34 КБ на всех): переход # уровень→уровень и чит Shift+L требуют, чтобы файл следующего лежал на # диске. res2000 — демо-уровень, в скоуп не входит. LVL_NUMS := 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 LVL_DATA := $(foreach n,$(LVL_NUMS),$(LVL_DIR)/res20$(n).bin) BG_DATA := $(BG_DIR)/pop_env0.atl $(BG_DIR)/pop_env1.atl $(BG_DIR)/pop_env2.atl \ $(BG_DIR)/pop_env3.atl $(BG_DIR)/pop_env4.atl \ $(BG_DIR)/pop_wall.atl $(BG_DIR)/pop_fore.atl \ $(BG_DIR)/pop_pot.atl # ВСЕ 28 страниц Kid — иначе кадры торможения/разворота/приседа (image>23) # не рисуются (kid_draw пропускает незагруженную страницу). Палитра — # ЕДИНАЯ игровая (env+wall+kid). KID_PAGES := $(foreach n,0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27,$(KID_DIR)/kid$(n).atl) KID_DATA := $(KID_PAGES) $(KID_DIR)/kid.pal $(KID_DIR)/sword.atl # Таблицы анимации (кадры+seqtbl) — отдельный бинарь в EMM-странице, его # делает pop_extract_kid_data.py (не упаковщик спрайтов) — своё правило ниже. KID_BIN := $(KID_DIR)/kid_data.bin GUARD_DIR := $(CURDIR)/../poc/res/guard GUARD_DATA := $(GUARD_DIR)/g0.atl $(GUARD_DIR)/g1.atl $(GUARD_DIR)/g2.atl \ $(GUARD_DIR)/g3.atl $(GUARD_DIR)/g4.atl # Скелет — ОТДЕЛЬНЫЙ набор спрайтов (SKEL.DAT в оригинале): его грузит # уровень 3 (tbl_guard_type == 2), кадров меньше (28 против 34). SKEL_DIR := $(CURDIR)/../poc/res/skel SKEL_DATA := $(SKEL_DIR)/g0.atl $(SKEL_DIR)/g1.atl $(SKEL_DIR)/g2.atl \ $(SKEL_DIR)/g3.atl EXTRA_DATA := $(BG_DATA) $(KID_DATA) $(KID_BIN) $(GUARD_DATA) $(SKEL_DATA) $(LVL_DATA) include $(PROJ_ROOT)/app.mk # Образ HDD для MAME: ресурсы раскладываются ПО КАТАЛОГАМ (8.3, как в DSS), # чтобы корень диска не зарастал десятками .atl. # BG\ — фон (env/wall/fore/pot) # KID\ — персонаж (kid0..27, палитра, меч, таблицы анимации) # GUARD\ — стражи (появятся здесь же) # LEVELS\ — уровни hdd: $(EXAMPLE).exe $(PROJ_ROOT)/toolchain/make_hdd.sh $(PROJ_ROOT)/mame/v306/IMG/test_hdd.chd \ $(EXAMPLE).exe \ $(foreach f,$(BG_DATA),BG:$(f)) \ $(foreach f,$(KID_DATA) $(KID_BIN),KID:$(f)) \ $(foreach f,$(GUARD_DATA),GUARD:$(f)) \ $(foreach f,$(SKEL_DATA),SKEL:$(f)) \ $(foreach f,$(LVL_DATA),LEVELS:$(f)) TC := $(PROJ_ROOT)/applications/PoP/toolchain $(BG_DATA): $(TC)/pop_pack_bg.py $(TC)/render_room.py cd $(TC) && python3 pop_pack_bg.py $(GUARD_DATA): $(TC)/pop_pack_guard.py cd $(TC) && python3 pop_pack_guard.py $(SKEL_DATA): $(TC)/pop_pack_guard.py cd $(TC) && python3 pop_pack_guard.py SKEL $(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py cd $(TC) && python3 pop_pack_kid.py kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py cd $(TC) && python3 pop_extract_kid_data.py $(EXAMPLE).exe: guards.c pop_guard.c pop_guard.h pop_gdraw.c pop_draw.c _pop_draw.h pop_state.c pop_state.h pop_cheat.h pop_bg.c pop_bg.h pop_geom.c pop_geom.h pop_redraw.c pop_redraw.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)