SprPoP: финал больше не убивает программу — прямой вызов в чужой банк
Пройденная игра доходила до таблицы рекордов и умирала: программа
исчезала, машина следом вставала намертво (di;halt на 0x0000) либо уходила
в reset. Одинаково из Flex Navigator и из голого DSS.
КОРЕНЬ. pop_ui.h объявлял группу pop_text_*_mapped БЕЗ __banked. Пока
pop_hof.c лежал в банке 9 рядом с pop_ui.c, прямой call был верен; после
переноса pop_hof/pop_config/pop_pal в банк 10 тот же call стал уходить в
пустой хвост чужого банка. Процессор полз по 0xFF до 0x0000, где ловушка
DSS ставит B=0x27 и сворачивает процесс — подмена страниц W1/W2/W3,
которую было видно на трупе, оказалась уборкой, а не причиной.
Точную инструкцию (call $E503 = _pop_text_map банка 9) дала трассировка
MAME на узком участке: trace включалась брейкпоинтом на входе в
pop_hof_show и выключалась на процедуре завершения процесса DSS (0x1E56).
ЧТО СДЕЛАНО
* pop_ui.h/.c — группа text_*_mapped помечена __banked.
* toolchain/check_bank_calls.py — две проверки банкового кода:
1) прямой call в чужой банк (доказательна, ВАЛИТ сборку — проверено
намеренной поломкой);
2) указатель на данные своего банка, отданный в чужой (эвристика по
форме кода, только предупреждает).
Встроена в app.mk, запускается сразу после линковки.
* pop_hof.c — курсор ввода строится на стеке: литерал "_" лежал в _BANK10
и после пометки __banked уезжал из-под ног чужому банку, заливая экран
знаками вопроса.
* libc: kbd_raw_keypad_as_ext() — kbd_raw_sync переносит голые коды
нумпада в EXT-половину карты. Лечит залипание стрелок (потерянный
префикс E0 сажал make в PLAIN как код нумпада, и снять его было нечем),
заодно нумпад стал управлением: 7/8/9, 4/6, 2 и 5 = вниз.
* pop_pace.c — цикл ожидания луча зовёт тот же idle-хук, что и
gfx_wait_vsync: без этого F10 в геймплее не работал вовсе.
* pop_hof.c — Esc в таблице рекордов отменяет запись (расхождение с
оригиналом записано в docs/impl_diff.md).
* Экран версии показывается только через Menu/Settings/About: стартовый
показ и Ctrl+V убраны, мёртвый код снят.
* sprpop_cold.c — pop_start_level зовёт pop_hp_invalidate: после Ctrl+A с
выросшим за уровень максимумом полоса HP моргала между страницами.
Разбор всех четырёх багов — в applications/PoP/roomtest/BUGS_CLOSED.md
(FINAL-BANKCALL, FINAL-HOF-GARBAGE, KBD-ARROW-PHANTOM, F10-GAMEPLAY),
правило про банки — в applications/SprPoP/CLAUDE.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -665,6 +665,12 @@ void pop_control(void) __banked
|
||||
* «откуда взялся прыжок» останется одним. */
|
||||
#define KBD_HOME (KBD_EXT | 0x6C)
|
||||
#define KBD_PGUP (KBD_EXT | 0x7D)
|
||||
/* Центр нумпада (KP5) — тоже «вниз», как просит раскладка оригинала: там
|
||||
* весь блок 7/8/9-4/6-1/2/3 был управлением, и середина работала как
|
||||
* приседание. Своей навигационной клавиши у KP5 нет, поэтому после
|
||||
* kbd_raw_keypad_as_ext его голый код 0x73 переезжает в EXT-половину как
|
||||
* есть — читаем оттуда и добавляем к стрелке «вниз». */
|
||||
#define KBD_KP5 (KBD_EXT | 0x73)
|
||||
|
||||
static void read_input(void)
|
||||
{
|
||||
@@ -673,7 +679,7 @@ static void read_input(void)
|
||||
uint8_t l = (uint8_t)(kbd_raw_down(KBD_LEFT) || home);
|
||||
uint8_t r = (uint8_t)(kbd_raw_down(KBD_RIGHT) || pgup);
|
||||
uint8_t u = (uint8_t)(kbd_raw_down(KBD_UP) || home || pgup);
|
||||
uint8_t d = kbd_raw_down(KBD_DOWN);
|
||||
uint8_t d = (uint8_t)(kbd_raw_down(KBD_DOWN) || kbd_raw_down(KBD_KP5));
|
||||
control_x = r ? CONTROL_HELD_RIGHT : (l ? CONTROL_HELD_LEFT : CONTROL_RELEASED);
|
||||
control_y = d ? CONTROL_HELD_DOWN : (u ? CONTROL_HELD_UP : CONTROL_RELEASED);
|
||||
control_shift = (kbd_raw_down(KBD_LSHIFT) || kbd_raw_down(KBD_RSHIFT))
|
||||
@@ -781,6 +787,16 @@ int pop_ctrl_init(void) __banked
|
||||
control_forward = control_backward = control_up = control_down = CONTROL_RELEASED;
|
||||
control_shift2 = CONTROL_RELEASED;
|
||||
ctrl1_forward = ctrl1_backward = ctrl1_up = ctrl1_down = ctrl1_shift2 = CONTROL_RELEASED;
|
||||
/* НУМПАД НАМ НЕ НУЖЕН, И ЭТО ЛЕЧИТ ЗАЛИПАНИЕ СТРЕЛОК. Управление и
|
||||
* меню читают только расширенные коды (KBD_LEFT = KBD_EXT|0x6B и т.д.).
|
||||
* А при переполнении FIFO SIO теряется префикс E0, и make стрелки
|
||||
* садится в PLAIN-половину карты как код нумпада — снять его нечем,
|
||||
* потому что break придёт уже с префиксом. Дальше kbd_raw_any_down()
|
||||
* навсегда «да», и всякое ожидание «пока ничего не нажато» виснет
|
||||
* насмерть (BUG KBD-STUCK-WAIT; поймано на 14-м уровне, где почти весь
|
||||
* путь идёт удержанием Left). Гасит биты kbd_raw_sync(), а его
|
||||
* pop_ctrl_tick зовёт каждый кадр. */
|
||||
kbd_raw_keypad_as_ext(1);
|
||||
return kbd_raw_open();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user