scr_x: таблица готовых значений на весь диапазон, включая отрицательные

Первая версия крыла только 0..255 байтовой таблицей x/7 по тождеству
8x/7 == x + x/7.  Это было мимо: obj_x = 2*fwd - 116 уходит в минус, как
только fwd < 58 (левее x_bump[5]) — то есть у ЛЕВОЙ КРОМКИ комнаты, и там
мы продолжали звать __divsint.

Границы взяты из данных, а не на глаз: kid_data.bin даёт dx кадров Кида
-5..+10, стража -2..+10; при Char.x типа uint8_t и render_dx из
{-140,0,+140} полный диапазон obj_x = -416..695.  SCRX[1152] кроет
-448..703 — деление стало недостижимым, оставлено страховкой.

Хранится ГОТОВОЕ значение (int16_t), а не x/7: байтовая таблица вдвое
меньше, но со знаковыми значениями требует расширения знака плюс
16-битного сложения — те же такты, что лишний add hl,hl при 2-байтном
индексе.  Кодоген проверен: индекс полный 16-битный (грабли
sdcc_z80_const_ptr_index_bug обойдены отдельной uint16_t-переменной),
~130 тактов номинала против ~1 000 у __divsint.

Банк 4: 7 336 -> 9 394 из 16 384 (свободно 6 990).  Таблица сверена
питоном обратно из .c (1 152 записи), правило генерации «усечение к нулю»
закреплено тестом geom_mul8div7_trunc_to_zero на целевом компиляторе.
tests-host: [geom] 1961 -> 1992, все 5 наборов прошли.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 20:35:01 +03:00
parent 72797e1be8
commit 8175121d25
3 changed files with 169 additions and 42 deletions
+14 -9
View File
@@ -72,16 +72,21 @@ TC_TEST(geom_y_to_row_matches_formula)
}
}
/* calc_screen_x_coord (seg008:2602) считается в pop_cdraw.c таблицей DIV7 по
* тождеству 8x/7 == x + x/7 (7x делится нацело, поэтому усечение обеих частей
* совпадает). Само тождество и проверяем — оно и есть неочевидная часть;
* таблица DIV7 сгенерирована как x/7 и живёт в банке 4, сюда не линкуется. */
TC_TEST(geom_mul8div7_identity)
/* calc_screen_x_coord (seg008:2602) считается в pop_cdraw.c ГОТОВОЙ таблицей
* SCRX (банк 4, сюда не линкуется). Таблица сгенерирована питоном по правилу
* «усечение К НУЛЮ»: значение = знак(x) * (|x|*8 / 7). Проверяем ИМЕННО это
* правило на целевом компиляторе: если бы __divsint у SDCC округлял иначе
* (к минус бесконечности), вся отрицательная половина таблицы уехала бы на
* пиксель, а поймалось бы это только глазами на левой кромке комнаты. */
TC_TEST(geom_mul8div7_trunc_to_zero)
{
int16_t x;
/* obj_x = 2*fwd 116; со сдвигом шва (∓140) уходит в 406..684. */
for (x = -420; x <= 700; x++)
TC_EQ((int16_t)(x * 8 / 7), (int16_t)(x + x / 7));
/* Полный диапазон obj_x по данным кадров: 416..695 (см. шапку scr_x). */
for (x = -448; x <= 703; x++) {
int16_t want = (int16_t)(((x < 0) ? -x : x) * 8 / 7);
if (x < 0) want = (int16_t)-want;
TC_EQ((int16_t)(x * 8 / 7), want);
}
}
/* ---- PRNG: сверка asm-LCG с эталонной формулой ---------------------- */
@@ -166,7 +171,7 @@ int main(void)
TC_RUN(geom_yland_rows);
TC_RUN(geom_y_to_row);
TC_RUN(geom_y_to_row_matches_formula);
TC_RUN(geom_mul8div7_identity);
TC_RUN(geom_mul8div7_trunc_to_zero);
#if POP_PRANDOM_EXACT
TC_RUN(geom_lcg_matches_reference);
TC_RUN(geom_lcg_seed_zero);