Compare commits
5 Commits
81e8ed4676
...
879f2bae31
| Author | SHA1 | Date | |
|---|---|---|---|
| 879f2bae31 | |||
| b3f9a7430c | |||
| fee3bdb354 | |||
| 6a97124e0d | |||
| 8610a8c178 |
@@ -92,11 +92,19 @@ RUNTIME_DEPS := $(wildcard $(PROJ_ROOT)/runtime/*.s)
|
||||
# bankN_*.asm; обычным небанковым программам ничего не стоит.
|
||||
BANK_CHECK := $(PROJ_ROOT)/toolchain/check_bank_calls.py
|
||||
|
||||
# ПРОВЕРКА ISR-СТАБА W0-СТРАНИЦ — там же, по свежей карте. Ловит стаб
|
||||
# _gfx_w0_isr, оставшийся в W1: программа, кладущая свои страницы в W0
|
||||
# (атласы спрайтов, gfx_w0_map), получает недетерминированные зависания,
|
||||
# когда прерывание приходит во время вызова DSS и W1 перемаплен. Только
|
||||
# предупреждение: страницы в W0 кладут не все. Разбор — в шапке скрипта.
|
||||
W0ISR_CHECK := $(PROJ_ROOT)/toolchain/check_w0_isr.py
|
||||
|
||||
$(EXE): $(SOURCES) $(MKEXE) $(LIB) $(RUNTIME_DEPS)
|
||||
$(if $(strip $(BUILD_DIR)),@mkdir -p $(dir $@))
|
||||
$(SPRINTER_CC) $(CC_FLAGS) -o $@ $(SOURCES)
|
||||
@d=$(dir $@).sprinter-cc-$(EXAMPLE); \
|
||||
if ls $$d/bank*_*.asm >/dev/null 2>&1; then python3 $(BANK_CHECK) $$d; fi
|
||||
if ls $$d/bank*_*.asm >/dev/null 2>&1; then python3 $(BANK_CHECK) $$d; fi; \
|
||||
if ls $$d/*.map >/dev/null 2>&1; then python3 $(W0ISR_CHECK) $$d; fi
|
||||
|
||||
$(MKEXE):
|
||||
$(MAKE) -C $(PROJ_ROOT)/toolchain/mkexe
|
||||
|
||||
@@ -47,7 +47,7 @@ MEMORY ?= huge
|
||||
#
|
||||
# ВАЖНО: сравнивать занятость банков можно только при ОДНОМ ALLOCS — иначе
|
||||
# сравниваются не правки, а уровни оптимизации.
|
||||
ALLOCS ?= 6000
|
||||
ALLOCS ?= 10000
|
||||
# Build info не хранится в C: ID и дата извлекаются из текущего commit.
|
||||
BUILD_ID ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo dev)
|
||||
BUILD_DATE ?= $(shell git log -1 --format=%cs 2>/dev/null || echo unknown)
|
||||
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -555,11 +555,6 @@ void pop_determine_col(void) __banked { determine_col(); }
|
||||
* Обе давно работают от Char, а не от Kid; не хватало только объявлений
|
||||
* (docs/sdlpop_audit.md, находка 12). */
|
||||
uint8_t pop_tile_behind_char(void) __banked { return get_tile_behind_char(); }
|
||||
int8_t pop_dist_to_edge_weight(void) __banked
|
||||
{
|
||||
int d = distance_to_edge_weight();
|
||||
return (int8_t)(d > 127 ? 127 : (d < -128 ? -128 : d));
|
||||
}
|
||||
|
||||
/* расстояние до края тайла (для in_wall). */
|
||||
static int distance_to_edge(int xpos)
|
||||
@@ -570,8 +565,15 @@ static int distance_to_edge(int xpos)
|
||||
if (Char.direction == 0) d = TILE_RIGHTX - d; /* dir_0_right */
|
||||
return d;
|
||||
}
|
||||
|
||||
static int distance_to_edge_weight(void) { return distance_to_edge(dx_weight()); }
|
||||
|
||||
int8_t pop_dist_to_edge_weight(void) __banked
|
||||
{
|
||||
int d = distance_to_edge_weight();
|
||||
return (int8_t)(d > 127 ? 127 : (d < -128 ? -128 : d));
|
||||
}
|
||||
|
||||
/* ---- ТОЧНАЯ коллизия со стеной (seg004) --------------------------- *
|
||||
* Передний край персонажа = char_x_right (взгляд вправо) / char_x_left
|
||||
* (влево) из set_char_collision (seg006:0723): obj_x/2 + 58, где obj_x =
|
||||
|
||||
+24
-5
@@ -33,9 +33,16 @@
|
||||
# --data-loc 0xN override SDCC --data-loc (default: derived from --memory)
|
||||
# -Wl FLAG extra linker flag (repeatable)
|
||||
# --bank N=FILE.c compile FILE.c as bank N; repeatable; pulls crt0_banked
|
||||
# --bank-data put bank modules' writable data INTO the bank page
|
||||
# --bank-data [N] put bank modules' writable data INTO the bank page
|
||||
# (default: it goes to the shared _DATA in W1/W2, which
|
||||
# stays mapped and is visible from everywhere)
|
||||
# stays mapped and is visible from everywhere).
|
||||
# Without an argument — for ALL banks (old behaviour).
|
||||
# With a bank number — only for that bank; repeatable:
|
||||
# --bank-data 5 --bank-data 6
|
||||
# Per-bank matters because bank-local data is NOT visible
|
||||
# from outside the bank: a module with an exported global
|
||||
# must stay on the shared _DATA while its neighbour keeps
|
||||
# a big private buffer off the resident budget.
|
||||
# automatically and adds -Wl-b_BANKN=0x{N}C000
|
||||
# --w3 FILE.c place FILE.c resident in window 3 (0xC000), called
|
||||
# DIRECTLY (no trampoline). Repeatable. Defaults to
|
||||
@@ -111,7 +118,8 @@ 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_LOCAL_DATA=0 # 1 (--bank-data без аргумента): данные ВСЕХ банков — в страницу
|
||||
BANK_LOCAL_LIST=() # номера банков из --bank-data N (по одному на банк)
|
||||
W3_RELS=() # заполняется при компиляции W3-модулей
|
||||
W3_LD_FLAGS=() # -Wl-b_W3CODE=0xC000, если есть --w3
|
||||
USER_SET_MEMORY="" # непусто, если --memory задан явно (для --w3 авто-small)
|
||||
@@ -147,7 +155,14 @@ while [[ $# -gt 0 ]]; do
|
||||
-Wl) LD_EXTRA+=("$2"); shift 2;;
|
||||
-D*) USER_DEFS+=("$1"); shift;;
|
||||
--bank) BANK_SPECS+=("$2"); shift 2;;
|
||||
--bank-data) BANK_LOCAL_DATA=1; shift;;
|
||||
--bank-data)
|
||||
# Аргумент необязателен: «--bank-data» = все банки (как было),
|
||||
# «--bank-data N» = только банк N, флаг повторяемый.
|
||||
if [[ -n "${2:-}" && "$2" =~ ^[0-9]+$ ]]; then
|
||||
BANK_LOCAL_LIST+=("$2"); shift 2
|
||||
else
|
||||
BANK_LOCAL_DATA=1; shift
|
||||
fi;;
|
||||
--mkexe) MKEXE_EXTRA+=("$2"); shift 2;;
|
||||
--max-allocs) MAX_ALLOCS="$2"; shift 2;;
|
||||
--gfx) GFX_MODE="$2"; shift 2;;
|
||||
@@ -464,7 +479,11 @@ if [[ "$CRT0_TYPE" == "banked" ]]; then
|
||||
# W1/W2, но требует ручного контроля видимости, поэтому
|
||||
# включается явно через --bank-data.
|
||||
bank_data_flags=()
|
||||
[[ $BANK_LOCAL_DATA -eq 1 ]] && bank_data_flags=(--dataseg "BANK${bank_n}")
|
||||
bank_local=$BANK_LOCAL_DATA
|
||||
for bl in "${BANK_LOCAL_LIST[@]}"; do
|
||||
[[ "$bl" == "$bank_n" ]] && bank_local=1
|
||||
done
|
||||
[[ $bank_local -eq 1 ]] && bank_data_flags=(--dataseg "BANK${bank_n}")
|
||||
run "$SDCC" "${CC_FLAGS[@]}" \
|
||||
--codeseg "BANK${bank_n}" --constseg "BANK${bank_n}" \
|
||||
"${bank_data_flags[@]}" \
|
||||
|
||||
@@ -3,7 +3,7 @@ accfill 3797
|
||||
accop 7067
|
||||
argv 3445
|
||||
assrtest 3861
|
||||
atlas 9193
|
||||
atlas 9627
|
||||
attrprob 4101
|
||||
banked 1070
|
||||
bankedbg 1081
|
||||
|
||||
|
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
check_w0_isr.py — предупредить, что ISR-стаб W0-страниц оказался в W1.
|
||||
|
||||
Зачем. Программа может временно маппить свою EMM-страницу в W0 (атласы
|
||||
спрайтов в sprite_update, ресурсы через gfx_w0_map). Пока страница там,
|
||||
ЛЮБОЕ прерывание уходит на #0038 ЭТОЙ страницы, поэтому gfx_w0_page_prepare()
|
||||
прошивает туда `JP _gfx_w0_isr`, а стаб возвращает страницу ядра DSS, зовёт
|
||||
честный обработчик и восстанавливает страницу обратно.
|
||||
|
||||
Мина. Сам стаб живёт в _CODE. В режимах small и huge _CODE начинается с
|
||||
0x4100, то есть попадает в W1 — окно, которое DSS перемаппит на время СВОИХ
|
||||
вызовов (docs/new/04-memory.md §4.2, §4.9). Если прерывание придёт, пока
|
||||
наша страница в W0 И идёт вызов DSS, переход уйдёт по адресу, которого в этот
|
||||
момент нет: W1 читается как #FF, процессор уползает в бесконечный пролог
|
||||
системного прерывания. Само libbgi это документирует в common/_gfx_w0_isr.c
|
||||
(«обязан быть в W2»).
|
||||
|
||||
Собирается это МОЛЧА и проявляется НЕДЕТЕРМИНИРОВАННО — зависанием примерно
|
||||
на каждом третьем холодном старте, что легко списать на случайность. Поймано
|
||||
вживую 2026-09-01 в порте Loom (huge): стаб был на 0x6769.
|
||||
|
||||
Как проверяем. По .map берём адрес __gfx_w0_isr. Если символа нет — W0-путь
|
||||
в программу не слинкован, молча выходим. Если адрес >= 0x8000 — он в W2, всё
|
||||
хорошо. Иначе печатаем WARNING: сборку не валим, потому что программа могла
|
||||
и не класть свои страницы в W0.
|
||||
|
||||
Лечение (со стороны приложения): вернуть модули из банков в резидент или
|
||||
разгрузить _DATA так, чтобы _CODE перевалил за 0x8000 и хвост libbgi уехал в
|
||||
W2. Порядок линковки сам по себе не помогает: пока весь _CODE влезает в W1
|
||||
(ёмкость 0x8000-0x4100 = 16128 Б), расстановка модулей ничего не меняет.
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
W2_BASE = 0x8000
|
||||
SYM = '__gfx_w0_isr'
|
||||
MAP_RE = re.compile(r'^\s+([0-9A-Fa-f]{4,8})\s+(\S+)\s')
|
||||
|
||||
|
||||
def find_symbol(map_path, name):
|
||||
for line in map_path.read_text(errors='replace').splitlines():
|
||||
m = MAP_RE.match(line)
|
||||
if m and m.group(2) == name:
|
||||
return int(m.group(1), 16)
|
||||
return None
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) != 2:
|
||||
print(__doc__.strip())
|
||||
return 2
|
||||
build = Path(argv[1])
|
||||
maps = list(build.glob('*.map'))
|
||||
if not maps:
|
||||
print(f'check_w0_isr: нет .map в {build}', file=sys.stderr)
|
||||
return 2
|
||||
|
||||
addr = find_symbol(maps[0], SYM)
|
||||
if addr is None:
|
||||
return 0 # W0-путь не слинкован — проверять нечего
|
||||
if addr >= W2_BASE:
|
||||
print(f'check_w0_isr: {SYM} @ 0x{addr:04X} — в W2, ок')
|
||||
return 0
|
||||
|
||||
print(f'check_w0_isr: ВНИМАНИЕ — {SYM} @ 0x{addr:04X} лежит в W1.',
|
||||
file=sys.stderr)
|
||||
print(' Если программа маппит свои страницы в W0 (атласы спрайтов, '
|
||||
'gfx_w0_map,', file=sys.stderr)
|
||||
print(' atlas_attach), прерывание во время вызова DSS уйдёт в '
|
||||
'перемапленное W1 —', file=sys.stderr)
|
||||
print(' недетерминированные зависания на старте. Стаб обязан быть в W2 '
|
||||
f'(>= 0x{W2_BASE:04X}).', file=sys.stderr)
|
||||
print(' Лечение: увести _CODE за 0x8000 (модули из банков в резидент / '
|
||||
'разгрузить', file=sys.stderr)
|
||||
print(' _DATA). Подробности — в шапке этого скрипта и '
|
||||
'docs/new/04-memory.md §4.2.', file=sys.stderr)
|
||||
return 0 # предупреждение, сборку не валим
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
Reference in New Issue
Block a user