Оптимизация: логический кадр уложился в бюджет, цикл 4 растровых кадра -> 3

Главный цикл спейсится тремя gfx_wait_vsync, поэтому работа сверх 430 000
тактов стоит сразу целый лишний растровый кадр.  Было 470 964, стало
~425 600 — игра быстрее на треть (16,7 логических кадров/с против 12,5).

- pop_y_to_row: цепочка сравнений вместо (y+60)/63%4-1.  ВАЖНО: медленный
  хвост вынесен в ОТДЕЛЬНУЮ функцию — SDCC видит одинаковое выражение в двух
  ветках и поднимает деление в вершину, быстрые возвраты не спасают.
- col_from_x (pop_bg) и get_tile_div_mod (pop_map) — общие резидентные
  таблицы POP_TILE_DIV/POP_TILE_MOD в pop_tile.c (const банка из чужого
  банка не читается).
- pop_fore_over_char: расширение окна считается арифметикой, а не перебором
  10 колонок и 3 рядов (условие монотонно -> границы).  Формулы сверены с
  прежним перебором перебором значений, расхождений нет.
- pop_cd_touch: цикл по страницам развёрнут, x+w/y+h считаются один раз.
  Зовётся с каждого блита фона, стоил 6 846 тактов.
- process_trobs: tp/10 и tp%10 у факелов — таблицей.
- Пустой слот соперника (стража на сцене нет, на странице ничего не
  нарисовано) считается «тихим»: ни heal, ни вход в pop_char_draw, ни
  fore-проход.

Приём для поиска делений: брейкпоинт на __divsint/__divuint/__divuchar с
печатью адреса возврата (printf "%04X", w@(sp)).

Профиль остатка — TASKS_OPEN.md#draw-cost.  tests-host: 5/5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-09 15:49:46 +03:00
parent d0030922ff
commit b0524b9ad0
9 changed files with 261 additions and 111 deletions
+27 -1
View File
@@ -10,9 +10,35 @@ const int16_t pop_x_bump[20] = {
};
const int16_t pop_y_land[5] = {-8, 55, 118, 181, 244};
#define TILE_SIZEY_OFF 60 /* сдвиг «ряд 0 начинается выше нуля» */
/* Медленный хвост — ОТДЕЛЬНОЙ функцией. Иначе SDCC видит одно и то же
* выражение в двух ветках и поднимает деление в вершину функции: быстрые
* возвраты уже не спасают, __divsint зовётся всё равно (проверено —
* 5 вызовов за кадр остались после первой переписи). */
static int8_t y_row_div(int16_t t)
{
return (int8_t)(t / TILE_SIZEY % 4 - 1);
}
int8_t pop_y_to_row(int16_t y)
{
return (int8_t)((y + 60) / TILE_SIZEY % 4 - 1);
/* Было `(y + 60) / 63 % 4 - 1` — SDCC разворачивает это в __divsint плюс
* __modsint (а тот внутри снова зовёт __divsint): ~5 400 тактов на вызов
* по замеру в MAME, при том что полос всего четыре. Цепочка сравнений
* повторяет ИМЕННО прежнюю арифметику, включая усечение деления К НУЛЮ
* для отрицательных (t в −62..−1 даёт 0, а не 1). */
int16_t t = (int16_t)(y + TILE_SIZEY_OFF);
if (t >= 0) {
if (t < TILE_SIZEY) return -1; /* 0 % 4 - 1 */
if (t < 2*TILE_SIZEY) return 0;
if (t < 3*TILE_SIZEY) return 1;
if (t < 4*TILE_SIZEY) return 2;
if (t < 5*TILE_SIZEY) return -1; /* 4 % 4 = 0 */
} else if (t > -TILE_SIZEY) {
return -1; /* t/63 == 0 -> 0 % 4 - 1 */
}
return y_row_div(t);
}
/* Уложить значение в диапазон 0..maxv. Вызовы оригинала — prandom(1),