Убраны три последних /63 %4 в pop_room.c — вызов pop_y_to_row
mob_tick_one (927) и mob_render (976/977) считали `(y+60)/63 % 4 - 1` вручную, хотя pop_y_to_row — точный эквивалент этой формулы на всём int16_t (включая усечение деления к нулю для отрицательных). В asm это были три пары __divsint+__modsint, ~16 200 тактов (3,8 % кадра) — только пока кусок плиты в полёте, то есть в самом тяжёлом кадре. В банке 7 теперь ноль __divsint. Эквивалентность закреплена тестом geom_y_to_row_matches_formula: перебор −400..400 против исходной формулы (вызовы разбросаны по трём банкам, соблазн написать деление «по месту» возвращается). tests-host: [geom] 39 -> 840, все 5 наборов прошли. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -425,6 +425,16 @@ wait-state'ы, и замеренная стоимость выходит **≈ 2
|
||||
`__divuchar` с печатью адреса возврата (`printf "%04X", w@(sp)`) — сразу
|
||||
видно, кто и сколько раз делит за кадр.
|
||||
|
||||
**Хвост подобран 2026-08-10.** После переписи `pop_y_to_row` в pop_room.c
|
||||
осталось ТРИ места, считавших `(y+60)/63 % 4 - 1` вручную (927 в
|
||||
`mob_tick_one`, 976/977 в `mob_render`) — сгенерированный asm подтвердил
|
||||
пару `__divsint`+`__modsint` в каждом. Это ~16 200 тактов (3,8 % кадра), но
|
||||
только пока кусок плиты в полёте — то есть ровно в самом тяжёлом кадре.
|
||||
Заменены вызовом `pop_y_to_row`; в банке 7 теперь НОЛЬ `__divsint`.
|
||||
Эквивалентность закреплена тестом `geom_y_to_row_matches_formula`
|
||||
(перебор −400..400 против исходной формулы) — вызовы разбросаны по трём
|
||||
банкам, и соблазн написать деление «по месту» возвращается.
|
||||
|
||||
**Профиль работы за логический кадр СЕЙЧАС (409 956 тактов + ~15 600 ввод):**
|
||||
|
||||
| блок | тактов | % растрового кадра |
|
||||
|
||||
@@ -924,7 +924,7 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
* поверх Kid, если его тайл идёт в обходе ПОЗЖЕ тайла Kid, а при
|
||||
* совпадении тайлов — если он ниже по y. */
|
||||
{
|
||||
int8_t mrow = (int8_t)(((m->y + 60) / 63) % 4 - 1); /* y_to_row_mod4 */
|
||||
int8_t mrow = pop_y_to_row((int16_t)m->y); /* y_to_row_mod4 */
|
||||
uint8_t over;
|
||||
if (mrow != pop_bg_obj_row) over = (mrow < pop_bg_obj_row); /* ряды идут 2,1,0 */
|
||||
else if (m->col != pop_bg_obj_col) over = (m->col > pop_bg_obj_col);
|
||||
@@ -973,8 +973,8 @@ static void mob_render(mob_t *m, uint8_t pg)
|
||||
* через пол + перекрыта передняя грань пола.
|
||||
* Плюс ВТОРОЙ тайл — под ВЕРХОМ куска (ypos-18), пока кусок висит на
|
||||
* границе рядов. Порт draw_mob (seg007:13E5). */
|
||||
int8_t r = (int8_t)(((m->y + 60) / 63) % 4 - 1);
|
||||
int8_t rt = (int8_t)(((m->y - 18 + 60) / 63) % 4 - 1);
|
||||
int8_t r = pop_y_to_row((int16_t)m->y);
|
||||
int8_t rt = pop_y_to_row((int16_t)(m->y - 18));
|
||||
if (r < 0) pop_t_clip_top = POP_YOFF; /* полоса у потолка — только срез */
|
||||
draw_tile(r, m->col + 1);
|
||||
pop_t_clip_top = 0;
|
||||
|
||||
@@ -56,6 +56,22 @@ TC_TEST(geom_y_to_row)
|
||||
TC_EQ(pop_y_to_row(pop_y_land[4]), -1);
|
||||
}
|
||||
|
||||
/* Цепочка сравнений в pop_y_to_row обязана совпадать с ИСХОДНОЙ формулой
|
||||
* `(y + 60) / 63 % 4 - 1` во всём рабочем диапазоне — включая усечение
|
||||
* деления К НУЛЮ для отрицательных. Тест держит инвариант: вызовы
|
||||
* разбросаны по банкам (pop_map, pop_bg, pop_room), и соблазн написать
|
||||
* деление «по месту» возвращается. */
|
||||
TC_TEST(geom_y_to_row_matches_formula)
|
||||
{
|
||||
int16_t y;
|
||||
/* −400..400 с запасом накрывает всё: кусок loose стартует у потолка
|
||||
* (ряд −1) и улетает ниже поля в комнату снизу. */
|
||||
for (y = -400; y <= 400; y++) {
|
||||
int16_t t = (int16_t)(y + 60);
|
||||
TC_EQ(pop_y_to_row(y), (int8_t)(t / 63 % 4 - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- PRNG: сверка asm-LCG с эталонной формулой ---------------------- */
|
||||
|
||||
#if POP_PRANDOM_EXACT
|
||||
@@ -137,6 +153,7 @@ int main(void)
|
||||
TC_RUN(geom_xbump_layout);
|
||||
TC_RUN(geom_yland_rows);
|
||||
TC_RUN(geom_y_to_row);
|
||||
TC_RUN(geom_y_to_row_matches_formula);
|
||||
#if POP_PRANDOM_EXACT
|
||||
TC_RUN(geom_lcg_matches_reference);
|
||||
TC_RUN(geom_lcg_seed_zero);
|
||||
|
||||
Reference in New Issue
Block a user