diff --git a/applications/PoP/docs/resident_budget.md b/applications/PoP/docs/resident_budget.md
deleted file mode 100644
index 3422b92..0000000
--- a/applications/PoP/docs/resident_budget.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# Бюджет резидента W1/W2 и как его освобождать
-
-Резидент huge-режима — это окно `0x4100..0xBB00` (стек с 0xBB00): код в W1,
-данные в W2, между концом данных и стеком остаётся куча. Всё, что туда не
-влезло, обязано жить в банках.
-
-## Как СМОТРЕТЬ, а не гадать
-
-Атрибуция по карте (`roomtest.map`) ВРЁТ: file-static SDCC в карту не
-попадает, и «дырка» между двумя именованными символами приписывается
-предыдущему модулю целиком. На этом легко получить «у pop_bg 1529 байт
-данных», когда на самом деле у него 289.
-
-Правильный источник — объектные файлы: в `.rel` есть строки
-`A size flags ` с ТОЧНЫМ размером каждой области модуля.
-
-```python
-# по каждому .rel: _DATA/_BSS/_INITIALIZED = резидентные данные модуля,
-# _BANKn = его код в банке
-re.match(r'A\s+(\S+)\s+size\s+([0-9A-Fa-f]+)\s+flags', line)
-```
-
-Кто на кого ссылается — оттуда же: `S Def...` — модуль определяет
-символ, `S Ref...` — ссылается на него.
-
-## Замер 2026-08-20 (до правки)
-
-Данные банковых модулей, лежавшие в РЕЗИДЕНТЕ:
-
-| модуль | данные в W2 | разделяемые символы |
-|---|---:|---|
-| `pop_room` (банк 7) | 1620 | нет (`_mobs` не читает никто) |
-| `pop_trob` (банк 6) | 929 | НЕТ ВООБЩЕ |
-| `pop_bg` (банк 2) | 289 | `pop_bg_obj_col/row` читает `pop_room` |
-| `pop_map` (банк 3) | 227 | `hitp_*`, `pop_upside*`, `pop_loose_modif`, … — читают 6 модулей |
-| `pop_cdraw` (банк 4) | 175 | `pop_cd` читают 4 модуля |
-
-## Что сделано: данные банка — в страницу банка
-
-`sprinter-cc --bank-data=SRC` (повторяемый) кладёт писучие данные ОДНОГО
-банкового модуля в его же 16-КБ страницу. Выборочность принципиальна:
-глобал, который читает соседний банк или резидент, обязан остаться
-замапленным всегда, иначе чтение придёт из чужой страницы.
-
-Включено для `pop_room.c`. Результат:
-
-| | было | стало |
-|---|---:|---:|
-| данные в W2 | 6774 | **5157** |
-| свободно до стека | 129 | **1746** |
-| BANK7 | 12684 | 14301 (87 %) |
-
-**Проверено в MAME**: уровень 1, комнаты 1 и 2 — фон, факелы, решётки,
-проваливающиеся полы и переход между комнатами работают.
-
-## ГЛАВНАЯ ЛОВУШКА: указатель на банковую статику
-
-Первый заход включал ещё и `pop_trob.c` — по Def/Ref он выглядел ИДЕАЛЬНЫМ
-кандидатом (экспортируемых данных нет вообще). Через несколько комнат
-живого прохода **перезагрузился DSS**.
-
-Причина: `pop_trob_modif()` ВОЗВРАЩАЕТ УКАЗАТЕЛЬ на `room_modif[24][30]`, а
-зовут её из банков 2, 3, 7 и резидента. После переноса массив лежит по
-0xC000+ в странице банка 6, но разыменовывает указатель чужой код — когда
-замаплена ЕГО страница. То есть чтение и запись идут по тем же смещениям
-поверх кода соседнего банка. Отсюда и уход системы.
-
-**Анализ Def/Ref этого не видит**: снаружи нет ссылки на символ, есть
-ссылка на функцию, которая отдаёт его адрес. Поэтому условий для
-кандидата ДВА, и второе проверяется только чтением кода:
-
-1. ни один чужой модуль не Ref его глобалы (по `.rel`);
-2. **ни один указатель на его статику не уходит наружу** — ни возвратом, ни
- через out-параметр, ни записью в общий глобал.
-
-У `pop_room` второе выполнено: единственные `&`-выражения наружу —
-`atlas_load(&pop_env[i])`, но `pop_env` определён в `pop_tile.c`, то есть в
-резиденте; `bake_copy` статическая.
-
-Внутри своей страницы указатель безопасен всегда: любой вызов резидентной
-функции, которая перемапливает W3 (`atlas_load`, `pop_page_read`),
-восстанавливает окно перед возвратом.
-
-### Два условия, без которых это молча ломается
-
-1. **Нулевая инициализация.** crt0 зануляет только резидентный `_DATA`, до
- банковых страниц он не дотягивается, а `mkexe` по умолчанию забивает
- пустоты образа `0xFF`. По правилам проекта file-scope переменные никто
- не инициализирует явно (crt0 же зануляет) — значит вся банковая статика
- поднялась бы с `0xFF`. Поэтому `sprinter-cc` при любом `--bank-data`
- САМ добавляет `mkexe -p 0`.
-2. **`_INITIALIZED` остаётся в резиденте.** `--dataseg` переименовывает
- только `_DATA`; инициализированные переменные и их `_INITIALIZER` живут
- как раньше, и gsinit копирует их без участия банков. У `pop_room` таких
- 3 байта — они и остались в W2.
-
-## Что осталось на столе
-
-- `malloc` — **287 Б** резидента, который никто не зовёт: его тянет
- `cbl_open`, где `malloc`/`free` стоят в мёртвой ветке
- `CBL_UNDERRUN_SILENCE`. Вынести аллокацию буфера тишины в отдельный
- модуль libc — и линкер выбросит malloc у всех приложений на
- `CBL_UNDERRUN_APP`.
-- `pop_bg` 289 Б — уедут, если вынести `pop_bg_obj_col/row` (2 байта!) в
- общий резидентный модуль состояния.
-- `pop_tile` — **5972 Б кода** в резиденте, самый крупный жилец. Он там
- потому, что его листья зовут обе половины слоя фона из РАЗНЫХ банков.
- Резать имеет смысл только по этому признаку: что зовут из одного банка —
- туда и переносить.
-- BANK7 после правки на 87 %: следующий кандидат на разгрузку —
- `pop_redraw.c` (981 Б) в другой банк.
diff --git a/applications/PoP/roomtest/Makefile b/applications/PoP/roomtest/Makefile
index 6d74a0e..184b93c 100644
--- a/applications/PoP/roomtest/Makefile
+++ b/applications/PoP/roomtest/Makefile
@@ -35,23 +35,7 @@ MEMORY ?= huge # small-раскладка + банки кода в W
# ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том
# же ALLOCS — иначе сравниваются не правки, а уровни оптимизации.
ALLOCS ?= 3000
-# Писучие данные ЭТОГО банкового модуля живут в его же странице, а не в
-# резиденте W1/W2 (−1620 Б базы). Список из одного файла — не лень, а
-# результат проверки; ДВА условия, и второе стоило перезагрузки DSS:
-#
-# 1) ни один чужой модуль не ссылается на его глобалы (проверяется по
-# .rel: символ Def только в своём объекте и нигде не Ref);
-# 2) НИ ОДИН УКАЗАТЕЛЬ на его статику не уходит наружу. Def/Ref этого не
-# видит. Так провалился pop_trob: pop_trob_modif() возвращает указатель
-# на room_modif[24][30], и его разыменовывают банки 2/3/7 и резидент —
-# то есть пишут по 0xC000+ в СВОЮ страницу, поверх чужого кода.
-#
-# У pop_room оба условия выполнены: _mobs не читает никто, bake_copy
-# статическая, а atlas_load(&pop_env[i]) берёт адрес глобала из pop_tile.c
-# (резидент), не своего. Подробности — ../docs/resident_budget.md.
-BANK_DATA := --bank-data=pop_room.c
-
-EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c --bank 8=pop_shadow.c --bank 8=pop_sfx_cold.c $(BANK_DATA) $(PROF_FLAGS)
+EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c --bank 8=pop_shadow.c --bank 8=pop_sfx_cold.c $(PROF_FLAGS)
# Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по
# умолчанию, пока идёт работа с производительностью; make PROF=0 выключает.
# Каждая фаза кадра красит бордюр в свой цвет, высота полосы на скриншоте
diff --git a/bin/sprinter-cc b/bin/sprinter-cc
index a2d4f38..b3b84f7 100755
--- a/bin/sprinter-cc
+++ b/bin/sprinter-cc
@@ -54,10 +54,6 @@
# no writable data belongs in W3 (code + rodata only). From a
# __banked context the resident W3 code is unreachable (but
# resident -> __banked via the W1 trampoline is fine).
-# --bank-data=SRC писучие данные ТОЛЬКО этого банкового модуля — в его
-# страницу (repeatable). Безопасно лишь если ни один
-# другой модуль не ссылается на его глобалы: проверяется
-# по .rel (Def/Ref). Включает mkexe -p 0 (zero-init).
# --mkexe FLAG extra mkexe flag (repeatable; e.g. --mkexe -p --mkexe 0)
# --max-allocs N SDCC --max-allocs-per-node (default: 100000 — smaller/
# faster code at the cost of compile time; pass a lower
@@ -115,8 +111,7 @@ MKEXE_EXTRA=()
BANK_SPECS=() # entries like "1=engine.c"
W3_SPECS=() # entries like "mod.c" — резидентные модули окна W3 (--w3)
USER_DEFS=() # -DFOO / -DFOO=bar — пробрасываются в sdcc как есть
-BANK_LOCAL_DATA=0 # 1 (--bank-data): писучие данные ВСЕХ банков — в страницу банка
-BANK_DATA_SRCS=() # --bank-data=src.c: только эти модули (выборочно)
+BANK_LOCAL_DATA=0 # 1 (--bank-data): писучие данные банков — В СТРАНИЦУ банка
W3_RELS=() # заполняется при компиляции W3-модулей
W3_LD_FLAGS=() # -Wl-b_W3CODE=0xC000, если есть --w3
USER_SET_MEMORY="" # непусто, если --memory задан явно (для --w3 авто-small)
@@ -153,7 +148,6 @@ while [[ $# -gt 0 ]]; do
-D*) USER_DEFS+=("$1"); shift;;
--bank) BANK_SPECS+=("$2"); shift 2;;
--bank-data) BANK_LOCAL_DATA=1; shift;;
- --bank-data=*) BANK_DATA_SRCS+=("${1#*=}"); shift;;
--mkexe) MKEXE_EXTRA+=("$2"); shift 2;;
--max-allocs) MAX_ALLOCS="$2"; shift 2;;
--gfx) GFX_MODE="$2"; shift 2;;
@@ -442,17 +436,8 @@ if [[ "$CRT0_TYPE" == "banked" ]]; then
# глобал банкового модуля лёг по 0x0001C000): это экономит
# W1/W2, но требует ручного контроля видимости, поэтому
# включается явно через --bank-data.
- # Выборочный режим (--bank-data=src.c) точнее глобального: у
- # большинства банковых модулей часть глобалов ЧИТАЮТ соседние
- # банки и резидент, и такие данные обязаны остаться в W2.
- # Проверять это надо по объектным файлам (кто Def, кто Ref), а
- # не на глаз.
bank_data_flags=()
- bank_data_want=$BANK_LOCAL_DATA
- for bd in "${BANK_DATA_SRCS[@]}"; do
- [[ "$(basename "$bd")" == "$(basename "$bank_src")" ]] && bank_data_want=1
- done
- [[ $bank_data_want -eq 1 ]] && bank_data_flags=(--dataseg "BANK${bank_n}")
+ [[ $BANK_LOCAL_DATA -eq 1 ]] && bank_data_flags=(--dataseg "BANK${bank_n}")
run "$SDCC" "${CC_FLAGS[@]}" \
--codeseg "BANK${bank_n}" --constseg "BANK${bank_n}" \
"${bank_data_flags[@]}" \
@@ -509,16 +494,6 @@ MK_PREFIX=()
[[ $VERBOSE -eq 1 ]] && MK_PREFIX+=(-v)
[[ $BANK_W1 -eq 1 ]] && MK_PREFIX+=(-B 0x4000)
[[ $W3_RESIDENT_HUGE -eq 1 ]] && MK_PREFIX+=(-W)
-# Данные банка в его же странице обязаны стартовать НУЛЯМИ: crt0 зануляет
-# только резидентный _DATA, до банковых страниц он не дотягивается. Даром
-# это даёт паддинг образа нулём вместо дефолтного 0xFF — иначе вся банковая
-# статика поднимется с 0xFF, а по правилам проекта её никто не инициализирует
-# явно (crt0 зануляет _DATA, см. memory/sdcc_static_storage_gotcha).
-if [[ $BANK_LOCAL_DATA -eq 1 || ${#BANK_DATA_SRCS[@]} -gt 0 ]]; then
- mk_has_pad=0
- for f in "${MKEXE_EXTRA[@]}"; do [[ "$f" == "-p" ]] && mk_has_pad=1; done
- [[ $mk_has_pad -eq 0 ]] && MK_PREFIX+=(-p 0)
-fi
MK_PREFIX+=("${MKEXE_EXTRA[@]}")
MK_PREFIX+=(-L "$LOAD_ADDR" -E "$ENTRY_ADDR" -S "$STACK_ADDR" -o "$OUT")
run "$MKEXE" "${MK_PREFIX[@]}" "$IHX"