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:
@@ -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 к минус бесконечности, вся
|
||||
отрицательная половина уехала бы на пиксель, и поймалось бы это только
|
||||
глазами на левой кромке.
|
||||
|
||||
Оставлено сознательно (НЕ трогать, это не забытые места):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user