99b430f2ed
Ревью на 32-бит сделан ПО ASM, а не по коду (искали и безымянные
временные): во всём приложении был ровно ОДИН 32-битный вызов —
__mullong в pop_prandom. Замер в MAME: 8 430 тактов на вызов, два
вызова за кадр. Прочие библиотечные вызовы 16-битные (__divsint 16,
__modsint 12, __moduchar 8, __divuchar 5).
1. pop_prandom. Состояние 32-бит -> две 16-битные половины. Два
генератора, выбор через POP_PRANDOM_EXACT:
- 0 (по умолчанию) — xorshift16 + шаг Вейля, без единого умножения;
- 1 — LCG оригинала бит-в-бит, посчитанный половинами (для сверки
картинки с эталоном).
8-битный RND Apple II (5*x+23 mod 256) НЕ взят: у LCG по модулю 256
вырождены младшие биты (бит 0 просто чередуется), а раскладка кладки
берёт как раз prandom(1) и prandom(4) — вместо шума вышла бы
правильная шахматка. Шаг Вейля ещё и убирает ноль как неподвижную
точку xorshift (сид кладки вполне может быть нулём).
Бит-в-бит эквивалентность half-word версии проверена на хосте:
70 000 сидов x 8 шагов + 7 крайних сидов x 2000 шагов.
Остаток 0..maxv: делитель степень двойки — маска вместо __moduint.
2. libbgi: gfx_blit_cols_part_noclip — column-major блит без клипа
(пара к gfx_blit_cols_part, как gfx_blit_part_noclip к
gfx_blit_part). Клипающий вариант платит ~5 622 такта подготовки на
КАЖДЫЙ вызов независимо от того, вылезает край (замер: подготовка
5 622 против 13 596 на сам accel-проход). Kid, страж и клинок
выбирают путь по pop_onscreen_cols. size-check: роста нет.
Бюджет (175 кадров, комната 3, медиана):
было (после клинка) 416 154 0.968 кадра
стало 397 986 0.926 кадра
Разница между генераторами, замер на одинаковой сборке:
xorshift16 + Вейль 397 986 prandom->torch_draw 7 927
бит-в-бит LCG 403 632 prandom->torch_draw 10 933
то есть точность обходится в 5 646 тактов за кадр (1.3 %).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
57 lines
3.1 KiB
C
57 lines
3.1 KiB
C
/*
|
|
* pop_geom.h — общая геометрия PoP и PRNG оригинала.
|
|
*
|
|
* Сюда сведено то, что раньше дублировалось по модулям (x_bump/y_land в
|
|
* pop_kid и pop_map, y_to_row в pop_bg и pop_map, 32-битный LCG в pop_bg и
|
|
* pop_trob). Кроме экономии это ФУНДАМЕНТ bank-safe API: модуль живёт в
|
|
* W1/W2 и не трогает графику, поэтому его может звать и главный цикл, и
|
|
* резидент W3, и будущий __banked-код стражей (docs/layout_plan_v2.md §4).
|
|
*/
|
|
#ifndef POP_GEOM_H
|
|
#define POP_GEOM_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#define FIRST_ONSCREEN_COLUMN 5 /* индекс col 0 комнаты в x_bump */
|
|
#define TILE_SIZEX 14 /* ширина тайла в координатах персонажа */
|
|
#define TILE_SIZEY 63 /* высота ряда */
|
|
|
|
/* x_bump (data.h): левая граница колонки в координатах персонажа; колонка
|
|
* комнаты col = x_bump[col + FIRST_ONSCREEN_COLUMN]. y_land: пол ряда
|
|
* (индекс row+1; [0] — ряд «над комнатой»). */
|
|
extern const int16_t pop_x_bump[20];
|
|
extern const int16_t pop_y_land[5];
|
|
|
|
/* y_to_row_mod4 (seg006): ряд по координате y с оборотом mod 4 (−1 = полоса
|
|
* над комнатой, 3 = под комнатой). */
|
|
int8_t pop_y_to_row(int16_t y);
|
|
|
|
/* prandom (порт seg009:321). Сид ВНЕШНИЙ: у стен (раскладка кладки) и у
|
|
* анимаций тайлов (фаза факелов) свои последовательности, смешивать их
|
|
* нельзя.
|
|
*
|
|
* ДВА генератора, выбор через POP_PRANDOM_EXACT (см. pop_geom.c):
|
|
* 0 (по умолчанию) — xorshift16 + шаг Вейля. Быстрый: ни одного
|
|
* умножения. Последовательность ОТЛИЧАЕТСЯ от SDLPoP, то есть другая
|
|
* раскладка кладки и другие броски в боёвке — статистически
|
|
* эквивалентные, но не те же самые;
|
|
* 1 — LCG оригинала (s*214013+2531011) бит-в-бит. Для сверки картинки
|
|
* с эталоном. Дороже: даже посчитанный 16-битными половинами (без
|
|
* __mullong, который один стоил 8 430 тактов — замер в MAME) он
|
|
* обходится в ~7 000 тактов на вызов.
|
|
*
|
|
* Состояние — две 16-битные половины, а не unsigned long: иначе SDCC на
|
|
* умножении зовёт __mullong. */
|
|
typedef struct { uint16_t lo, hi; } pop_rnd_t;
|
|
|
|
#ifndef POP_PRANDOM_EXACT
|
|
#define POP_PRANDOM_EXACT 0
|
|
#endif
|
|
|
|
uint16_t pop_prandom(pop_rnd_t *seed, uint16_t maxv);
|
|
|
|
/* Сид из 16-битного числа (старшая половина = 0). */
|
|
#define pop_prandom_set(s, v) do { (s).lo = (uint16_t)(v); (s).hi = 0; } while (0)
|
|
|
|
#endif
|