PoP roomtest: pop_bg и pop_map в банки; --dataseg BANKn стал опцией
Резидента --w3 больше нет: отрисовка (pop_bg + pop_gdraw) уехала в БАНК 2, физика/коллизия (pop_map) — в БАНК 3. Куча W1/W2 1294 -> 6750 Б. Что это разблокировало. Резидент был тупиком: из банка он недостижим ни прямо, ни транзитивно, поэтому pop_map (самый крупный модуль, 5.8 КБ) в банк было не увести — он зовёт mob-отрисовку. Проверено, что банк->банк РАБОТАЕТ: ___sdcc_bcall_ehl читает страницу окна портом 0xE2 и кладёт её на СТЕК своего кадра (runtime/bank.s), поэтому вложенность корректна по построению. Подтверждено в MAME цепочкой W1 -> банк1 -> банк2 -> банк1: nested=124 after=8, ровно ожидаемое. Значит развязка mob'а (самое рисковое место, loose-полы) НЕ понадобилась — pop_map зовёт pop_bg трамплином. Правила вызовов проверены на сгенерированном asm и записаны в memory sdcc_banked_call_rules: трамплин выбирает ОБЪЯВЛЕНИЕ (__banked), а не раскладка — даже внутри одного .c между __banked функциями он есть. Внутрибанковые функции оставлены непомеченными и зовутся напрямую, в т.ч. через границу файла (pop_gdraw -> pop_fore_over_char). sprinter-cc: --dataseg BANKn БОЛЬШЕ НЕ ставится по умолчанию. Раньше вся писучая память банкового модуля уезжала в страницу банка и снаружи не читалась (проверено на .map: глобал лёг по 0x0001C000) — грабли на каждом переносе. Теперь данные банков по умолчанию в общем _DATA (W1/W2, замаплен всегда), а прежнее поведение — по явному --bank-data. Замеры (комната 3, Kid + страж; кадр Sprinter в турбо = 430 000 тактов): до переноса 338 508 (0.79 кадра) + pop_bg в банк 2 347 100 (+2.5 %) + pop_map в банк 3 371 100 (+9.6 % к исходному, 0.86 кадра) Плата — трамплины (~654 такта на вызов, ~30 вызовов за кадр). При пейсинге в 3 кадра это 29 % логического кадра, но запас до ОДНОГО кадра всего ~59 000 тактов — под звук его надо возвращать (следующий шаг: батчить кроссбанковые вызовы, начиная с pop_redraw_needed). Профилирование бордюром включено по умолчанию (make PROF=0 выключает) и переведено на реально работающие биты: бит 0 (красный) у бордюра Sprinter ИГНОРИРУЕТСЯ, поэтому различимых состояний четыре и значения обязаны быть чётными — 0 чёрный (ждём vsync), 2 синий (логика), 4 зелёный (фон), 6 циан (спрайты). Раньше нечётные номера сливались и полосы не читались. Проверено в MAME: комнаты 1/3 рисуются как прежде, бег и коллизия работают, в комнате 12 плиты проваливаются со щебнем — то есть цепочка loose банк3 -> банк2 живая. Полосы бордюра в комнате 3: логика 73 строки, фон 64, спрайты 128, свободно 23. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "pop_bg.h"
|
||||
#include "pop_state.h"
|
||||
#include "pop_geom.h"
|
||||
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
||||
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев (см. ниже) */
|
||||
@@ -32,7 +33,7 @@ static const char *const ENV_ATL[5] = {
|
||||
"BG\\pop_env3.atl", "BG\\pop_env4.atl"
|
||||
};
|
||||
|
||||
int pop_bg_load(void)
|
||||
int pop_bg_load(void) __banked
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
@@ -43,7 +44,7 @@ int pop_bg_load(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pop_bg_free(void)
|
||||
void pop_bg_free(void) __banked
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
@@ -76,7 +77,7 @@ static int g_clip_top;
|
||||
static int fclip_x0, fclip_y0, fclip_x1, fclip_y1;
|
||||
static uint8_t fclip_on;
|
||||
|
||||
void pop_fore_set_clip(int x, int y, int w, int h)
|
||||
void pop_fore_set_clip(int x, int y, int w, int h) __banked
|
||||
{
|
||||
fclip_x0 = x; fclip_y0 = y;
|
||||
fclip_x1 = x + w; fclip_y1 = y + h;
|
||||
@@ -169,7 +170,7 @@ static void ov_mark(int x, int y, int w, int h)
|
||||
ov_pending = 3; /* обе страницы */
|
||||
}
|
||||
|
||||
void pop_fore_heal(void)
|
||||
void pop_fore_heal(void) __banked
|
||||
{
|
||||
uint8_t pg = gfx_get_draw_page() & 1;
|
||||
if (!(ov_pending & (1 << pg))) return;
|
||||
@@ -293,12 +294,12 @@ static uint8_t g_room;
|
||||
* floorright, когда тайл нижнего ряда стал видимым (empty после падения
|
||||
* loose): «стена вниз» = топрайт тайла room_B(0, col-1). 0 — нет комнаты
|
||||
* снизу (кромка уровня = стена). */
|
||||
void pop_room_set_below(const uint8_t *below_row0_fg) { g_below = below_row0_fg; }
|
||||
void pop_room_set_below(const uint8_t *below_row0_fg) __banked { g_below = below_row0_fg; }
|
||||
|
||||
/* Задать ряд 2 (fg-коды + модификаторы) комнаты СВЕРХУ — для полосы кладки
|
||||
* у потолка (seg008 draw_room: доп. верхний ряд из room_A, draw_tile_aboveroom
|
||||
* при draw_main_y=-1). 0 — нет комнаты сверху (кромка уровня → пол). */
|
||||
void pop_room_set_above(const uint8_t *above_row2_fg, const uint8_t *above_row2_mod)
|
||||
void pop_room_set_above(const uint8_t *above_row2_fg, const uint8_t *above_row2_mod) __banked
|
||||
{ g_above = above_row2_fg; g_abovemod = above_row2_mod; }
|
||||
|
||||
static uint8_t tile_code(int row, int col)
|
||||
@@ -746,7 +747,7 @@ static void draw_tile(int row, int col)
|
||||
* Порт SDLPoP redraw_tile_height: каждый кадр анимации перерисовать
|
||||
* ПОЛНОСТЬЮ и loose-тайл, и ПРАВЫЙ СОСЕД (грани loose анимируются по modif
|
||||
* внутри draw_tile). */
|
||||
void pop_loose_shake_draw(int row, int col)
|
||||
void pop_loose_shake_draw(int row, int col) __banked
|
||||
{
|
||||
int x = COL_XH[col] * 8;
|
||||
/* heal возвращает печёный фон обоих тайлов из ОЗУ-копии, поверх —
|
||||
@@ -768,7 +769,7 @@ void pop_loose_shake_draw(int row, int col)
|
||||
* читает lmod = g_bg[row*10+col] = живой modif пики). g_bg должен указывать
|
||||
* на room_modif (enter_room передаёт его как bg). Порт redraw_21h/draw_tile.
|
||||
* heal берёт печёный статич. фон, поверх — динамич. кадр (шипы над полом). */
|
||||
void pop_spike_redraw(int row, int col)
|
||||
void pop_spike_redraw(int row, int col) __banked
|
||||
{
|
||||
int x = COL_XH[col] * 8;
|
||||
/* Порт redraw_21h -> redraw_tile_height (seg007:0218): wipe + ПОЛНЫЙ
|
||||
@@ -795,7 +796,7 @@ void pop_spike_redraw(int row, int col)
|
||||
* room_modif соседа перед вызовом). Bar-в-чёрный + redraw (как loose bake):
|
||||
* heal вернул бы ЗАПЕЧЁННОЕ состояние ворот → при открытии нижние бары
|
||||
* оставались бы; чёрная плита стирает старые бары в VRAM+ОЗУ-копию. */
|
||||
void pop_room_redraw_seam_left(void)
|
||||
void pop_room_redraw_seam_left(void) __banked
|
||||
{
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
setfillstyle(SOLID_FILL, BLACK);
|
||||
@@ -817,7 +818,7 @@ void pop_room_redraw_seam_left(void)
|
||||
* после провала (NORMAL, в ОЗУ-копию, чтобы heal её сохранял). */
|
||||
#define CEIL_BAND_H 8 /* видимая высота полосы (room-space y 0..7) */
|
||||
|
||||
void pop_ceil_shake_draw(int col)
|
||||
void pop_ceil_shake_draw(int col) __banked
|
||||
{
|
||||
int x = COL_XH[col] * 8;
|
||||
heal_off(x, 0, 64, CEIL_BAND_H); /* фон полосы обоих тайлов */
|
||||
@@ -829,7 +830,7 @@ void pop_ceil_shake_draw(int col)
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
}
|
||||
|
||||
void pop_ceil_bake_empty(int col)
|
||||
void pop_ceil_bake_empty(int col) __banked
|
||||
{
|
||||
int x = COL_XH[col] * 8;
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
@@ -852,7 +853,7 @@ void pop_ceil_bake_empty(int col)
|
||||
* draw_main_y − 40). Зелье: маска (23, «прорезает» фон) + кадр пузырька
|
||||
* potion_fram_bubb[modif & 7] на xh+3/xl=1, ybottom = draw_main_y −
|
||||
* (pot_size<<2) − 14 (seg008:668). */
|
||||
void pop_torch_draw(int row, int col, uint8_t modif)
|
||||
void pop_torch_draw(int row, int col, uint8_t modif) __banked
|
||||
{
|
||||
/* Пламя рисует ПРАВЫЙ сосед со своим draw_xh: xh = COL_XH[col+1] + 1
|
||||
* (seg008:560), т.е. x = (col+1)*32 + 8 — как и основание факела (env
|
||||
@@ -869,7 +870,7 @@ void pop_torch_draw(int row, int col, uint8_t modif)
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
}
|
||||
|
||||
void pop_potion_draw(int row, int col, uint8_t modif)
|
||||
void pop_potion_draw(int row, int col, uint8_t modif) __banked
|
||||
{
|
||||
uint8_t type = potion_type(modif);
|
||||
int pot_size = (type >= 2 && type < 5) ? 1 : 0;
|
||||
@@ -887,7 +888,7 @@ void pop_potion_draw(int row, int col, uint8_t modif)
|
||||
* (draw_tile подставляет пол/stuck по таймеру связи). Bar-в-чёрный +
|
||||
* redraw — иначе «шишка» отжатой кнопки (base 147) осталась бы при переходе
|
||||
* в пол. Звать из pop_process_trobs для кнопок текущей комнаты. */
|
||||
void pop_floor_bake(int row, int col)
|
||||
void pop_floor_bake(int row, int col) __banked
|
||||
{
|
||||
int x = COL_XH[col] * 8;
|
||||
int yb = POP_YOFF + 63 * row;
|
||||
@@ -905,13 +906,13 @@ void pop_floor_bake(int row, int col)
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
}
|
||||
|
||||
void pop_button_redraw(int row, int col) { pop_floor_bake(row, col); }
|
||||
void pop_button_redraw(int row, int col) __banked { pop_floor_bake(row, col); }
|
||||
|
||||
/* Перерисовать ПРАВУЮ половину двери уровня (в её ячейке рисуется створка,
|
||||
* см. draw_leveldoor) на back-странице С ЗАПЕЧКОЙ в ОЗУ-копию: створка едет,
|
||||
* а heal обязан возвращать её ТЕКУЩЕЕ положение, а не запечённое закрытое.
|
||||
* Куски двери непрозрачные — wipe не нужен. */
|
||||
void pop_leveldoor_redraw(int row, int col)
|
||||
void pop_leveldoor_redraw(int row, int col) __banked
|
||||
{
|
||||
gfx_set_bank(GFX_BANK_TRANSPARENT);
|
||||
draw_tile(row, col);
|
||||
@@ -924,7 +925,7 @@ void pop_leveldoor_redraw(int row, int col)
|
||||
* рисовал loose-правый-край env_b(42); теперь пусто → чистая грань).
|
||||
* g_fg[pos] уже = 0 (pop_map). Чёрная плита (NORMAL) стирает старые
|
||||
* пиксели пола в видео-ОЗУ + ОЗУ-копию, поверх — новый статич. фон. */
|
||||
void pop_loose_bake_empty(int row, int col)
|
||||
void pop_loose_bake_empty(int row, int col) __banked
|
||||
{
|
||||
int x = COL_XH[col] * 8;
|
||||
int xr = COL_XH[col + 1] * 8;
|
||||
@@ -987,7 +988,8 @@ static mob_t mobs[MOB_MAX];
|
||||
|
||||
/* Кусок «приземлился» (порт loose_land): 0 = нет, иначе tilepos+1 тайла, на
|
||||
* который он лёг → приложение/pop_map ставит debris + do_knock. */
|
||||
uint8_t pop_loose_landed;
|
||||
/* pop_loose_landed переехал в pop_state.c: его читает pop_map (W1/W2), а
|
||||
* писучие данные банкового модуля недоступны снаружи (см. pop_state.h). */
|
||||
|
||||
/* y_loose_land / y_something (seg007): [row+1], row = −1..3. Ряд −1 —
|
||||
* плита-потолок (ряд 2 комнаты сверху): в оригинале это отрицательный
|
||||
@@ -996,7 +998,7 @@ static const int16_t MOB_Y_LAND[5] = {2, 65, 128, 191, 254};
|
||||
static const int16_t MOB_Y_BOUND[5] = {-1, 62, 125, 188, 25};
|
||||
#define MOB_Y_NONE 0x7FFF
|
||||
|
||||
void pop_loose_mob_spawn(int row, int col)
|
||||
void pop_loose_mob_spawn(int row, int col) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
mob_t *m = 0;
|
||||
@@ -1033,7 +1035,7 @@ static int8_t obj_col, obj_row;
|
||||
|
||||
static void mob_render(mob_t *m, uint8_t pg);
|
||||
|
||||
void pop_loose_mob_reset(void)
|
||||
void pop_loose_mob_reset(void) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < MOB_MAX; i++) {
|
||||
@@ -1098,7 +1100,7 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
||||
mob_render(m, pg);
|
||||
}
|
||||
|
||||
void pop_loose_mob_tick(void)
|
||||
void pop_loose_mob_tick(void) __banked
|
||||
{
|
||||
uint8_t pg = gfx_get_draw_page() & 1, i;
|
||||
for (i = 0; i < MOB_MAX; i++)
|
||||
@@ -1148,7 +1150,7 @@ static void mob_render(mob_t *m, uint8_t pg)
|
||||
|
||||
/* Отложенная отрисовка куска ПОВЕРХ Kid (он ниже Kid по obj_y). Звать
|
||||
* после kid_draw, до fore-слоя. */
|
||||
void pop_loose_mob_draw_over(void)
|
||||
void pop_loose_mob_draw_over(void) __banked
|
||||
{
|
||||
uint8_t pg = gfx_get_draw_page() & 1, i;
|
||||
for (i = 0; i < MOB_MAX; i++)
|
||||
@@ -1157,7 +1159,7 @@ void pop_loose_mob_draw_over(void)
|
||||
|
||||
/* Позиция падающего куска для check_loose_fall_on_kid (pop_map): колонка и
|
||||
* y (низ куска). 0 — куска нет. */
|
||||
uint8_t pop_loose_mob_pos(int *col, int *y)
|
||||
uint8_t pop_loose_mob_pos(int *col, int *y) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < MOB_MAX; i++)
|
||||
@@ -1172,7 +1174,7 @@ uint8_t pop_loose_mob_pos(int *col, int *y)
|
||||
* кадрах падения — гейт по флагу). */
|
||||
static uint8_t border_dirty;
|
||||
|
||||
void pop_clip_sprite(int x, int w, int sy_top, int h)
|
||||
void pop_clip_sprite(int x, int w, int sy_top, int h) __banked
|
||||
{
|
||||
int sy_bot = sy_top + h;
|
||||
(void)x; (void)w;
|
||||
@@ -1184,7 +1186,7 @@ void pop_clip_sprite(int x, int w, int sy_top, int h)
|
||||
* вышел за поле в последние 2 кадра) — иначе ноль стоимости. Возвращает
|
||||
* чёрный из ОЗУ-копии (вне поля она чёрная) в верхний борт и статус-полосу
|
||||
* + нижний борт. Звать КАЖДЫЙ кадр ПОСЛЕ всей отрисовки спрайтов. */
|
||||
void pop_room_clip_borders(void)
|
||||
void pop_room_clip_borders(void) __banked
|
||||
{
|
||||
if (!border_dirty) return;
|
||||
border_dirty--;
|
||||
@@ -1194,7 +1196,7 @@ void pop_room_clip_borders(void)
|
||||
|
||||
void pop_room_draw(uint8_t room_num,
|
||||
const uint8_t *fg, const uint8_t *bg,
|
||||
const uint8_t *lcol_fg, const uint8_t *lcol_bg)
|
||||
const uint8_t *lcol_fg, const uint8_t *lcol_bg) __banked
|
||||
{
|
||||
int row, col;
|
||||
g_room = room_num;
|
||||
@@ -1502,7 +1504,7 @@ static void char_footprint(int obj_x, int obj_y, uint16_t w, uint16_t h,
|
||||
}
|
||||
|
||||
void pop_fore_over_kid(int obj_x, int obj_y, uint16_t w, uint16_t h,
|
||||
int8_t dir, uint8_t frame, uint8_t action)
|
||||
int8_t dir, uint8_t frame, uint8_t action) __banked
|
||||
{
|
||||
int8_t cL, cR, cLraw, rT, rB, rTraw, r, c;
|
||||
fclip_on = 1; /* окно = прямоугольник спрайта */
|
||||
|
||||
Reference in New Issue
Block a user