From b3bf2cca3d99eb37e8a1a235a633363d6d94ed30 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 29 Jul 2026 21:18:27 +0300 Subject: [PATCH] =?UTF-8?q?tests/w3bankgfx:=20=D0=BF=D1=80=D0=BE=D0=B1?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20?= =?UTF-8?q?=C2=ABhuge=20+=20=D1=80=D0=B5=D0=B7=D0=B8=D0=B4=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=20W3=20+=20=D0=B1=D0=B0=D0=BD=D0=BA=20W3=20+=20=D0=B3?= =?UTF-8?q?=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B0=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проверяет то, на чём стоит план раскладки PoP (layout_plan_v2.md §2): R3 резидент/HOME -> __banked через трамплин работает; R4 примитивы libbgi можно звать ИЗ БАНКА: _bgi_begin запоминает текущую страницу W3 (порт 0xE2), _bgi_end её возвращает — банк переживает рисование и продолжает исполняться; то же верно для функции W1/W2, вызванной из банка: она рисует, а в W3 остаётся страница БАНКА, не резидента. Результат в MAME: все пять полос на месте, вердикт ЗЕЛЁНЫЙ. Замеры: страница банка 0xF0 до рисования, после прямого блита и после возврата из W1/W2-функции — та же 0xF0; резидент 0xF3; банк дожил до конца и вернул корректное значение. Два побочных вывода, важных для стражей: 1. Писучие статики __banked-модуля линкуются В СТРАНИЦУ БАНКА (адрес 0x1C000+), снаружи их не прочитать — состояние банка держать в W1/W2. 2. Инлайновый `in a,(0xE2)` посреди тела функции затирает A, куда SDCC уже положил параметр (в первой версии пробника цвет заливки становился номером страницы, и «резидент не рисовал»). Читать порт отдельной __naked-функцией. Имя exe — 8.3 (w3bgfx.exe): DSS длинных имён не понимает. Co-Authored-By: Claude Opus 5 --- tests/w3bankgfx/Makefile | 24 ++++++++++++ tests/w3bankgfx/bank1.c | 48 +++++++++++++++++++++++ tests/w3bankgfx/res.c | 27 +++++++++++++ tests/w3bankgfx/w3bgfx.c | 85 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 tests/w3bankgfx/Makefile create mode 100644 tests/w3bankgfx/bank1.c create mode 100644 tests/w3bankgfx/res.c create mode 100644 tests/w3bankgfx/w3bgfx.c diff --git a/tests/w3bankgfx/Makefile b/tests/w3bankgfx/Makefile new file mode 100644 index 0000000..357e394 --- /dev/null +++ b/tests/w3bankgfx/Makefile @@ -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 внутри банка не +# менялась вокруг рисования. diff --git a/tests/w3bankgfx/bank1.c b/tests/w3bankgfx/bank1.c new file mode 100644 index 0000000..8ab9ae3 --- /dev/null +++ b/tests/w3bankgfx/bank1.c @@ -0,0 +1,48 @@ +/* + * bank1.c — __banked модуль (страница W3 подменяется трамплином на время + * вызова). Задача: проверить, что ИЗ БАНКА можно рисовать примитивами + * libbgi и звать функции W1/W2, и что после этого банк ЖИВ (его страница + * вернулась в W3). + * + * Резидент (res_draw) отсюда НЕ зовём сознательно: пока исполняется банк, + * резидентной страницы в адресном пространстве нет (правило R2). + */ +#include +#include + +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); +} diff --git a/tests/w3bankgfx/res.c b/tests/w3bankgfx/res.c new file mode 100644 index 0000000..a4023bd --- /dev/null +++ b/tests/w3bankgfx/res.c @@ -0,0 +1,27 @@ +/* + * res.c — РЕЗИДЕНТНЫЙ модуль окна W3 (--w3): лежит на 0xC000 и вызывается + * напрямую из W1/W2. Рисует через готовые примитивы libbgi — это законно: + * скобку _bgi_begin/_bgi_end они открывают внутри себя (сам W3-код открывать + * её НЕ имеет права, иначе исполняемая страница подменяется видеобанком). + */ +#include +#include + +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); +} diff --git a/tests/w3bankgfx/w3bgfx.c b/tests/w3bankgfx/w3bgfx.c new file mode 100644 index 0000000..fb1b87f --- /dev/null +++ b/tests/w3bankgfx/w3bgfx.c @@ -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 +#include +#include +#include + +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; +}