diff --git a/applications/PoP/docs/perf_backlog.md b/applications/PoP/docs/perf_backlog.md index 53e9ff7..0789b7a 100644 --- a/applications/PoP/docs/perf_backlog.md +++ b/applications/PoP/docs/perf_backlog.md @@ -24,7 +24,16 @@ MAME (`z80_profiling_method`) на роомтесте, уровень 1 комн только по ОДНОЙ функции с одинаковыми входами, а не по общей работе за кадр. - Кто делит: брейкпоинт на `__divsint`/`__divuint`/`__divuchar` с печатью - адреса возврата — `bpset ,1,{printf "ret=%04X\n",w@(sp); g}`. + адреса возврата — `bpset ,1,{printf "ret=%04X\n",w@(sp); g}`. Если + адрес возврата в банке (>= 0xC000), поставить тот же брейкпоинт с условием + `w@(sp)==<адрес>` и БЕЗ `g`: машина встанет с нужным банком в окне, и + `dasm` покажет вызывающего. +- **Брейкпоинт по адресу в банке ловит ВСЕ банки.** 0xC000..0xFFFF — общее + окно, и один и тот же адрес есть у семи модулей сразу. Либо ловить через + трамплин (`hl==<адрес>&&(de&0xff)==<банк>`), либо перепроверять, что + срабатывания идут из нужной фазы: иначе в интервал попадает чужой код и + цифры врут (так я намерил несуществующие 134 730 тактов в прологе + `pop_char_fore`). - Трасса вызовов графики с параметрами: скрипт в истории сессии, ставит маркеры фаз на трамплин `___sdcc_bcall_ehl` (условие `hl==<адрес>&&(de&0xff)==<банк>`) и брейкпоинты на листья libbgi с печатью аргументов @@ -97,6 +106,34 @@ MAME (`z80_profiling_method`) на роомтесте, уровень 1 комн --- +## СДЕЛАНО 2026-08-10: деление в луче видимости стража (Кид у шва) + +`tile_at_kid` (`guards.c`) считала колонку честным `/` и `%`, тогда как везде +уже стоит резидентная таблица `POP_TILE_DIV` (это и есть `tile_div_tbl` +оригинала). У SDCC z80 это `__divsint` плюс `__modsint`, а тот внутри снова +зовёт `__divsint` — ~5 400 тактов на вызов. + +Зовут её В ЦИКЛЕ по колонкам между стражем и Кидом +(`check_can_guard_see_kid`, seg003:761). Когда Кид стоит У ШВА, его +`curr_col = −1`, луч тянется через всю комнату, и за кадр набегало ВОСЕМЬ пар +делений — около 43 000 тактов, 10 % растрового кадра, в фазе ЛОГИКИ. + +Замер: брейкпоинт на `__divsint` с печатью адреса возврата дал `ret=C033` +восемь раз за кадр; остановка на нём и дизассемблирование с правильным банком +показали `HL−65`, `ld de,#14`, `call __divsint` по смещению 0x24 банка 1 — +`tile_at_kid`. После фикса пар `C033` не остаётся ни одной. + +**Заодно снята ложная тревога.** В прошлом замере я записал, что на шве +пролог `pop_char_fore` разбухает до 134 730 тактов. Это была ошибка зонда: +брейкпоинт на `fore_tile` стоял по адресу, который совпадает с кодом ДРУГИХ +банков, и в интервал попадали чужие срабатывания. Чистый замер (Кид в +колонке 0, спрайт свисает за левый край, окно `x −8..5`): пролог **16 950** — +ровно как в середине комнаты, весь fore-проход 41 803, `pop_room_clip_borders` +14 364. Урок в «Как мерить» выше: адрес в банке нужно либо проверять на +уникальность, либо ловить через трамплин с условием на банк. + +--- + ## 0. Дворцовая кладка в fore-проходе — **СДЕЛАНО 2026-08-10** Все три шага выполнены; замер после — в конце пункта. Ниже сохранён исходный diff --git a/applications/PoP/roomtest/guards.c b/applications/PoP/roomtest/guards.c index a7e93dd..74e86c8 100644 --- a/applications/PoP/roomtest/guards.c +++ b/applications/PoP/roomtest/guards.c @@ -23,6 +23,7 @@ #include "pop_trob.h" #include "pop_level.h" /* pop_current_level — спецсобытие уровня 3 */ #include "pop_state.h" /* pop_immortal, pop_droppedout */ +#include "pop_tile.h" /* POP_TILE_DIV — таблица колонок (tile_div_tbl) */ #define TILE_MIDX 7 /* середина тайла в координатах персонажа */ #define SCREENSPACE_X 58 /* = pop_x_bump[FIRST_ONSCREEN_COLUMN] */ @@ -61,12 +62,29 @@ static uint8_t tile_at_kid(int16_t xpos) { /* get_tile_div_mod_m7 (seg006:697): колонка = floor((xpos − 7 − 58)/14), * СРАЗУ в координатах комнаты (58 = x_bump[FIRST_ONSCREEN_COLUMN]). - * Оригинал берёт её из tile_div_tbl, у нас — делением с округлением - * вниз, как в pop_map. */ - int16_t x = xpos - 7 - SCREENSPACE_X; - int16_t col = x / TILE_SIZEX; - if (x % TILE_SIZEX < 0) --col; - tile_col = (int8_t)col; + * Оригинал берёт её из tile_div_tbl — и мы теперь тоже: резидентная + * POP_TILE_DIV[] это ровно она (индекс = xpos, значение = floor((xpos−58)/14)), + * поэтому здесь индексируем её на xpos−7. + * + * Было честное `/` и `%`: у SDCC z80 это __divsint плюс __modsint, а тот + * внутри снова зовёт __divsint — около 5 400 тактов на вызов. А зовут + * нас В ЦИКЛЕ по колонкам между стражем и Кидом + * (check_can_guard_see_kid, seg003:761). Когда Кид у шва, его + * curr_col = −1, луч тянется через всю комнату, и за кадр набегало ВОСЕМЬ + * пар делений — ~43 000 тактов, 10 % растрового кадра, в фазе логики + * (замер MAME 2026-08-10, уровень 1 комната 2). + * + * Медленный хвост остаётся для xpos за пределами таблицы (страж и Кид в + * разных комнатах: логическая X уезжает на ±140). */ + int16_t x = xpos - 7; + if ((uint16_t)x < 256u) { + tile_col = POP_TILE_DIV[x]; + } else { + int16_t v = x - SCREENSPACE_X; + int16_t col = v / TILE_SIZEX; + if (v % TILE_SIZEX < 0) --col; + tile_col = (int8_t)col; + } return pop_tile_at(tile_col, Kid.curr_row); }