Compare commits
3 Commits
ecf5ecfc14
...
18f5115e0d
| Author | SHA1 | Date | |
|---|---|---|---|
| 18f5115e0d | |||
| b3bf2cca3d | |||
| 3b2dd8bfcc |
@@ -11,6 +11,73 @@
|
||||
|
||||
---
|
||||
|
||||
## СТАТУС ВЫПОЛНЕНИЯ (обновлено 2026-07-29, коммит ecf5ecf)
|
||||
|
||||
| Шаг | Статус | Факт |
|
||||
|-----|--------|------|
|
||||
| 1. `kid_data.h` → EMM-страница + `load_frame`/`cur_frame` | **сделан** | `_CODE` −3 247 Б; попутно найден и обойдён баг кодогенерации SDCC (см. ниже) |
|
||||
| 2. `pop_geom.c` (дедуп геометрии + PRNG) | **сделан** | −41 Б `_CODE`, −11 Б W3; ценность — не байты, а bank-safe слой |
|
||||
| 3. `pop_map` без вызовов графики | **сделан** (фазы 1a/1b) | через пометки перерисовки, см. ниже |
|
||||
| 4. Разгрузка/перебалансировка W3 | **сделан** | в резиденте остался ТОЛЬКО `pop_bg`; W3 14 376 → 11 632 (свободно 4 752 Б) |
|
||||
| 5. Данные (`room_modif`, `dl1/dl2`, `_kbdraw_down`) | не начат | потенциал ~1.5 КБ |
|
||||
| 6. Контракт банка стражей + пробник | **пробник сделан** | `tests/w3bankgfx` — модель подтверждена в MAME, см. ниже |
|
||||
| 7. Дедуп семейства `draw_tile` | отложен по решению пользователя | «мороки много, выгода не так велика» |
|
||||
|
||||
**Замер сейчас против замера §1:** `_CODE` 24 881 → 24 421, куча W2 2 076 → 2 592 Б,
|
||||
W3-резидент 14 376 → 11 632 (свободно 2 008 → 4 752 Б). Сумма кода упала
|
||||
на ~3.2 КБ (данные Kid уехали в EMM), остальное — перераспределение.
|
||||
|
||||
### Что сделано вместо §5.3 (вынос loose в W3)
|
||||
|
||||
Вместо переноса кода между окнами выбран (по обсуждению с пользователем)
|
||||
**порт архитектуры оригинала**: логика ставит пометку, отрисовка идёт
|
||||
отдельным проходом — `set_redraw_*` (seg007) + `redraw_needed` (seg008:0178).
|
||||
Появился `pop_redraw.c/.h`; `pop_trob` и `pop_map` больше не рисуют тайлы.
|
||||
Наши самодельные счётчики (`spike_rest`, `button_rest`, `ldoor_rest`,
|
||||
`loose_bake`, `loose_rest`, `ceil_rest`, `ceil_bake`, `land_bake`) удалены —
|
||||
их роль (вторая страница дабл-буфера) взял счётчик страниц в пометке.
|
||||
|
||||
**Два исключения остались** (обе — функции ТОЛЬКО главного цикла, звать из
|
||||
банка нельзя):
|
||||
- `pop_process_trobs` — пламя факела и пузырёк зелья (покадровый оверлей);
|
||||
- `pop_loose_tick` — падающий кусок (mob): spawn/tick/pos. В оригинале это
|
||||
отдельная подсистема (`mobs` + `draw_moving`), разделение на логику и
|
||||
отрисовку — задел следующей фазы.
|
||||
|
||||
### Пробник банка (2026-07-29): модель ПОДТВЕРЖДЕНА
|
||||
|
||||
`tests/w3bankgfx` (huge + `--w3 res.c` + `--bank 1=bank1.c`, графика 256):
|
||||
|
||||
- банк рисует примитивом libbgi НАПРЯМУЮ — работает; страница W3 внутри
|
||||
банка до блита, после блита и после возврата из вызванной им W1/W2-функции
|
||||
одна и та же (0xF0), резидент — 0xF3. То есть `_bgi_begin`/`_bgi_end`
|
||||
корректно возвращают ИМЕННО банковую страницу (правило R4);
|
||||
- вызов W1/W2-функции из банка работает, и она тоже может рисовать;
|
||||
- резидент W3 жив и вызывается после возврата из банка (R3).
|
||||
|
||||
**Дополнительно выяснено (важно для стражей):** писучие статики
|
||||
`__banked`-модуля линкуются В СТРАНИЦУ БАНКА (0x1C000+) — снаружи их не
|
||||
прочитать, из W1/W2 по 0xC000 видна резидентная страница. Значит всё
|
||||
состояние банкованного кода (позиции стражей, таймеры боя) обязано жить в
|
||||
W1/W2 как обычные глобалы, а банк — только код.
|
||||
|
||||
Ещё одна мина, найденная там же: инлайновый `in a,(#0xE2)` посреди тела
|
||||
функции затирает A, куда SDCC уже положил параметр (у нас из-за этого цвет
|
||||
заливки стал номером страницы, и «резидент не рисовал»). Читать порт
|
||||
отдельной `__naked`-функцией.
|
||||
|
||||
### Найденная по дороге ловушка компилятора
|
||||
|
||||
`(const T *)КОНСТАНТА + var*K` SDCC 4.5 может собрать неверно: умножение
|
||||
делает в 16 битах, а потом берёт только младший байт (`ld c,l` / `inc b`).
|
||||
Кадры Kid с индексом ≥ 52 читались из чужой строки таблицы, у бега/шага
|
||||
пропадал `FRAME_NEEDS_FLOOR` и персонаж проваливался сквозь пол. Лечение —
|
||||
считать адрес в `uint16_t` и кастовать один раз. Тот же паттерн в
|
||||
`pop_level.c` компилируется ПРАВИЛЬНО, т.е. полагаться на «у соседа
|
||||
работает» нельзя. Подробности: memory `sdcc_z80_const_ptr_index_bug`.
|
||||
|
||||
---
|
||||
|
||||
## 0. Что уже сделано из v1 (не повторять)
|
||||
|
||||
- `--opt-code-size` и `--max-allocs 100000` **уже включены по умолчанию** в
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# w3bankgfx — пробник модели «huge + резидент W3 + банк W3 + графика».
|
||||
#
|
||||
# Проверяем ровно то, на чём стоит план раскладки PoP (docs/layout_plan_v2.md):
|
||||
# R2 из __banked-кода резидентная страница W3 недостижима (НЕ зовём);
|
||||
# R3 резидент -> банк работает через трамплин;
|
||||
# R4 примитивы libbgi можно звать ИЗ БАНКА: _bgi_begin запоминает текущую
|
||||
# страницу W3 (порт 0xE2) и _bgi_end её возвращает — значит банк
|
||||
# переживает рисование и продолжает исполняться.
|
||||
#
|
||||
# Раскладка huge: CODE 0x4100 (W1), DATA 0x8000 (W2), банк 0x1C000 (W3),
|
||||
# резидент --w3 делит W3 с банком (crt0 запоминает резидентную страницу).
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := w3bgfx
|
||||
MEMORY := huge
|
||||
EXTRA_FLAGS := --gfx 256 --w3 res.c --bank 1=bank1.c
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
|
||||
# Ожидаемый результат (проверено 2026-07-29, MAME dev):
|
||||
# пять полос сверху вниз: синяя (резидент), бирюзовая (банк рисует сам),
|
||||
# жёлтая (W1/W2-функция, вызванная из банка), ЗЕЛЁНАЯ (все проверки ок),
|
||||
# синяя (резидент жив после возврата). Красная вместо зелёной = модель
|
||||
# не подтвердилась. Диагностика в переменных bank_page_*/home_page_seen/
|
||||
# res_page_seen: банк 0xF0, резидент 0xF3, страница W3 внутри банка не
|
||||
# менялась вокруг рисования.
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* bank1.c — __banked модуль (страница W3 подменяется трамплином на время
|
||||
* вызова). Задача: проверить, что ИЗ БАНКА можно рисовать примитивами
|
||||
* libbgi и звать функции W1/W2, и что после этого банк ЖИВ (его страница
|
||||
* вернулась в W3).
|
||||
*
|
||||
* Резидент (res_draw) отсюда НЕ зовём сознательно: пока исполняется банк,
|
||||
* резидентной страницы в адресном пространстве нет (правило R2).
|
||||
*/
|
||||
#include <graphics.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t home_helper(uint8_t x); /* функция в W1/W2 (рисует сама) */
|
||||
|
||||
/* ВАЖНО: писучие статики __banked-модуля линкуются В СТРАНИЦУ БАНКА
|
||||
* (адрес 0x1C000+), поэтому снаружи их не прочитать — из W1/W2 по 0xC000
|
||||
* видна РЕЗИДЕНТНАЯ страница. Состояние банка держим в главном модуле. */
|
||||
extern uint8_t bank_page_before, bank_page_after, bank_page_after_home;
|
||||
extern uint8_t bank_alive;
|
||||
|
||||
/* Текущая страница W3 (порт 0xE2). ОТДЕЛЬНОЙ __naked-функцией: инлайновый
|
||||
* `in a,(0xE2)` посреди тела затирает A, куда SDCC уже положил параметр —
|
||||
* в первой версии пробника из-за этого цвет заливки становился номером
|
||||
* страницы (0xF3 = чёрный), и «резидент не рисовал». */
|
||||
static uint8_t w3_page(void) __naked
|
||||
{
|
||||
__asm__("in a, (#0xE2)\n\tret");
|
||||
}
|
||||
|
||||
uint8_t bank_run(uint8_t arg) __banked
|
||||
{
|
||||
uint8_t r;
|
||||
bank_page_before = w3_page();
|
||||
|
||||
/* 1) прямое рисование примитивом libbgi (он живёт в W1/W2 и сам
|
||||
* открывает/закрывает W3-скобку) */
|
||||
setfillstyle(SOLID_FILL, CYAN);
|
||||
bar(70, 40, 120, 52);
|
||||
bank_page_after = w3_page();
|
||||
|
||||
/* 2) вызов функции W1/W2, которая тоже рисует */
|
||||
r = home_helper(arg);
|
||||
bank_page_after_home = w3_page();
|
||||
|
||||
/* 3) банк ещё исполняется — значит его страница на месте */
|
||||
bank_alive = 1;
|
||||
return (uint8_t)(r + 1);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* res.c — РЕЗИДЕНТНЫЙ модуль окна W3 (--w3): лежит на 0xC000 и вызывается
|
||||
* напрямую из W1/W2. Рисует через готовые примитивы libbgi — это законно:
|
||||
* скобку _bgi_begin/_bgi_end они открывают внутри себя (сам W3-код открывать
|
||||
* её НЕ имеет права, иначе исполняемая страница подменяется видеобанком).
|
||||
*/
|
||||
#include <graphics.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t res_page_seen; /* какая страница была в W3 во время вызова */
|
||||
|
||||
/* Текущая страница W3 (порт 0xE2). ОТДЕЛЬНОЙ __naked-функцией: инлайновый
|
||||
* `in a,(0xE2)` посреди тела затирает A, куда SDCC уже положил параметр —
|
||||
* в первой версии пробника из-за этого цвет заливки становился номером
|
||||
* страницы (0xF3 = чёрный), и «резидент не рисовал». */
|
||||
static uint8_t w3_page(void) __naked
|
||||
{
|
||||
__asm__("in a, (#0xE2)\n\tret");
|
||||
}
|
||||
|
||||
|
||||
void res_draw(int y, int color)
|
||||
{
|
||||
res_page_seen = w3_page();
|
||||
setfillstyle(SOLID_FILL, color);
|
||||
bar(10, y, 60, y + 12);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* w3bankgfx — пробник раскладки «huge + резидент W3 + банк W3 + графика».
|
||||
* См. Makefile: проверяются правила R2/R3/R4 из
|
||||
* applications/PoP/docs/layout_plan_v2.md §2.
|
||||
*
|
||||
* Итог рисуется полосами, чтобы читалось и глазом, и скриптом по VRAM:
|
||||
* y=20 синяя — рисовал РЕЗИДЕНТ W3 (до банка)
|
||||
* y=40 бирюз. — рисовал БАНК напрямую примитивом libbgi
|
||||
* y=60 жёлтая — рисовала функция W1/W2, вызванная ИЗ БАНКА
|
||||
* y=80 зелёная — все проверки прошли (иначе КРАСНАЯ)
|
||||
* y=100 синяя — резидент W3 жив ПОСЛЕ возврата из банка
|
||||
*/
|
||||
#include <graphics.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sprinter.h>
|
||||
|
||||
const uint8_t n_banks = 1; /* читает crt0_banked */
|
||||
|
||||
extern uint8_t res_page_seen;
|
||||
uint8_t bank_page_before, bank_page_after, bank_page_after_home, bank_alive;
|
||||
extern uint8_t bank_pages[];
|
||||
|
||||
void res_draw(int y, int color); /* резидент W3 (прямой вызов) */
|
||||
uint8_t bank_run(uint8_t arg) __banked; /* банк (через трамплин) */
|
||||
|
||||
uint8_t home_page_seen;
|
||||
|
||||
/* Текущая страница W3 (порт 0xE2). ОТДЕЛЬНОЙ __naked-функцией: инлайновый
|
||||
* `in a,(0xE2)` посреди тела затирает A, куда SDCC уже положил параметр —
|
||||
* в первой версии пробника из-за этого цвет заливки становился номером
|
||||
* страницы (0xF3 = чёрный), и «резидент не рисовал». */
|
||||
static uint8_t w3_page(void) __naked
|
||||
{
|
||||
__asm__("in a, (#0xE2)\n\tret");
|
||||
}
|
||||
|
||||
|
||||
/* Функция W1/W2, которую зовёт БАНК. Рисует — то есть внутри неё libbgi
|
||||
* подменит W3 на видеобанк и вернёт обратно страницу БАНКА, а не резидента. */
|
||||
uint8_t home_helper(uint8_t x)
|
||||
{
|
||||
home_page_seen = w3_page();
|
||||
setfillstyle(SOLID_FILL, YELLOW);
|
||||
bar(130, 60, 180, 72);
|
||||
return (uint8_t)(x * 2);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint8_t ret, ok;
|
||||
uint8_t res_page, bank_page;
|
||||
|
||||
initgraph();
|
||||
setfillstyle(SOLID_FILL, BLACK);
|
||||
bar(0, 0, 319, 255);
|
||||
|
||||
res_draw(20, BLUE); /* R3-часть: W1/W2 -> резидент W3 */
|
||||
res_page = res_page_seen;
|
||||
|
||||
ret = bank_run(21); /* R3: резидент/HOME -> банк */
|
||||
bank_page = bank_page_before;
|
||||
|
||||
/* Критерии: банк дожил до конца, вернул r+1 = 21*2+1 = 43, страница W3
|
||||
* ВНУТРИ банка не менялась вокруг рисования (её вернули), и она НЕ равна
|
||||
* резидентной. */
|
||||
ok = (uint8_t)(bank_alive == 1 && ret == 43 &&
|
||||
bank_page_after == bank_page &&
|
||||
bank_page_after_home == bank_page &&
|
||||
home_page_seen == bank_page &&
|
||||
bank_page != res_page);
|
||||
|
||||
setfillstyle(SOLID_FILL, ok ? GREEN : RED); /* зелёная / красная */
|
||||
bar(10, 80, 60, 92);
|
||||
|
||||
res_draw(100, BLUE); /* резидент жив после возврата? */
|
||||
|
||||
printf("res_page=%02X bank_page=%02X after=%02X afterhome=%02X home=%02X ret=%u alive=%u ok=%u\n",
|
||||
res_page, bank_page, bank_page_after, bank_page_after_home,
|
||||
home_page_seen, ret, bank_alive, ok);
|
||||
printf("bank_pages[1]=%02X\n", bank_pages[1]);
|
||||
|
||||
while (1) { } /* держим картинку для скрипта */
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user