Луч видимости стража: колонка из таблицы вместо деления (Кид у шва)
tile_at_kid (guards.c) считала колонку честным / и %, хотя резидентная POP_TILE_DIV — это и есть tile_div_tbl оригинала, и остальной порт давно на неё переведён. У SDCC z80 пара / и % над int это __divsint плюс __modsint, который внутри снова зовёт __divsint — ~5 400 тактов на вызов. Зовут её в ЦИКЛЕ по колонкам между стражем и Кидом (check_can_guard_see_kid, seg003:761). Когда Кид у шва, его curr_col = −1, луч тянется через всю комнату: замер дал ВОСЕМЬ пар делений за кадр, около 43 000 тактов = 10 % растрового кадра, в фазе логики. После фикса таких вызовов не остаётся. Как ловилось: брейкпоинт на __divsint с печатью адреса возврата дал ret=C033 восемь раз за кадр; остановка на нём с dasm при замапленном банке показала HL−65 / ld de,#14 / call __divsint по смещению 0x24 банка 1. Снята и ложная тревога из прошлого коммита: пролог pop_char_fore на шве НЕ разбухает до 134 730 — это была ошибка зонда (адрес fore_tile в банке совпадает с кодом других банков, в интервал попадали чужие срабатывания). Чистый замер: пролог 16 950, как и в середине комнаты. Урок записан в «Как мерить» в docs/perf_backlog.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,16 @@ MAME (`z80_profiling_method`) на роомтесте, уровень 1 комн
|
||||
только по ОДНОЙ функции с одинаковыми входами, а не по общей работе за
|
||||
кадр.
|
||||
- Кто делит: брейкпоинт на `__divsint`/`__divuint`/`__divuchar` с печатью
|
||||
адреса возврата — `bpset <addr>,1,{printf "ret=%04X\n",w@(sp); g}`.
|
||||
адреса возврата — `bpset <addr>,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**
|
||||
|
||||
Все три шага выполнены; замер после — в конце пункта. Ниже сохранён исходный
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user