scr_x: байтовая таблица x/7 вместо словарной — 1 такт быстрее, -1152 Б

Гипотеза «двухбайтная индексация съест выигрыш от сложения» не
подтвердилась.  Собраны ОБА варианта, такты посчитаны по сгенерированному
asm (хвост после проверки границ):

  int16_t готовое: add hl,hl / add hl,de / ld e,(hl) / inc hl / ld d,(hl)
                   = 132 такта, 2 304 байта
  int8_t  x/7:     add hl,bc / ld a,(hl) / ld l,a / rlca / sbc a,a /
                   ld h,a / add hl,de  = 131 такт, 1 152 байта

Расширение знака плюс 16-битное сложение стоят ровно столько же, сколько
лишний add hl,hl при двухбайтном индексе, а обращений к памяти на одно
меньше — под wait-state'ами Sprinter (2,4x номинала именно на обращениях
к ОЗУ) байтовый вариант ещё чуть выгоднее номинала.

Банк 4: 9 394 -> 8 243 из 16 384 (свободно 8 141 вместо 6 990) — запас под
рост pop_cdraw, о котором и был вопрос.

Тест переименован в geom_mul8div7_table_rules и проверяет ОБА правила
генерации таблицы: тождество 8x/7 == x + x/7 и усечение к нулю.
tests-host: [geom] 1992 -> 3144, все 5 наборов прошли.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 20:43:27 +03:00
parent 8175121d25
commit fc0ede91e1
3 changed files with 115 additions and 132 deletions
+26 -15
View File
@@ -454,8 +454,8 @@ awk '/^;[a-z_0-9]+\.[ch]:[0-9]+:/{s=$0} /^\tcall\t__(div|mod|mul)/{printf "%-22s
| `pop_guard.c` `guard_col_from_x` | `/14` + `%14` **безусловно**, мимо `POP_TILE_DIV` | единственное 16-битное деление, у которого таблица вообще не была подключена |
| `pop_trob.c` `animate_chomper` | `tp / 10` = `__divuchar` на чомпера каждый кадр | таблицы `TP_ROW`/`TP_COL` уже лежали в ЭТОМ ЖЕ файле, но ниже по тексту — чомперы их не видели |
Приём для `×8/7`: **таблица готовых значений** `SCRX[1152]` (int16_t) в
банке 4, индекс `x + 448`. 2 304 байта, резидент не тронут.
Приём для `×8/7`: **таблица** `SCRX7[1152]` (int8_t, хранит `x/7`) в банке 4,
индекс `x + 448`, результат `x + SCRX7[i]`. 1 152 байта, резидент не тронут.
Два решения по дороге, оба проверены, а не угаданы:
@@ -468,22 +468,33 @@ awk '/^;[a-z_0-9]+\.[ch]:[0-9]+:/{s=$0} /^\tcall\t__(div|mod|mul)/{printf "%-22s
`render_dx ∈ {140, 0, +140}` полный диапазон `obj_x` = **416..695**.
Таблица кроет −448..703, деление стало недостижимым (оставлено
страховкой на третьего персонажа / другой `render_dx`).
2. **Хранить готовое значение, а не `x/7`.** Байтовая таблица вдвое меньше,
но со знаковыми значениями к ней добавляются расширение знака и 16-битное
сложение — ровно те же такты, что лишний `add hl,hl` при 2-байтном
индексе. Раз выигрыша нет, берём вариант без арифметики.
2. **Хранить `x/7` байтом, а не готовое `x*8/7` словом** — по тождеству
`8x/7 == x + x/7`. Первая версия хранила готовое, «раз всё равно
индексация двухбайтная». Собраны ОБА варианта, такты посчитаны по
сгенерированному asm:
| вариант | хвост после проверки границ | тактов | байт |
|---|---|---|---|
| `int16_t` готовое | `add hl,hl / add hl,de / ld e,(hl) / inc hl / ld d,(hl)` | **132** | 2 304 |
| `int8_t` `x/7` | `add hl,bc / ld a,(hl) / ld l,a / rlca / sbc a,a / ld h,a / add hl,de` | **131** | 1 152 |
Расширение знака и 16-битное сложение стоят ровно столько же, сколько
лишний `add hl,hl` при двухбайтном индексе, а обращений к памяти на одно
меньше — под wait-state'ами Sprinter (такт ≈ 2,4× номинала именно на
обращениях к ОЗУ) байтовый вариант ещё чуть выгоднее номинала. Итог:
байтовая таблица не хуже по скорости и на килобайт меньше. **Урок:
«двухбайтный индекс съест выигрыш» — гипотеза; она не подтвердилась.**
Кодоген проверен глазами (`bank4_pop_cdraw.asm`): `ld hl,#0x01C0; add hl,de`,
16-битное беззнаковое сравнение, `add hl,hl; add hl,de; ld e,(hl); inc hl;
ld d,(hl)` — индекс полный, старший байт не теряется (грабли
`sdcc_z80_const_ptr_index_bug` обойдены отдельной `uint16_t`-переменной).
≈130 тактов номинала против ~1 000 у `__divsint`.
16-битное беззнаковое сравнение — индекс полный, старший байт не теряется
(грабли `sdcc_z80_const_ptr_index_bug` обойдены отдельной
`uint16_t`-переменной). 131 такт номинала против ~1 000 у `__divsint`.
Проверка таблицы: значения сверены питоном обратно из `.c` со всеми 1 152
записями, а ПРАВИЛО генерации («усечение к нулю») — тестом
`geom_mul8div7_trunc_to_zero` на целевом компиляторе: округляй SDCC к минус
бесконечности, вся отрицательная половина уехала бы на пиксель, и поймалось
бы это только глазами на левой кромке.
Проверка таблицы: все 1 152 записи сверены питоном обратно из `.c`, а ПРАВИЛА
генерации (тождество + усечение к нулю) — тестом `geom_mul8div7_table_rules`
на целевом компиляторе: округляй SDCC к минус бесконечности, вся
отрицательная половина уехала бы на пиксель, и поймалось бы это только
глазами на левой кромке.
Оставлено сознательно (НЕ трогать, это не забытые места):
+77 -108
View File
@@ -117,12 +117,21 @@ void pop_guard_free(void) __banked
* `__divsint` — 2 400 тактов на вызов, и зовётся оно на КАЖДОГО персонажа
* КАЖДЫЙ кадр (последнее деление, остававшееся в горячем пути).
*
* Таблица хранит ГОТОВЫЙ результат (int16_t), а не x/7 с последующим
* сложением по тождеству 8x/7 == x + x/7. Байтовая таблица вдвое меньше,
* но она обязана быть знаковой (x/7 при x<0 отрицателен), а значит к её
* значению добавляется расширение знака плюс 16-битное сложение — по
* тактам это ровно то же самое, что лишний `add hl,hl` при 2-байтном
* индексе. Раз выигрыша нет, берём вариант без арифметики вообще.
* ХРАНИМ x/7 БАЙТОМ, а не готовое x*8/7 словом. Тождество: 8x/7 == x + x/7
* (7x делится нацело, поэтому усечение обеих частей совпадает — и для
* отрицательных с трункейтом к нулю тоже). Оба варианта собраны и
* посчитаны по сгенерированному asm:
*
* int16_t готовое: ... add hl,hl / add hl,de / ld e,(hl) / inc hl /
* ld d,(hl) = 132 такта, 2 304 байта
* int8_t x/7: ... add hl,bc / ld a,(hl) / ld l,a / rlca / sbc a,a /
* ld h,a / add hl,de = 131 такт, 1 152 байта
*
* Расширение знака и 16-битное сложение стоят РОВНО столько же, сколько
* лишний `add hl,hl` при двухбайтном индексе, а чтение из памяти на одно
* меньше — под wait-state'ами Sprinter (такт ≈ 2,4× номинала на обращениях
* к ОЗУ) байтовый вариант даже чуть выгоднее номинала. Плюс килобайт
* банка, который в pop_cdraw ещё понадобится.
*
* ДИАПАЗОН — весь, а не «обычный случай». Отрицательные X реальны:
* obj_x = 2*fwd 116 уходит в минус, как только fwd < 58 (левее
@@ -133,109 +142,69 @@ void pop_guard_free(void) __banked
* Деление ниже поэтому недостижимо и оставлено страховкой на случай
* третьего персонажа или другого render_dx.
*
* Цена: 2 304 байта в банке 4 (там было 9 048 свободно).
*
* Экранная X по логической: SCRX[x + SCRX_BIAS] == x*8/7 (усечение к
* нулю, как в C и как у 8086 idiv в оригинале). */
* SCRX7[x + SCRX_BIAS] == x/7 (усечение к нулю, как в C и как у 8086 idiv
* в оригинале); экранная X = x + SCRX7[...]. */
#define SCRX_BIAS 448
#define SCRX_N 1152
static const int16_t SCRX[SCRX_N] = {
-512, -510, -509, -508, -507, -506, -505, -504, -502, -501, -500, -499,
-498, -497, -496, -494, -493, -492, -491, -490, -489, -488, -486, -485,
-484, -483, -482, -481, -480, -478, -477, -476, -475, -474, -473, -472,
-470, -469, -468, -467, -466, -465, -464, -462, -461, -460, -459, -458,
-457, -456, -454, -453, -452, -451, -450, -449, -448, -446, -445, -444,
-443, -442, -441, -440, -438, -437, -436, -435, -434, -433, -432, -430,
-429, -428, -427, -426, -425, -424, -422, -421, -420, -419, -418, -417,
-416, -414, -413, -412, -411, -410, -409, -408, -406, -405, -404, -403,
-402, -401, -400, -398, -397, -396, -395, -394, -393, -392, -390, -389,
-388, -387, -386, -385, -384, -382, -381, -380, -379, -378, -377, -376,
-374, -373, -372, -371, -370, -369, -368, -366, -365, -364, -363, -362,
-361, -360, -358, -357, -356, -355, -354, -353, -352, -350, -349, -348,
-347, -346, -345, -344, -342, -341, -340, -339, -338, -337, -336, -334,
-333, -332, -331, -330, -329, -328, -326, -325, -324, -323, -322, -321,
-320, -318, -317, -316, -315, -314, -313, -312, -310, -309, -308, -307,
-306, -305, -304, -302, -301, -300, -299, -298, -297, -296, -294, -293,
-292, -291, -290, -289, -288, -286, -285, -284, -283, -282, -281, -280,
-278, -277, -276, -275, -274, -273, -272, -270, -269, -268, -267, -266,
-265, -264, -262, -261, -260, -259, -258, -257, -256, -254, -253, -252,
-251, -250, -249, -248, -246, -245, -244, -243, -242, -241, -240, -238,
-237, -236, -235, -234, -233, -232, -230, -229, -228, -227, -226, -225,
-224, -222, -221, -220, -219, -218, -217, -216, -214, -213, -212, -211,
-210, -209, -208, -206, -205, -204, -203, -202, -201, -200, -198, -197,
-196, -195, -194, -193, -192, -190, -189, -188, -187, -186, -185, -184,
-182, -181, -180, -179, -178, -177, -176, -174, -173, -172, -171, -170,
-169, -168, -166, -165, -164, -163, -162, -161, -160, -158, -157, -156,
-155, -154, -153, -152, -150, -149, -148, -147, -146, -145, -144, -142,
-141, -140, -139, -138, -137, -136, -134, -133, -132, -131, -130, -129,
-128, -126, -125, -124, -123, -122, -121, -120, -118, -117, -116, -115,
-114, -113, -112, -110, -109, -108, -107, -106, -105, -104, -102, -101,
-100, -99, -98, -97, -96, -94, -93, -92, -91, -90, -89, -88,
-86, -85, -84, -83, -82, -81, -80, -78, -77, -76, -75, -74,
-73, -72, -70, -69, -68, -67, -66, -65, -64, -62, -61, -60,
-59, -58, -57, -56, -54, -53, -52, -51, -50, -49, -48, -46,
-45, -44, -43, -42, -41, -40, -38, -37, -36, -35, -34, -33,
-32, -30, -29, -28, -27, -26, -25, -24, -22, -21, -20, -19,
-18, -17, -16, -14, -13, -12, -11, -10, -9, -8, -6, -5,
-4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8,
9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21,
22, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35,
36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 48, 49,
50, 51, 52, 53, 54, 56, 57, 58, 59, 60, 61, 62,
64, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76,
77, 78, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90,
91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 104,
105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117,
118, 120, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131,
132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 144, 145,
146, 147, 148, 149, 150, 152, 153, 154, 155, 156, 157, 158,
160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172,
173, 174, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186,
187, 188, 189, 190, 192, 193, 194, 195, 196, 197, 198, 200,
201, 202, 203, 204, 205, 206, 208, 209, 210, 211, 212, 213,
214, 216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227,
228, 229, 230, 232, 233, 234, 235, 236, 237, 238, 240, 241,
242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254,
256, 257, 258, 259, 260, 261, 262, 264, 265, 266, 267, 268,
269, 270, 272, 273, 274, 275, 276, 277, 278, 280, 281, 282,
283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 296,
297, 298, 299, 300, 301, 302, 304, 305, 306, 307, 308, 309,
310, 312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323,
324, 325, 326, 328, 329, 330, 331, 332, 333, 334, 336, 337,
338, 339, 340, 341, 342, 344, 345, 346, 347, 348, 349, 350,
352, 353, 354, 355, 356, 357, 358, 360, 361, 362, 363, 364,
365, 366, 368, 369, 370, 371, 372, 373, 374, 376, 377, 378,
379, 380, 381, 382, 384, 385, 386, 387, 388, 389, 390, 392,
393, 394, 395, 396, 397, 398, 400, 401, 402, 403, 404, 405,
406, 408, 409, 410, 411, 412, 413, 414, 416, 417, 418, 419,
420, 421, 422, 424, 425, 426, 427, 428, 429, 430, 432, 433,
434, 435, 436, 437, 438, 440, 441, 442, 443, 444, 445, 446,
448, 449, 450, 451, 452, 453, 454, 456, 457, 458, 459, 460,
461, 462, 464, 465, 466, 467, 468, 469, 470, 472, 473, 474,
475, 476, 477, 478, 480, 481, 482, 483, 484, 485, 486, 488,
489, 490, 491, 492, 493, 494, 496, 497, 498, 499, 500, 501,
502, 504, 505, 506, 507, 508, 509, 510, 512, 513, 514, 515,
516, 517, 518, 520, 521, 522, 523, 524, 525, 526, 528, 529,
530, 531, 532, 533, 534, 536, 537, 538, 539, 540, 541, 542,
544, 545, 546, 547, 548, 549, 550, 552, 553, 554, 555, 556,
557, 558, 560, 561, 562, 563, 564, 565, 566, 568, 569, 570,
571, 572, 573, 574, 576, 577, 578, 579, 580, 581, 582, 584,
585, 586, 587, 588, 589, 590, 592, 593, 594, 595, 596, 597,
598, 600, 601, 602, 603, 604, 605, 606, 608, 609, 610, 611,
612, 613, 614, 616, 617, 618, 619, 620, 621, 622, 624, 625,
626, 627, 628, 629, 630, 632, 633, 634, 635, 636, 637, 638,
640, 641, 642, 643, 644, 645, 646, 648, 649, 650, 651, 652,
653, 654, 656, 657, 658, 659, 660, 661, 662, 664, 665, 666,
667, 668, 669, 670, 672, 673, 674, 675, 676, 677, 678, 680,
681, 682, 683, 684, 685, 686, 688, 689, 690, 691, 692, 693,
694, 696, 697, 698, 699, 700, 701, 702, 704, 705, 706, 707,
708, 709, 710, 712, 713, 714, 715, 716, 717, 718, 720, 721,
722, 723, 724, 725, 726, 728, 729, 730, 731, 732, 733, 734,
736, 737, 738, 739, 740, 741, 742, 744, 745, 746, 747, 748,
749, 750, 752, 753, 754, 755, 756, 757, 758, 760, 761, 762,
763, 764, 765, 766, 768, 769, 770, 771, 772, 773, 774, 776,
777, 778, 779, 780, 781, 782, 784, 785, 786, 787, 788, 789,
790, 792, 793, 794, 795, 796, 797, 798, 800, 801, 802, 803,
static const int8_t SCRX7[SCRX_N] = {
-64, -63, -63, -63, -63, -63, -63, -63, -62, -62, -62, -62, -62, -62, -62, -61, -61, -61, -61, -61,
-61, -61, -60, -60, -60, -60, -60, -60, -60, -59, -59, -59, -59, -59, -59, -59, -58, -58, -58, -58,
-58, -58, -58, -57, -57, -57, -57, -57, -57, -57, -56, -56, -56, -56, -56, -56, -56, -55, -55, -55,
-55, -55, -55, -55, -54, -54, -54, -54, -54, -54, -54, -53, -53, -53, -53, -53, -53, -53, -52, -52,
-52, -52, -52, -52, -52, -51, -51, -51, -51, -51, -51, -51, -50, -50, -50, -50, -50, -50, -50, -49,
-49, -49, -49, -49, -49, -49, -48, -48, -48, -48, -48, -48, -48, -47, -47, -47, -47, -47, -47, -47,
-46, -46, -46, -46, -46, -46, -46, -45, -45, -45, -45, -45, -45, -45, -44, -44, -44, -44, -44, -44,
-44, -43, -43, -43, -43, -43, -43, -43, -42, -42, -42, -42, -42, -42, -42, -41, -41, -41, -41, -41,
-41, -41, -40, -40, -40, -40, -40, -40, -40, -39, -39, -39, -39, -39, -39, -39, -38, -38, -38, -38,
-38, -38, -38, -37, -37, -37, -37, -37, -37, -37, -36, -36, -36, -36, -36, -36, -36, -35, -35, -35,
-35, -35, -35, -35, -34, -34, -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -32, -32,
-32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -30, -30, -30, -30, -30, -30, -30, -29,
-29, -29, -29, -29, -29, -29, -28, -28, -28, -28, -28, -28, -28, -27, -27, -27, -27, -27, -27, -27,
-26, -26, -26, -26, -26, -26, -26, -25, -25, -25, -25, -25, -25, -25, -24, -24, -24, -24, -24, -24,
-24, -23, -23, -23, -23, -23, -23, -23, -22, -22, -22, -22, -22, -22, -22, -21, -21, -21, -21, -21,
-21, -21, -20, -20, -20, -20, -20, -20, -20, -19, -19, -19, -19, -19, -19, -19, -18, -18, -18, -18,
-18, -18, -18, -17, -17, -17, -17, -17, -17, -17, -16, -16, -16, -16, -16, -16, -16, -15, -15, -15,
-15, -15, -15, -15, -14, -14, -14, -14, -14, -14, -14, -13, -13, -13, -13, -13, -13, -13, -12, -12,
-12, -12, -12, -12, -12, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -9,
-9, -9, -9, -9, -9, -9, -8, -8, -8, -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -7,
-6, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -4, -4,
-4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1,
-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7,
7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10,
10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 13,
13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18,
18, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21,
21, 21, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24,
24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 30, 30,
30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 33,
33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35,
36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38,
38, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41,
41, 41, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44,
44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47,
47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 50, 50,
50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 53,
53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58,
58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61,
61, 61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64,
64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67,
67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 70, 70,
70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 73,
73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75,
76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78,
78, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81,
81, 81, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84,
84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87,
87, 87, 87, 87, 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 90, 90,
90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 93,
93, 93, 93, 93, 93, 93, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, 95,
96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98,
98, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100,
};
static int scr_x(int x)
@@ -245,7 +214,7 @@ static int scr_x(int x)
* индекса (memory sdcc_z80_const_ptr_index_bug), а тут индекс как раз
* больше 255. */
uint16_t i = (uint16_t)(x + SCRX_BIAS);
if (i < SCRX_N) return SCRX[i];
if (i < SCRX_N) return x + SCRX7[i];
return x * 8 / 7; /* по данным кадров недостижимо */
}
+12 -9
View File
@@ -72,20 +72,23 @@ TC_TEST(geom_y_to_row_matches_formula)
}
}
/* calc_screen_x_coord (seg008:2602) считается в pop_cdraw.c ГОТОВОЙ таблицей
* SCRX (банк 4, сюда не линкуется). Таблица сгенерирована питоном по правилу
* «усечение К НУЛЮ»: значение = знак(x) * (|x|*8 / 7). Проверяем ИМЕННО это
* правило на целевом компиляторе: если бы __divsint у SDCC округлял иначе
* (к минус бесконечности), вся отрицательная половина таблицы уехала бы на
* пиксель, а поймалось бы это только глазами на левой кромке комнаты. */
TC_TEST(geom_mul8div7_trunc_to_zero)
/* calc_screen_x_coord (seg008:2602) считается в pop_cdraw.c таблицей SCRX7
* (банк 4, сюда не линкуется): хранится x/7 байтом, результат = x + SCRX7[..].
* Таблица сгенерирована питоном, поэтому проверяем два правила, на которых
* держится генерация — ИМЕННО на целевом компиляторе:
* 1) тождество 8x/7 == x + x/7 (7x делится нацело);
* 2) усечение К НУЛЮ, а не к минус бесконечности.
* Округляй SDCC иначе — вся отрицательная половина уехала бы на пиксель, и
* поймалось бы это только глазами на левой кромке комнаты. */
TC_TEST(geom_mul8div7_table_rules)
{
int16_t x;
/* Полный диапазон 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);
TC_EQ((int16_t)(x * 8 / 7), want); /* усечение к нулю */
TC_EQ((int16_t)(x * 8 / 7), (int16_t)(x + x / 7)); /* тождество */
}
}
@@ -171,7 +174,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_trunc_to_zero);
TC_RUN(geom_mul8div7_table_rules);
#if POP_PRANDOM_EXACT
TC_RUN(geom_lcg_matches_reference);
TC_RUN(geom_lcg_seed_zero);